1
0
mirror of https://github.com/aquatix/digimarks.git synced 2025-12-06 23:05:10 +01:00

6 Commits

11 changed files with 208 additions and 149 deletions

View File

@@ -0,0 +1 @@
"""Digimarks project."""

View File

@@ -1,3 +1,5 @@
"""Alembic environment file for SQLAlchemy."""
import asyncio
from logging.config import fileConfig
@@ -7,7 +9,7 @@ from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config
from sqlmodel import SQLModel
from src.digimarks.models import Bookmark, PublicTag, User
from src.digimarks.models import Bookmark, PublicTag, User # noqa
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@@ -56,6 +58,7 @@ def run_migrations_offline() -> None:
def do_run_migrations(connection: Connection) -> None:
"""Run the migrations."""
context.configure(
connection=connection,
target_metadata=target_metadata,

View File

@@ -1,15 +1,14 @@
"""Initial migration
"""Initial migration.
Revision ID: 115bcd2e1a38
Revises:
Create Date: 2025-09-12 16:06:16.479075
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = '115bcd2e1a38'
@@ -21,7 +20,8 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('bookmark',
op.create_table(
'bookmark',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('userkey', sa.String(length=255), nullable=False),
sa.Column('title', sa.String(length=255), nullable=False),
@@ -36,23 +36,25 @@ def upgrade() -> None:
sa.Column('deleted_date', sa.DateTime(), server_default=sa.text('(null)'), nullable=True),
sa.Column('status', sa.Integer(), server_default=sa.text('0'), nullable=True),
sa.Column('note', sa.Text(), server_default=sa.text('(null)'), nullable=True),
sa.PrimaryKeyConstraint('id')
sa.PrimaryKeyConstraint('id'),
)
op.create_table('publictag',
op.create_table(
'publictag',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('tagkey', sa.String(length=255), nullable=False),
sa.Column('userkey', sa.String(length=255), nullable=False),
sa.Column('tag', sa.String(length=255), nullable=False),
sa.Column('created_date', sa.DateTime(), server_default=sa.text('(null)'), nullable=True),
sa.PrimaryKeyConstraint('id')
sa.PrimaryKeyConstraint('id'),
)
op.create_table('user',
op.create_table(
'user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=255), nullable=False),
sa.Column('key', sa.String(length=255), nullable=False),
sa.Column('created_date', sa.DateTime(), nullable=False),
sa.Column('theme', sa.String(length=20), server_default=sa.text("'green'"), nullable=True),
sa.PrimaryKeyConstraint('id')
sa.PrimaryKeyConstraint('id'),
)
# ### end Alembic commands ###

View File

@@ -3,15 +3,14 @@
Revision ID: a8d8e45f60a1
Revises: 115bcd2e1a38
Create Date: 2025-09-12 16:10:41.378716
"""
from datetime import UTC, datetime
from typing import Sequence, Union
from alembic import op
from datetime import UTC, datetime
import sqlalchemy as sa
import sqlmodel
from alembic import op
# revision identifiers, used by Alembic.
revision: str = 'a8d8e45f60a1'
@@ -24,72 +23,74 @@ def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('bookmark', schema=None) as batch_op:
batch_op.alter_column('note',
batch_op.alter_column(
'note',
existing_type=sa.TEXT(),
type_=sqlmodel.sql.sqltypes.AutoString(),
nullable=True,
existing_server_default=sa.text('(null)'))
batch_op.alter_column('starred',
existing_type=sa.BOOLEAN(),
nullable=False,
existing_server_default=sa.text('0'))
batch_op.alter_column('modified_date',
existing_type=sa.DATETIME(),
nullable=True)
batch_op.alter_column('deleted_date',
existing_type=sa.DATETIME(),
nullable=True,
existing_server_default=sa.text('(null)'))
batch_op.alter_column('status',
existing_type=sa.INTEGER(),
nullable=False,
existing_server_default=sa.text('0'))
existing_server_default=sa.text('(null)'),
)
batch_op.alter_column(
'starred', existing_type=sa.BOOLEAN(), nullable=False, existing_server_default=sa.text('0')
)
batch_op.alter_column('modified_date', existing_type=sa.DATETIME(), nullable=True)
batch_op.alter_column(
'deleted_date', existing_type=sa.DATETIME(), nullable=True, existing_server_default=sa.text('(null)')
)
batch_op.alter_column(
'status', existing_type=sa.INTEGER(), nullable=False, existing_server_default=sa.text('0')
)
batch_op.create_foreign_key('bookmark_user', 'user', ['userkey'], ['key'])
with op.batch_alter_table('publictag', schema=None) as batch_op:
batch_op.alter_column('created_date',
batch_op.alter_column(
'created_date',
existing_type=sa.DATETIME(),
nullable=True,
existing_server_default=sa.text(str(datetime.now(UTC))))
existing_server_default=sa.text(str(datetime.now(UTC))),
)
batch_op.create_foreign_key('publictag_user', 'user', ['userkey'], ['key'])
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.alter_column('theme',
existing_type=sa.VARCHAR(length=20),
nullable=False,
existing_server_default=sa.text("'green'"))
batch_op.alter_column(
'theme', existing_type=sa.VARCHAR(length=20), nullable=False, existing_server_default=sa.text("'green'")
)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('user', 'theme',
existing_type=sa.VARCHAR(length=20),
nullable=True,
existing_server_default=sa.text("'green'"))
op.alter_column(
'user', 'theme', existing_type=sa.VARCHAR(length=20), nullable=True, existing_server_default=sa.text("'green'")
)
op.drop_constraint(None, 'publictag', type_='foreignkey')
op.alter_column('publictag', 'created_date',
op.alter_column(
'publictag',
'created_date',
existing_type=sa.DATETIME(),
nullable=True,
existing_server_default=sa.text('(null)'))
existing_server_default=sa.text('(null)'),
)
op.drop_constraint(None, 'bookmark', type_='foreignkey')
op.alter_column('bookmark', 'status',
existing_type=sa.INTEGER(),
nullable=True,
existing_server_default=sa.text('0'))
op.alter_column('bookmark', 'deleted_date',
op.alter_column(
'bookmark', 'status', existing_type=sa.INTEGER(), nullable=True, existing_server_default=sa.text('0')
)
op.alter_column(
'bookmark',
'deleted_date',
existing_type=sa.DATETIME(),
nullable=True,
existing_server_default=sa.text('(null)'))
op.alter_column('bookmark', 'modified_date',
existing_type=sa.DATETIME(),
nullable=True)
op.alter_column('bookmark', 'starred',
existing_type=sa.BOOLEAN(),
nullable=True,
existing_server_default=sa.text('0'))
op.alter_column('bookmark', 'note',
existing_server_default=sa.text('(null)'),
)
op.alter_column('bookmark', 'modified_date', existing_type=sa.DATETIME(), nullable=True)
op.alter_column(
'bookmark', 'starred', existing_type=sa.BOOLEAN(), nullable=True, existing_server_default=sa.text('0')
)
op.alter_column(
'bookmark',
'note',
existing_type=sqlmodel.sql.sqltypes.AutoString(),
type_=sa.TEXT(),
nullable=True,
existing_server_default=sa.text('(null)'))
existing_server_default=sa.text('(null)'),
)
# ### end Alembic commands ###

View File

@@ -1,16 +1,13 @@
"""Renamed keys
"""Renamed keys.
Revision ID: b8cbc6957df5
Revises: a8d8e45f60a1
Create Date: 2025-09-12 22:26:38.684120
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision: str = 'b8cbc6957df5'

View File

@@ -0,0 +1 @@
"""digimarks main module."""

View File

@@ -0,0 +1,3 @@
"""Top-level package for Digimarks."""
__author__ = """Michiel Scholten"""

View File

@@ -34,8 +34,10 @@ class Settings(BaseSettings):
favicons_dir: DirectoryPath
# inside the codebase
static_dir: DirectoryPath = 'static'
template_dir: DirectoryPath = 'templates'
# static_dir: DirectoryPath = Path('digimarks/static')
# template_dir: DirectoryPath = Path('digimarks/templates')
static_dir: DirectoryPath = 'digimarks/static'
template_dir: DirectoryPath = 'digimarks/templates'
media_url: str = '/static/'

View File

@@ -30,6 +30,7 @@
--border-color: #d5d9d9;
--border-width: 1px;
--border-radius: 8px;
--chip-border-radius: 2rem;
--shadow-color: rgba(213, 217, 217, .5);
--global-theme-toggle-content: ' 🌞';
@@ -77,6 +78,7 @@ html[data-theme='nebula-dark'] {
--border-color: #333;
--border-width: 1px;
--border-radius: 8px;
--chip-border-radius: 2rem;
--shadow-color: rgba(3, 3, 3, .5);
--global-theme-toggle-content: ' 🌝';
}
@@ -99,6 +101,7 @@ html[data-theme='bbs'] {
--border-color: #333;
--border-width: 2px;
--border-radius: 0;
--chip-border-radius: 0;
--global-theme-toggle-content: ' 🖥️';
}
@@ -124,6 +127,7 @@ html[data-theme='silo'] {
/*--border-color: #003eaa;*/
--border-width: 2px;
--border-radius: 0;
--chip-border-radius: 0;
--global-theme-toggle-content: ' ⌨️';
}
@@ -229,6 +233,7 @@ ol li::marker, ul li::marker {
.active {
background-color: var(--color-highlight);
color: var(--text-color);
transition-duration: 0.2s;
}
/* Special button */
@@ -254,6 +259,7 @@ button, .button, input, select, textarea {
-webkit-user-select: none;
touch-action: manipulation;
vertical-align: middle;
transition-duration: 0.2s;
}
button, .button, input, select, textarea, table {
@@ -267,6 +273,7 @@ button:hover, .button:hover {
/*background-color: #d57803;*/
background-color: var(--color-highlight);
filter: brightness(80%);
transition-duration: 0.2s;
}
button:focus, .button:focus {
@@ -303,6 +310,22 @@ button:focus, .button:focus {
filter: brightness(80%);
}
/* Toggle buttons */
.button-group {
display: inline-flex;
overflow: hidden;
border: var(--border-width) solid var(--border-color);
border-radius: var(--border-radius);
}
.button-group button {
/* Reset borders because the buttons are mashed together and the group has its own border */
border: none;
border-radius: 0;
box-shadow: none !important;
}
/* Table */
th {
@@ -334,6 +357,7 @@ th, td {
[data-theme='nebula'] .card,
[data-theme='nebula'] button,
[data-theme='nebula'] .button,
[data-theme='nebula'] .button-group,
[data-theme='nebula'] input,
[data-theme='nebula'] select,
[data-theme='nebula'] textarea,
@@ -342,6 +366,7 @@ th, td {
[data-theme='nebula-dark'] .card,
[data-theme='nebula-dark'] button,
[data-theme='nebula-dark'] .button,
[data-theme='nebula-dark'] .button-group,
[data-theme='nebula-dark'] input,
[data-theme='nebula-dark'] select,
[data-theme='nebula-dark'] textarea,
@@ -419,7 +444,7 @@ th, td {
.chip {
font-size: .8rem;
border-radius: var(--border-radius);
border-radius: var(--chip-border-radius);
background-color: var(--background-color-secondary);
color: var(--text-color-secondary);
/*color: var(--text-color);*/
@@ -428,7 +453,7 @@ th, td {
}
.chip .button {
border-radius: var(--border-radius);
border-radius: var(--chip-border-radius);
}
/* Status */

View File

@@ -18,6 +18,7 @@ document.addEventListener('alpine:init', () => {
/* Bookmark that is being edited, used to fill the form, etc. */
bookmarkToEdit: Alpine.$persist({}).as('bookmarkToEdit'),
bookmarkToEditError: null,
bookmarkToEditVisible: false,
/* Loading indicator */
loading: false,
@@ -147,6 +148,10 @@ document.addEventListener('alpine:init', () => {
)
},
get filteredTags() {
if (this.cache[this.userKey].tags === undefined) {
console.log('Tags not yet cached');
return [];
}
/* Search in the list of all tags */
return this.cache[this.userKey].tags.filter(
i => i.match(new RegExp(this.search, "i"))
@@ -214,7 +219,6 @@ document.addEventListener('alpine:init', () => {
'note': '',
'tags': ''
}
},
async startAddingBookmark() {
/* Open 'add bookmark' page */
@@ -222,6 +226,7 @@ document.addEventListener('alpine:init', () => {
this.resetEditBookmark();
// this.show_bookmark_details = true;
const editFormDialog = document.getElementById("editFormDialog");
this.bookmarkToEditVisible = true;
editFormDialog.showModal();
},
async bookmarkURLChanged() {
@@ -253,6 +258,7 @@ document.addEventListener('alpine:init', () => {
},
async saveBookmark() {
console.log('Saving bookmark');
// this.bookmarkToEditVisible = false;
// this.show_bookmark_details = false;
},
async addBookmark() {

View File

@@ -11,9 +11,14 @@
<ul>
<li><h1>digimarks</h1></li>
<li>
<div class="button-group">
<button x-data @click="$store.digimarks.toggleTagPage()"
:class="!$store.digimarks.showTags && 'active'">bookmarks
</button>
<button x-data @click="$store.digimarks.toggleTagPage()"
:class="$store.digimarks.showTags && 'active'">tags
</button>
</div>
</li>
<li>
<button @click="$store.digimarks.startAddingBookmark()">add bookmark</button>
@@ -32,6 +37,7 @@
<h1 x-bind:title="$store.digimarks.userKey">Bookmarks</h1>
<p>
<div class="button-group">
<button @click="$store.digimarks.sortAlphabetically()"
:class="$store.digimarks.sortTitleAsc && 'active'">a-z &darr;
</button>
@@ -44,9 +50,15 @@
<button @click="$store.digimarks.sortCreated('desc')"
:class="$store.digimarks.sortCreatedDesc && 'active'">date &uarr;
</button>
</div>
<div class="button-group">
<button @click="$store.digimarks.toggleListOrGrid()"
:class="$store.digimarks.showBookmarksCards && 'active'">list or grid
:class="$store.digimarks.showBookmarksCards && 'active'">grid
</button>
<button @click="$store.digimarks.toggleListOrGrid()"
:class="!$store.digimarks.showBookmarksCards && 'active'">list
</button>
</div>
</p>
<table x-cloak x-show="$store.digimarks.showBookmarksList">
@@ -98,15 +110,18 @@
<div class="card-thumb" x-show="bookmark.favicon"><img
x-bind:src="'/content/favicons/' + bookmark.favicon"></div>
<div class="statuses">
<div x-show="bookmark.starred" class="star"><i class="fa-fw fa-solid fa-star"></i>
<div x-show="bookmark.starred" class="star"><i
class="fa-fw fa-solid fa-star"></i>
</div>
<div x-show="bookmark.http_status !== 200 && bookmark.http_status !== 304"
class="error"><i
class="fa-fw fa-solid fa-triangle-exclamation"></i>
</div>
<div x-show="bookmark.note"><i class="fa-fw fa-regular fa-note-sticky"></i></div>
<div x-show="bookmark.note"><i class="fa-fw fa-regular fa-note-sticky"></i>
</div>
</div>
<div><a x-text="bookmark.title" x-bind:href="bookmark.url" target="_blank"></a>
</div>
<div><a x-text="bookmark.title" x-bind:href="bookmark.url" target="_blank"></a></div>
</div>
<div class="card-footer">
<button title="show actions"><i class="fa-solid fa-square-caret-down"></i></button>
@@ -170,7 +185,8 @@
</span>
</div>
#}
<form method="dialog" id="bookmarkEditForm" x-if="$store.digimarks.bookmarkToEdit">
<template x-if="$store.digimarks.bookmarkToEditVisible">
<form method="dialog" id="bookmarkEditForm">
<fieldset class="form-group">
<label for="bookmark_url">URL</label>
<input id="bookmark_url" type="text" name="bookmark_url" placeholder="url"
@@ -195,7 +211,8 @@
placeholder="tags, divided bij comma's"
x-model="$store.digimarks.bookmarkToEdit.tags">
</fieldset>
<p x-show="$store.digimarks.bookmarkToEditError" x-data="$store.digimarks.bookmarkToEditError"></p>
<p x-show="$store.digimarks.bookmarkToEditError"
x-data="$store.digimarks.bookmarkToEditError"></p>
<p>
<label>
<input type="checkbox" name="strip" id="strip"/>
@@ -207,6 +224,7 @@
<button @click="$store.digimarks.saveBookmark()">Save</button>
</div>
</form>
</template>
</dialog>
</main>