Commit graph

95 commits

Author SHA1 Message Date
marwin
76068f6ed8 Reader: Fußnoten-Popover erkennt jetzt mehr EPUB-Konventionen (SW v31)
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 14s
Die Erkennung von Fußnoten-Links war auf class="footnote" + gleiche-Datei-
Anker (href startsWith '#') hartkodiert. Andere Editionen markieren Fußnoten
anders — z.B. die e-artnow-Ausgabe von Marx' "Das Kapital" (zeno.org-Konvertierung)
nutzt gar keine Klasse und verlinkt mit einem <sup> als Kind (statt Vorfahre)
des <a> auf eine ANDERE Kapiteldatei ("../Text/Karl0045.html#F537") — dadurch
griff weder die Klassen- noch die Hash-Prüfung, das Popover blieb tot.

_looksLikeFootnoteLink() erkennt jetzt zusätzlich epub:type="noteref" (EPUB3-
Standard), jede Klasse mit "note"/"footnote"/"fn" im Namen, und als Fallback
jeden Link mit Fragment-Anker, der irgendwo mit einem <sup> verschachtelt ist
(in beide Richtungen) — der in EPUBs praktisch universelle Marker für
Fußnotenziffern. Die Fragment-Extraktion nimmt jetzt alles nach dem letzten
'#' statt nur bei href.startsWith('#'), da das Buch als eine zusammenhängende
DOM gerendert wird und getElementById dateiübergreifend funktioniert.

Verifiziert per Playwright: Marx-Edition zeigt jetzt beim Hover 1326 erkannte
Fußnoten-Links mit korrektem Popover-Inhalt; Žižeks "Weniger als nichts"
(vorher funktionierend, class="footnote"-basiert) weiterhin unverändert
funktionsfähig — keine Regression.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 18:55:48 +02:00
marwin
42bc090a28 Reader: Marker-Farben mit color:inherit statt UA-Default-Schwarz (SW v30)
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
mark-Elemente haben browserseitig einen UA-Default (color:black), der bislang
nicht überschrieben wurde — beim Markieren von Text im dunklen Standard-Theme
(weißer Fließtext) sprang die Markierung dadurch abrupt auf schwarzen Text.
Jetzt color:inherit, damit markierter Text immer die Farbe des umgebenden
Texts behält; die vier Hintergrundfarben sind dafür kräftiger/dunkler gewählt,
sodass sie in allen drei Themes (dunkel/weißer Text, Sepia, Hell) ausreichend
Kontrast zum inherited Text bieten (WCAG-Kontrastwerte 4.8:1–11.7:1, per
Playwright-Screenshot in allen drei Themes gegengeprüft).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 18:44:09 +02:00
marwin
b805d62b11 Books: Notizen-Sidebar auto-öffnen, Notizen-Download + Gelesen-Status in Übersicht (SW v29)
All checks were successful
Build and push Docker image / build (push) Successful in 17s
Test / test (push) Successful in 16s
- EBook.is_read (Migration) + neuer /books/<id>/read/-Endpoint zum Togglen
- book_list liefert is_read und has_highlights (Existenz einer Highlights-Zeile)
- Reader öffnet die Notizen-Sidebar automatisch, wenn das Buch bereits
  Markierungen/Notizen hat, statt sie hinter dem manuellen Toggle zu verstecken
- Buch-Übersicht: Download-Button für Notizen/Markierungen direkt aus der Liste
  (ohne den Reader zu öffnen), "Als gelesen markieren" mit Bestätigungsdialog,
  Filter "Gelesene Bücher anzeigen" (standardmäßig aus)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 18:10:33 +02:00
marwin
f9573d3d62 Reader: lange Notizen wurden im Rand zu früh ausgeblendet (SW v28)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
_repositionMarginMarkers() filterte Einträge anhand eines festen ±60px-
Fensters um den reinen Ankerpunkt, bevor die tatsächliche Kartenhöhe bekannt
war. Für Notizen mit mehr Text als eine "Standard"-Karte reichte das nicht:
die Karte hätte teilweise schon sichtbar sein müssen, obwohl ihr Anker noch
weiter außerhalb lag — sie blieb beim Scrollen also länger verschwunden als
erwartet.

Vorfilter jetzt großzügig (mind. 400px bzw. die Höhe des sichtbaren
Bereichs), danach ein zweiter Cull-Durchgang mit den tatsächlich gemessenen
Kartenhöhen nach dem Stapeln — dadurch werden nur Einträge entfernt, die
wirklich komplett außerhalb liegen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 14:09:02 +02:00
marwin
9648730be6 Reader: Prozentanzeige mit Nachkommastelle bei langen Büchern (SW v27)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Bei sehr langen Büchern (ab ca. 1 Mio. Zeichen, entspricht etwa 600-700
Druckseiten) bewegt sich die ganzzahlige Prozentanzeige beim Lesen kaum noch
— eine Nachkommastelle macht sie wieder aussagekräftig. Betrifft die
Fortschrittsanzeige im Reader-Header sowie die "≈X% im Buch"-Koordinate bei
Annotationen-Export und -Verzeichnis.

Formatierung über toLocaleString() (Komma bei de, Punkt bei en, etc.). Das
Fortschrittsfeld ist dafür von <input type="number"> auf type="text" mit
inputmode="decimal" umgestellt — number-Inputs erzwingen intern immer einen
Punkt, unabhängig von der Locale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 13:51:05 +02:00
marwin
7bfce034ba Reader: Marker-Modus statt impliziter Auswahl, Notiz-Anker rein positional (SW v26)
All checks were successful
Build and push Docker image / build (push) Successful in 17s
Test / test (push) Successful in 16s
Vier vom Nutzer gemeldete Bugs behoben:

- Markierter Text war kaum lesbar: der globale weiße Text-Outline (fürs
  Hintergrundbild-Feature gedacht) kollidierte mit der Highlight-Farbe.
  Reader sitzt immer auf eigenem, opakem Hintergrund — Outline dort komplett
  deaktiviert.
- "Notiz zu Markierung hinzufügen" öffnete weiterhin die rechte Sidebar statt
  den Rand. Jeder Notiz-Eintragspunkt (Highlight+Notiz aus der Textauswahl,
  Edit-Note-Klick auf eine Markierung im Fließtext) läuft jetzt über
  _openMarginAndEditNote() — öffnet bei Bedarf den Rand und bearbeitet dort
  inline. openNoteEditor()/rechte Sidebar für Notizen komplett entfernt.
- Kernursache für "Notiz verschwindet, Markierung heftet sich an falsche
  Notiz": Anker basierten auf XPath mit Sibling-Index unter den Textknoten
  eines Blocks — jede weitere Markierung im selben Block (surroundContents
  spaltet Textknoten) verschob diese Indizes und korrumpierte lautlos ALLE
  anderen Anker im selben Block. Anker adressieren jetzt stattdessen
  Block-Index + Zeichen-Offset innerhalb des Blocks (wie das bestehende
  Lesefortschritt-Ankersystem) — Wrapping/Unwrapping durch andere
  Markierungen ändert weder Blockreihenfolge noch Zeichenanzahl, ist also
  erschütterungsfrei für andere Anker im selben Block.
- Löschen einer Markierung riss zuvor aus demselben Grund weiter unten
  liegende Notizen optisch mit raus (Daten blieben in der DB) — mit dem
  neuen Ankersystem behoben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 13:28:19 +02:00
marwin
3f40a4078a Reader: Notiz-Eingabe direkt im Rand statt Sprung zur Sidebar (SW v25)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 14s
Notizen setzen/bearbeiten passiert jetzt inline an der Stelle im Notizen-Rand,
wo die Notiz auch angezeigt wird — kein Wechsel mehr zur rechten Sidebar.
Textfeld wird beim Öffnen automatisch fokussiert und ausgewählt. Enter
speichert, Escape verwirft die Änderung.

Stift-Button (Marker-Modus) zieht in die Titelzeile des Notizen-Rands um,
neben "Notes" — vorher musste man dafür ständig zur Hauptleiste zurück, die
im Immersive-Modus eingeklappt ist.

Nebenbei zwei Bugs beim Testen gefunden und behoben: ein Klick auf leere
Randfläche während ein Editor bereits offen war, legte durchs Blur-Event
gleichzeitig eine zweite, ungewollte Notiz an; und Escape im Notizfeld
bubbled zum globalen Escape-Handler durch, der dann den ganzen Reader
schloss (und damit die gerade bearbeiteten Highlights aus dem Speicher warf).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 11:23:16 +02:00
marwin
a2f4be8e1e Reader: Positions-Koordinate im Export + Verzeichnis für Markierungen/Notizen (SW v24)
Echte Buchseiten sind fürs Erste zurückgestellt (kein Konzept dafür bei
reflowable EPUB-Text) — stattdessen bekommt jeder Export-Eintrag jetzt eine
grobe Prozent-Koordinate ("≈37% im Buch"), zusätzlich zur Kapitelgruppierung.

Neu: ein Verzeichnis für Markierungen/Notizen im selben Sidebar-Stil wie die
Lesezeichen (Button in der Margin-Kopfzeile), das alle Einträge in
Lesereihenfolge mit Vorschau und Koordinate auflistet und per Klick an die
jeweilige Textstelle springt — anders als die Margin-Leiste, die nur zeigt,
was gerade sichtbar ist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 11:10:56 +02:00
marwin
bc180daab0 Reader: Marker-Modus statt impliziter Auswahl, Notiz-Anker rein positional (SW v23)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 14s
Drei Nachbesserungen am Annotationen-Feature nach Live-Test:

- Neuer Stift-Button (Marker-Modus) in der Kopfleiste: Textauswahl löst das
  Highlight-Popup nur noch aus, wenn der Modus aktiv ist — vorher war die
  Funktion unauffindbar (impliziter "einfach Text markieren"-Gestus ohne
  sichtbaren Einstiegspunkt) und hätte jede Textauswahl (auch zum Kopieren)
  gekapert.
- Freiform-Notizen bekommen keine Textdekoration mehr im Lesefluss — der
  Anker dient nur der Positionierung im Rand, nicht der optischen Markierung.
- Die Margin-Sidebar zeigt Notiztext jetzt direkt lesbar als kleine
  Post-it-Karte an der zugehörigen Stelle (mit Stapel-Logik gegen
  Überlappung), statt nur ein abstraktes Symbol zum Anklicken. Reine
  Highlights ohne Notiz bleiben ein kleiner Farbpunkt.
- Highlight-Popover/Tooltip klammern ihre Position jetzt hart an den
  Viewport, damit eine Auswahl nahe Seitenrand nicht unsichtbar außerhalb
  des sichtbaren Bereichs landet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 10:49:30 +02:00
marwin
090aec9c60 Reader: Annotationen — Marker, freie Notizen, Margin-Sidebar, Export (SW v22)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Textauswahl→Highlight-Popover war implementiert, aber nie verdrahtet (kein
mouseup/touchend-Listener) — als Voraussetzung mit behoben. Neu: freiformige
Notizen ohne Textmarkierung, verankert per Klick in einer neuen linken
Margin-Sidebar (Notiz am ersten Wort der Zeile auf Klickhöhe); Sidebar zeigt
Marker für alle Highlights/Notizen im sichtbaren Bereich und schiebt den
Lesetext nach rechts. Export sammelt alle Markierungen/Notizen eines Buchs in
Lesereihenfolge, nach Kapitel gruppiert, als Textdatei. EPUB-only — PDFs haben
noch keinen Text-Layer (siehe Issue #10).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 10:17:01 +02:00
marwin
17e205b6f0 Reader/UI: mehrere Fixes + Playwright-Setup (SW v21)
All checks were successful
Build and push Docker image / build (push) Successful in 55s
Test / test (push) Successful in 15s
- Books: Reader sprang beim Scroll+sofortigem Tap auf die alte Position
  zurück (Anker-Tracking lief nur alle 2s über den Save-Debounce, jetzt
  eigener 150ms-Tracker unabhängig davon)
- Books: +/- Buttons neben den Reader-Slidern (Font/Zeilenhöhe/Breite)
- Books: Sicherheitsnetz-Toast bei plötzlichen großen Scroll-Sprüngen
  (Fling, aus Versehen 'G' gedrückt) mit Zurückspringen-Option; bewusste
  Sprünge (TOC, Lesezeichen, Fortschritts-Eingabe, Suche) lösen ihn nicht aus
- Radio: Donation-Hinweis kam bei vielen Lieblingssendern gefühlt ständig —
  jetzt zusätzlich auf ~1-von-10 Plays gedrosselt
- UI: farbige Emoji-Icons (🔍📻💡 etc.) durch monochrome Unicode-Symbole
  ersetzt, die nicht mehr je nach OS/Browser-Font unterschiedlich aussehen;
  Lesezeichen-Icon war zudem fast identisch zum TOC-Icon
- UI: native alert()/confirm()/prompt() durch eigenes Modal-System ersetzt
- UI: Hash-basiertes URL-Routing für Tabs (#radio/saved, #podcasts/feeds, …)
  — Browser-Zurück/Vor und Deep-Links funktionieren jetzt
- Tests: Playwright e2e-Setup gegen isolierte Test-DB (DIORA_DB_NAME),
  Smoke- und Auth-Specs

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-04 09:01:52 +02:00
marwin
daffd0002b Books: Fortschritt-Konflikt via Anker-Blockindex statt scroll_fraction (SW v15)
All checks were successful
Build and push Docker image / build (push) Successful in 1m1s
Test / test (push) Successful in 15s
Die max()-Semantik aus v14 verglich nur die grobe scroll_fraction. Da
scroll_fraction und position_anchor gemeinsam, aber entkoppelt gespeichert
werden, konnte ein einzelner Save mit transient zu hoher fraction (z.B.
instabiles Layout beim Laden) die Position dauerhaft einfrieren: jeder
spätere echte Fortschritt hatte eine kleinere fraction und wurde inklusive
Anker verworfen — der Leser landete immer wieder an derselben Stelle.

Fix: Vergleich läuft jetzt über den Blockindex im Anker (die Größe, die
auch die Sprungposition bestimmt), mit innerFraction als Tiebreaker.
scroll_fraction dient nur noch als Fallback für PDFs ohne Anker. Server
(_progress_is_further) und Client (_cmpProgress) nutzen identische Logik;
loadBookList-Push und lokaler Cache ebenfalls. Bestehende eingefrorene
Einträge entfrieren sich beim ersten Weiterlesen selbst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:52:27 +02:00
marwin
29f6cc4413 Books: Fortschritt-Konflikt via max() lösen — weiter = gewinnt (SW v14)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Der am weitesten gelesene Wert hat immer Vorrang:
- Server: scroll_fraction = max(neu, aktuell) — ein afk-Fenster bei 10%
  kann nicht mehr 80% überschreiben
- Client loadBookList: wenn lokaler Fortschritt > Server, wird gepusht
  und für die Anzeige verwendet (deckt Offline-Lesen ab)
- Pending-Flag-Logik entfernt — nicht mehr nötig dank max-Semantik
- saveReaderProgress(force=true): neuer force-Parameter schreibt
  Position unabhängig vom gespeicherten Maximum; Button ⚑ im
  Reader-Header für den Ausnahmefall "zurück-zum-Anfang"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:41:35 +02:00
marwin
28756ffdc2 Books: Fortschritt-Sync robuster — Pending-Flag statt Timestamp (SW v13)
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 18s
Timestamp-Vergleich in _saveBookMeta entfernt: client-seitige
ISO-Strings (new Date().toISOString) lagen fast immer leicht vor dem
Serverwert und haben dadurch regelmässig korrekten Online-Fortschritt
überschrieben.

Neu: explizites Pending-Flag (localStorage diora_pending_progress) —
gesetzt wenn saveReaderProgress offline scheitert, gelöscht nach
erfolgreicher Synchronisierung.

- _saveBookMeta nutzt das Flag statt Zeitstempel: Server-Daten
  überschreiben lokalen Fortschritt nur wenn kein Pending-Flag gesetzt
- _syncPendingProgress: pusht ausstehenden Fortschritt beim
  online-Event bevor loadBookList läuft
- saveReaderProgress setzt das Flag nur wenn !navigator.onLine

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:29:38 +02:00
marwin
b097eea600 Books: offline-Fortschritt wird nicht überschrieben (SW v12)
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
- _saveBookMeta vergleicht local vs. Server last_read — neuere lokale
  Daten (offline gelesen) überleben den nächsten Server-Abruf
- loadBookList pusht beim Online-Werden automatisch lokal neueren
  Fortschritt an den Server bevor die Liste gerendert wird
- saveBookmarks/saveHighlights markieren fehlgeschlagene Saves als
  pending sync (localStorage); beim nächsten online-Event werden alle
  pending Annotationen zuerst gepusht, dann erst die Buchliste geladen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 07:22:32 +02:00
marwin
5d69edc57e Layout: Tab-Leiste position:fixed + padding-top korrekt (SW v11)
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
Statt padding-top gegen die Navbar zu kämpfen ist #tabs jetzt
position:fixed direkt unterhalb der Navbar (top:var(--nav-h),
z-index:150). Damit ist die Leiste garantiert immer sichtbar,
unabhängig vom Scroll-Zustand oder Offline-Status.

main-content padding-top auf calc(var(--nav-h)+3rem) erhöht um
Platz für Navbar+Tabs zu schaffen. Offline-Banner vereinfacht zu
einer body-Klasse (kein fixed DOM-Element mehr).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:34:53 +02:00
marwin
d7a27b188d Layout + SW: Tab-Leiste sichtbar + kein veralteter Cache
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 15s
- main-content padding-top auf calc(var(--nav-h) + 0.75rem) erhöht
  damit die Tab-Leiste (Radio/Focus/Podcasts/Books) sicher unterhalb
  der fixed Navbar liegt — auf Desktop und Mobile
- SW v10: sendet SW_ACTIVATED an alle offenen Tabs wenn ein neuer SW
  übernimmt; app.js lädt daraufhin neu (außer wenn ein Buch geöffnet
  ist) — verhindert dass der Browser eine uralte HTTP-gecachte Version
  ausliefert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:19:00 +02:00
marwin
aa562f8b4d Books: offline UX — Banner, Auto-Tab, klare Fehlermeldung
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
- Bei Offline-Start oder Wechsel in Flugzeugmodus: roter Banner
  unterhalb der Navbar, automatischer Wechsel zum Books-Tab (einziger
  sinnvoller Tab offline), Upload-Zone wird ausgeblendet
- Bei Rückkehr online: Banner verschwindet, Upload-Zone erscheint wieder,
  Buchliste wird neu synchronisiert
- openBook unterscheidet jetzt zwischen "nicht gecacht" (Toast-Hinweis
  zum einmaligen Online-Öffnen) und echtem Defekt (markBookBroken wie
  bisher) — kein stilles Scheitern mehr

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 00:12:22 +02:00
marwin
a96591c63f SW: cache navigation response offline (v9)
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 14s
Ohne diesen Fix schlägt das Öffnen der App im Flugzeug fehl, weil der
Service Worker die HTML-Seite (/) nicht cached — der Browser zeigt
dann eine Netzwerkfehler-Seite bevor JS überhaupt startet.

Strategie: Network-first für Navigationsanfragen, bei Netzwerkfehler
die zuletzt gecachte Version ausliefern. Nach dem ersten Online-Besuch
funktioniert die App vollständig offline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 23:58:07 +02:00
marwin
5ba1a7bdad Books: request persistent storage when first caching a book
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
Ohne navigator.storage.persist() ist der IndexedDB-Speicher "best-effort"
und kann vom Browser bei Speicherknappheit still gelöscht werden. Der
Aufruf erfolgt beim ersten Schreiben eines Buches in den Cache — Chrome
gewährt das für installierte PWAs automatisch, Firefox kann einen Dialog
zeigen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 23:54:54 +02:00
marwin
3d25519367 PWA: fix icon purpose entries + bump SW cache to v8
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
Chrome 98+ hat Probleme mit kombinierten purpose-Werten ("any maskable")
auf einem einzelnen Icon-Eintrag. Separate Einträge für "any" und
"maskable" sind zuverlässiger und entsprechen der Spec-Empfehlung.
SW-Version auf v8 erhöht, um nach den JS-Änderungen einen sauberen
Cache-Neustart zu erzwingen.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 23:49:32 +02:00
marwin
5504e5c627 Books: fix footnote popover background + strip EPUB title tooltips
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
Popover had transparent background because --bg-card is explicitly
transparent; now uses hardcoded colors with theme-aware overrides.
Also strips title attributes during EPUB sanitization to prevent
native browser tooltips from appearing while reading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 21:21:43 +02:00
marwin
bfa0439aa1 Books: vollständiger Offline-Modus für EPUB-Reader
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 17s
- IndexedDB v2 mit zwei neuen Stores: book_meta (Buchliste +
  Lesefortschritt) und book_annotations (Lesezeichen & Highlights)
- loadBookList fällt bei Netzwerkfehler auf lokalen Meta-Cache zurück,
  blendet Upload-Zone aus und zeigt Offline-Hinweis
- Leseposition (scroll_fraction + position_anchor) wird bei jedem
  Auto-Save lokal gecacht, sodass offline-Öffnen am richtigen Ort
  landet
- Lesezeichen und Highlights werden nach Server-Abruf lokal gecacht
  und bei Netzwerkfehler von dort geladen; Änderungen offline bleiben
  bis zur nächsten Synchronisierung erhalten
- Mobile Reader-Header: kompaktere Abstände, Fortschritts-Input auf
  kleinen Screens ausgeblendet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 21:14:40 +02:00
marwin
159aa6f340 Books: footnote hover popover for EPUB reader
All checks were successful
Build and push Docker image / build (push) Successful in 20s
Test / test (push) Successful in 16s
Hovering over a footnote reference shows the footnote content in a
floating popover; moving the mouse away dismisses it. On mobile, a
tap toggles the popover with an ✕ close button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 21:04:47 +02:00
marwin
fe91000e7c Books: repair flow also re-encrypts metadata from file
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 14s
replace-data endpoint now optionally accepts meta_ct/meta_iv.
The client extracts title/author from the uploaded file (same as
normal upload), re-encrypts metadata with the current key, and sends
both data and meta together — so broken books are fully restored
including their displayed title and author.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 17:06:52 +02:00
marwin
4b47f6e67a Books: broken-book repair flow + simplify password change
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
When a book fails to open, a '!' button appears next to it in the list.
Clicking it prompts for the original file; the file is re-encrypted with
the current key and replaces the broken ciphertext on the server while
keeping all metadata, progress, highlights and bookmarks intact.

- Add POST /books/<pk>/replace-data/ endpoint (updates data only)
- Add _evictCachedBook() to clear IndexedDB cache for a single book
- Replace complex client-side re-encryption on password change with a
  simple confirm() warning that books will need to be re-uploaded

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 17:03:59 +02:00
marwin
d64f159044 EPUB reader: add 'Kein Fett' toggle to suppress book bold
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 13s
Publisher EPUBs often set font-weight via <b>/<strong> tags or inline
style attributes. A new toggle in the settings panel adds the
.reader-no-bold class which overrides all font weights to normal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 11:52:45 +02:00
marwin
2d488fd542 EPUB reader: font picker + performance fixes for large books
All checks were successful
Build and push Docker image / build (push) Successful in 1m17s
Test / test (push) Successful in 14s
- Add font family selector (Serif/Sans/Verdana/Mono) to reader settings panel,
  saved per book in localStorage
- Strip <style>/<script> blocks before regex and DOMParser processing to avoid
  working over large base64-embedded font CSS in publisher EPUBs
- Parallelize image blob URL creation with Promise.all instead of sequential await
- Inject chapter HTML progressively in batches with requestAnimationFrame yields
  to keep the UI responsive when loading many-chapter books

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 11:40:58 +02:00
marwin
9241d6170b Remove loading overlay from re-renders (zoom/spread)
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Current page renders almost instantly, no overlay needed.
Overlay stays for initial book open only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:55:13 +02:00
marwin
1cf3f730ea Render PDF from current page outward on zoom/re-render
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 16s
renderPdf now takes an optional pivotPage. Pass 1 builds the full DOM
and sizes all canvases (instant). Then scrolls to the pivot page
immediately so the user stays in place. Pass 2 renders pixels from
pivot→end, then pivot-1→start.

reRenderPdf detects the current visible page before re-rendering and
passes it as pivot, so zoom no longer resets scroll position.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:50:01 +02:00
marwin
20a1b9a889 Fix scroll position lost after PDF zoom re-render
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Scroll position was restored before browser finished layout, so
scrollHeight was still wrong. Now waits two animation frames after
reRenderPdf completes before restoring position.

Also shows loading overlay during zoom re-renders, not just on initial load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:44:49 +02:00
marwin
89cb70392a j/k scroll continuously while held, stop on keyup
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Uses a 16ms interval (~60fps) instead of per-event smooth scroll,
so holding j/k scrolls fluidly. d/u/f/b remain one-shot with smooth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:32:32 +02:00
marwin
b6619f6465 Fix PDF loading overlay disappearing too early
All checks were successful
Test / test (push) Successful in 18s
Build and push Docker image / build (push) Successful in 14s
Moved overlay out of contentEl (which renderPdf clears immediately)
into the reader-overlay element. It now stays visible for the entire
render duration and is removed only after renderPdf resolves.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:29:46 +02:00
marwin
d607388bad Add vim-style keyboard shortcuts to reader
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 17s
j/k    scroll down/up (small step, ~8% viewport)
d/u    scroll half page down/up
f/b    scroll full page down/up
g/G    jump to top/bottom
n/p    next/prev page (PDF scroll mode)

Keys are ignored when an input or textarea is focused.
Existing arrow key navigation in paginated PDF mode unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:20:06 +02:00
marwin
846b299713 Show dark loading overlay while PDF is rendering
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
Displays a dark background with a spinning indicator in the reader
content area before renderPdf starts. renderPdf clears innerHTML
itself when it begins, so no explicit cleanup needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:08:44 +02:00
marwin
def879de2d Fix radio sidebar play buttons broken by JSON.stringify double quotes
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Inline onclick='playStation("url", "name", null)' broke because
JSON.stringify wraps strings in double quotes, conflicting with the
onclick attribute quotes. Replaced with data attributes + addEventListener.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 17:32:05 +02:00
marwin
f5c141626f Fix blurry PDF rendering when zoomed in Chrome PWA
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
Zoom is now baked into the canvas render scale instead of being applied
via CSS zoom. CSS zoom only scales pixels already on the canvas, causing
blurriness at high DPR (e.g. PWA on mobile). Now the canvas is rendered
at the correct resolution for the chosen zoom level.

Also: stop nulling currentPdfDoc on re-render so PDF.js page cache is
preserved, making zoom re-renders significantly faster.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 16:14:24 +02:00
marwin
e5dc58d84f Replace focus station sidebar with compact radio player sidebar
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
The 📻 button now opens a sidebar with the currently playing station/track,
play/stop + volume control, and the saved stations list. The old focus
station configuration UI (presets, custom URL input, save-to-server) and
the auto-play-on-book-open behavior are removed.

Closes #6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:22:07 +02:00
marwin
554ca93e30 Close reader settings panel when tapping content to hide bars
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:13:28 +02:00
marwin
6b419c6fe0 Save reader settings per book in localStorage
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
Each book gets its own key (diora_reader_settings_{bookId}).
Opening a book resets to defaults then applies book-specific overrides,
so zoom, spread, invert, theme etc. are remembered independently per book.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:53:38 +02:00
marwin
916e8a568b Add PDF two-page spread mode and mobile pinch-to-zoom
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 16s
Spread mode: new toggle in reader settings renders pages side-by-side
(cover alone, then pairs 2-3, 4-5...) using full screen width. Each
page scales to half the container. Navigation and scroll position
tracking are unchanged since per-page IDs are preserved.

Pinch-to-zoom: captures 2-finger pinch on the PDF reader, blocking
native browser zoom. Live CSS zoom during gesture, snaps to nearest
10% step on release. Single-finger scroll unaffected. applyPdfZoom
moved to module level so touch handlers can call it. Touch listeners
cleaned up on reader close.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 13:18:25 +02:00
marwin
e9c5b8058b Centralize remaining magic numbers in settings.py
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
- HIGHLIGHTS_MAX_BYTES, BOOKMARKS_MAX_BYTES: books size limits now in settings
- PODCAST_INBOX_PAGE_SIZE: shared between podcasts/views.py and app.js via DIORA_CONFIG
- VOLUME_DEFAULT: radio stream player default volume
- ITUNES_TIMEOUT: unified iTunes API timeout (was 5s vs 6s inconsistency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:10:14 +02:00
marwin
0a6ba6feac Inject upload size limits from settings into frontend via DIORA_CONFIG
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 15s
Backend settings are now the single source of truth for EBOOK_MAX_BYTES
and BG_MAX_BYTES. A new context processor exposes them to all templates,
and base.html injects them as window.DIORA_CONFIG so app.js reads from
there instead of hardcoded values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:05:51 +02:00
marwin
9c0a046c57 Fix ebook upload: new books appear at top, 50 MB limit frontend/backend
All checks were successful
Build and push Docker image / build (push) Successful in 14s
Test / test (push) Successful in 17s
- Create EBookProgress on upload so new books get a last_read timestamp
  and sort to the top of the book list
- Update frontend file size check from 10 MB to 50 MB
- Fix backend error message to say 50 MB instead of 10 MB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 21:01:32 +02:00
marwin
2ba613fdd8 Reconnect audio automatically on device change
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
Listens for navigator.mediaDevices.devicechange and re-routes the
audio element to the new default output device without a page reload.
Debounced 500ms to handle BT device bursts. Podcasts resume at the
correct timestamp via loadedmetadata.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 02:27:18 +02:00
marwin
aff4f5aef2 Mobile: hide volume, add PDF zoom +/- buttons, fix zoom scroll position
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 15s
- Hide volume label/slider/input on mobile (≤600px)
- Add − and + buttons flanking the PDF zoom slider
- Preserve scroll fraction across zoom changes in PDF scroll mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 12:22:04 +02:00
marwin
1bda59e3fc Fix PDF position restore: timer after restore, add scroll-mode case
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 16s
- Move auto-save timer setup to after position restore so an early
  visibilitychange can't overwrite the saved position with 0
- Add missing restore path for non-paginated PDF scroll mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:46:57 +02:00
marwin
68bb7b5920 Add IndexedDB book cache and fix PDF position on mobile
All checks were successful
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 15s
- Cache encrypted book data in IndexedDB (cache-first on open)
- Evict books not read for 4 weeks on book list load
- Fix PDF paginated mode not activating on book open (mobile)
- enterPdfPaginatedMode() now called after position restore in openBook()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 16:10:03 +02:00
marwin
dbe3b46f3e Simplify immersive reader: tap centre to toggle bars
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Replace timer/edge-hover system with a simple click-to-toggle.
Tapping interactive elements (buttons, links, settings) is ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:50:31 +02:00
marwin
2448586050 Fix PDF rendering blur on high-DPI/mobile screens
All checks were successful
Build and push Docker image / build (push) Successful in 13s
Test / test (push) Successful in 14s
Scale canvas by devicePixelRatio and constrain CSS size to logical
pixels so PDF pages render crisp on Retina and mobile displays.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:48:44 +02:00