From 8e63867ad8ace687fd3fb2fb572f0ab55cc53bbc Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 7 Jun 2026 19:07:34 +0200 Subject: [PATCH] docs(specs): UI specs for Lesereisen reader and Journey editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lesereisen-reader-spec.html — Issue #752 LR-0 type selector on /geschichten/new LR-1 REISE badge on the list LR-2 Journey reader (ordered cards, interlude asides, no position numbers) lesereisen-editor-spec.html — Issue #753 LE-1 empty JourneyEditor layout LE-2 editor with mixed items (documents + interludes, drag handles) LE-3 inline note-editing state LE-4 mobile layout Co-Authored-By: Claude Sonnet 4.6 --- docs/specs/lesereisen-editor-spec.html | 808 +++++++++++++++++++++++++ docs/specs/lesereisen-reader-spec.html | 727 ++++++++++++++++++++++ 2 files changed, 1535 insertions(+) create mode 100644 docs/specs/lesereisen-editor-spec.html create mode 100644 docs/specs/lesereisen-reader-spec.html diff --git a/docs/specs/lesereisen-editor-spec.html b/docs/specs/lesereisen-editor-spec.html new file mode 100644 index 00000000..6b9ea590 --- /dev/null +++ b/docs/specs/lesereisen-editor-spec.html @@ -0,0 +1,808 @@ + + + + + + Lesereisen — Journey-Editor · Familienarchiv + + + + +
+ + +
+
+

Lesereisen — Journey-Editor

+

Kuratierungs-Oberfläche für JourneyEditor auf /geschichten/[id]/edit (wenn type === 'JOURNEY'). Geordnete Briefliste mit Drag-to-Reorder, Dokumenten-Picker, Interlude-Notizen und Inline-Annotation-Editing. Ersetzt den TipTap-Editor für den Journey-Typ.

+
+
+ Familienarchiv
+ Final Spec
+ 2026-06-07 · @leonievoss
+ Issue #753 +
+
+ + +
+
E
+
+

Journey-Editor

+

BLOG_WRITERs kuratieren eine geordnete Briefsequenz — Briefe hinzufügen, Zwischentexte einfügen, Reihenfolge per Drag anpassen, Notizen inline bearbeiten.

+
/geschichten/[id]/edit (type === 'JOURNEY')
+
+
+ + +
+
Konzept
+

Der JourneyEditor ist eine parallele Implementierung zum bestehenden GeschichteEditor und wird auf derselben Edit-Route eingeblendet wenn type === 'JOURNEY'. Das Split-Layout (70/30) bleibt erhalten: links die Briefliste, rechts die Sidebar mit Personen und Status.

+

Die linke Fläche zeigt: oben einen optionalen Einleitungs-Textarea (body), darunter die geordnete Itemliste, ganz unten eine Aktionsleiste mit „+ Brief hinzufügen" und „+ Zwischentext hinzufügen". Jedes Item hat einen Drag-Handle, eine Positionsnummer, den Inhalt und einen Entfernen-Button.

+

Dokument-Items zeigen Titel und Kurz-Metadaten. Eine „Notiz hinzufügen/bearbeiten"-Aktion expandiert ein Textarea direkt unterhalb des Items — kein Modal, kein separates Formular. Interlude-Items (reiner Zwischentext) zeigen direkt ein editierbares Textarea mit orangenem Hintergrund zur klaren visuellen Unterscheidung.

+

Speicheraktionen: Speichern (bei veröffentlichter Journey) oder „Entwurf speichern" + „Veröffentlichen" (bei DRAFT). Die Savebarlogik ist identisch zum GeschichteEditor. Alle Mutationen lösen sofort einen API-Call aus und aktualisieren den lokalen Zustand optimistisch — kein separates Save für einzelne Items.

+
+ + +
+
Screens — Leerer Editor
+ +
+
+

LE-1 — Journey-Editor leer

+ Issue #753 · LE-1 +
+

Ausgangszustand einer neuen oder leeren Lesereise. Titel-Input oben. Darunter ein optionaler Einleitungs-Textarea. Leere Itemliste mit Leerstate-Text. Aktionsleiste mit zwei Buttons. Sidebar: Personen-Verknüpfung und Status-Anzeige. Keine Items → „Veröffentlichen" noch nicht aktiv (Disabled-Hint erscheint).

+

Varianten: Neuer Entwurf ohne Titel (hier gezeigt) · Mit Titel, leere Liste

+ +
+
+ Desktop — 1040px · Neuer Entwurf +
+
+ + + Dokumente + Personen + Geschichten + Chronik +
+
MR
+
+
+
+
+
+ Neue Lesereise + REISE +
+
ENTWURF
+
+
+ +
+ +
+
+
Einleitung (optional)
+ +
+
+
Briefe & Zwischentexte
+
+
Noch keine Einträge. Füge den ersten Brief oder einen Zwischentext hinzu.
+
+
+ + +
+
+ +
+
+
Personen
+
+ 🔍 +
Person suchen…
+
+
Welche historischen Personen kommen in dieser Lesereise vor?
+
+
+
+
Status
+
ENTWURF
+
Noch nicht öffentlich sichtbar. Füge mindestens einen Brief hinzu, um zu veröffentlichen.
+
+
+
+
+ Alle Änderungen werden als Entwurf gespeichert. +
+ + +
+
+
+
+
+ +
+

impl-ref — LE-1 Leerer Editor

+ + + + + + + + + + + + + + + + + + +
ElementWertHinweise
Seitenstruktur
Bedingte Verzweigung{#if geschichte.type === 'JOURNEY'}<JourneyEditor />{:else}<GeschichteEditor />{/if}in edit/+page.svelte; Props: geschichte: Geschichte
Split-Layoutflex flex-1 overflow-hidden (gleich wie GeschichteEditor)70/30; Sidebar identisch
Topbar-Badge„REISE" Pill neben dem Titel-Labelorange; kein interaktives Element; zeigt Typ
Titel-Input
Titel-Inputfont-serif text-2xl border-b border-line pb-2 w-full bg-transparent outline-nonebind:value={title}; gleiche Validierung wie GeschichteEditor (required)
Einleitungs-Textarea
Intro-Textareafont-serif text-sm italic text-ink-3 leading-relaxed w-full resize-none bg-transparent outline-none border-none py-1bind:value={body}; plaintext; auto-resize per rows-attr oder JS
Labeltext-[10px] font-bold uppercase tracking-widest text-ink-3 mb-1„EINLEITUNG (OPTIONAL)"
Leerstate
Leerstate-Containerpy-8 text-center border border-dashed border-line rounded-sm bg-surfaceverschwindet sobald erstes Item vorhanden
Leerstate-Textfont-serif text-xs text-ink-3 italic
Veröffentlichen-Button
Disabled-Zustanddisabled={items.length === 0 || !title.trim()}opacity-40 + cursor-not-allowed; keine Tooltip nötig — Sidebar-Hint erklärt es
+
+
+
+ + +
+
Screens — Editor mit Einträgen
+ +
+
+

LE-2 — Journey-Editor mit Einträgen

+ Issue #753 · LE-2 +
+

Gefüllte Itemliste mit gemischten Typen: Dokument-Item ohne Notiz, Interlude-Item (reiner Zwischentext), Dokument-Item mit bestehender Notiz. Jedes Item zeigt Drag-Handle links, Positionsnummer, Inhalt und Entfernen-Button. Aktionsleiste bleibt unter der Liste sichtbar.

+

Varianten: Veröffentlichte Journey (hier gezeigt) · Entwurf · Mobile

+ +
+
+ Desktop — 1040px · VERÖFFENTLICHT +
+
+ + + Dokumente + Personen + Geschichten +
+
KR
+
+
+
+
+
+ Lesereise bearbeiten + REISE +
+
VERÖFFENTLICHT
+ Löschen +
+
+ +
+ +
+
+
Einleitung (optional)
+ +
+
+
Briefe & Zwischentexte
+ + +
+
+
+
+
+
+
+
1
+
+
Brief vom 12. Juli 1938
+
12. Juli 1938 · von Franz Raddatz an Emma Müller
+
+ + Notiz hinzufügen +
+
+
×
+
+ + +
+
+
+
+
+
+
+
+ +
+
+
Zwischentext
+ +
+
×
+
+ + +
+
+
+
+
+
+
+
2
+
+
Postkarte aus Breslau, August 1938
+
22. Aug. 1938 · von Franz Raddatz an Emma Müller
+ +
+ + Notiz entfernen +
+
+
×
+
+ + +
+
+
+
+
+
+
+
3
+
+
Brief vom 3. September 1939
+
3. Sept. 1939 · von Emma Müller an Franz Raddatz
+
+ + Notiz hinzufügen +
+
+
×
+
+ + +
+ + +
+
+ + +
+
+
Personen
+
+ 🔍 +
Person suchen…
+
+
+ + FR + Franz Raddatz + × + + + EM + Emma Müller + × + +
+
+
+
+
Status
+
VERÖFFENTLICHT
+
Änderungen gehen sofort live.
+
+
+
+
+ Änderungen sofort live — Leser sehen die aktuelle Version. +
+ + +
+
+
+
+
+ +
+

impl-ref — LE-2 Items-Liste

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ElementWertHinweise
Item-Zeile allgemein
Item-Containerflex items-stretch bg-white border border-line rounded-sm mb-2 overflow-hiddeninterlude: bg-orange-50 border-orange-200
Drag-Handlew-4 bg-surface border-r border-line flex items-center justify-center cursor-grab shrink-0aria-label="Reihenfolge ändern"; cursor-grabbing während Drag
Positions-Nr.w-5 text-[10px] font-bold text-ink-3 flex items-start justify-center pt-2 shrink-0aus Array-Index, nicht item.position
Entfernen-Buttonw-6 flex items-start justify-center pt-2 shrink-0× aria-label="Eintrag entfernen"; hover: text-red-500; Confirm nur wenn note vorhanden
Dokument-Item
Brieftiteltext-[11px] font-semibold text-ink leading-snug mb-0.5document.title
Briefmetatext-xs text-ink-3formatDate(doc.documentDate) · "von X" oder "von X an Y"
Notiz-Textarea (sichtbar)w-full min-h-[40px] font-serif text-xs italic bg-surface border border-line rounded-sm p-1.5 resize-none focus:border-primary focus:bg-white mt-2auto-expand; bind:value={item.note}
„Notiz hinzufügen" Linktext-xs font-semibold text-blue-600 inline-flex items-center gap-1 mt-1togglet Notiz-Textarea
„Notiz entfernen" Linktext-xs text-ink-3 inline-flex items-center gap-1 mt-1zeigt sich wenn note.trim() nicht leer; setzt note = '' und blendet Textarea aus
Interlude-Item
Interlude-Containerbg-orange-50 border-orange-200 (überschreibt Item-Container)kein Positions-Kreis; Positions-Spalte zeigt Icon statt Zahl
Label „Zwischentext"text-[9px] font-bold uppercase tracking-widest text-orange-700 mb-1immer sichtbar; nicht editierbar
Zwischentext-Textareaw-full min-h-[44px] font-serif text-xs italic bg-white/60 border border-orange-200 rounded-sm p-1.5 resize-none focus:border-orange-400bind:value={item.note}; auto-expand; min 44px für Touch-Target
Aktionsleiste
Add Barflex gap-2 pt-2 pb-1immer unten sichtbar, auch wenn Liste gefüllt
„Brief hinzufügen" Buttonborder border-dashed border-line rounded-sm px-3 py-1.5 text-xs font-semibold text-ink-2 hover:border-primary hover:text-primary flex items-center gap-1öffnet existierende DocumentPicker-Komponente als Dropdown/Modal
„Zwischentext hinzufügen" Buttongleich wie Brief-Buttonfügt neues Interlude-Item am Ende ein; Fokus auf das neue Textarea
Drag-to-Reorder
Bibliothek@dnd-kit/core oder svelte-dnd-action (bereits im Projekt prüfen)kein neues Package ohne Absprache
Reorder-API-CallPUT /api/geschichten/{id}/items/reorder — body: [{id, position}] für alle Itemsnach jedem Drop ausgelöst; optimistisch: lokalen State sofort aktualisieren
AccessibilityDrag-Handle: role="button" tabIndex=0; Keyboard: Space startet Drag, Arrow hoch/runter verschiebt, Space/Enter bestätigt, Esc abbrichtWCAG 2.1 SC 2.1.1
+
+
+
+ + +
+
Screens — Inline-Notiz-Editing
+ +
+
+

LE-3 — Notiz-Textarea wird geöffnet

+ Issue #753 · LE-3 +
+

Wenn der Nutzer auf „Notiz hinzufügen" klickt, expandiert das Item um ein Textarea direkt unterhalb der Briefmeta — kein Modal. Der Fokus springt automatisch in das Textarea. Das Textarea hat einen blauen Fokusring als Orientierungshilfe. Ein API-PATCH wird beim Verlassen des Textareas (blur) ausgelöst, nicht bei jedem Tastendruck.

+

Inset-Ansicht — kein vollständiger Seiten-Mockup nötig

+ +
+
+ Inset — Notiz-Textarea geöffnet (Fokus) +
+ +
+
+
+
+
+
+
+
1
+
+
Brief vom 12. Juli 1938
+
12. Juli 1938 · Franz → Emma
+
+ + Notiz hinzufügen +
+
+
×
+
+ + +
+
+
+
+
+
+
+
2
+
+
Postkarte aus Breslau, August 1938
+
22. Aug. 1938 · Franz → Emma
+ + +
Wird gespeichert, wenn du das Feld verlässt.
+
+ + Notiz entfernen +
+
+
×
+
+
+
+
+ +
+

impl-ref — LE-3 Inline-Notiz

+ + + + + + + + + + + + + + + +
ElementWertHinweise
Toggleverhalten
Lokaler Statelet noteOpen = item.note !== null and item.note !== ''öffnet sich automatisch wenn Notiz bereits vorhanden
„Notiz hinzufügen" KlicknoteOpen = true; tick().then(() => noteTextarea.focus())Fokus nach Svelte-Tick um DOM-Update abzuwarten
Textarea blur-Handleron:blur={() => saveNote(item.id, note)}PATCH /api/geschichten/{id}/items/{itemId} mit {note}
Leere Notiz on blurwenn note.trim() === '' → noteOpen = false; note = nullverhindert leere Notizen im Backend
Fokus-Styling
Fokus-Ringfocus:border-primary focus:ring-2 focus:ring-primary/20 focus:bg-whitesichtbarer Ring für Keyboard-Navigation; ring-offset für Abstand
Spar-Hinttext-[9px] text-ink-3 mt-1„Wird gespeichert, wenn du das Feld verlässt."; verschwindet wenn noteOpen = false
Barrierefreiheit
aria-label Textareaaria-label="Kuratoren-Notiz für {document.title}"spezifisch; Screen-Reader nennt Brief-Kontext
aria-expanded Togglearia-expanded={noteOpen} auf „Notiz hinzufügen"-Buttonkommuniziert Expand-State
+
+
+
+ + +
+
Screens — Mobile Editor
+ +
+
+

LE-4 — Mobile Journey-Editor

+ Issue #753 · LE-4 +
+

Auf Mobile (320px) entfällt die Sidebar-Split. Die Personen- und Status-Sektion werden als ausklappbare Sektionen unter der Itemliste gezeigt. Drag-to-Reorder ist auf Mobile durch Long-Press aktiviert. Die Aktionsleiste scrollt mit dem Inhalt.

+

Primäre Zielgruppe für den Editor: Desktop/Tablet. Mobile ist sekundär — alle Funktionen erreichbar, aber Drag ist schwerer bedienbar.

+ +
+
+ Mobile — 320px · mit Einträgen +
+
9:41●●●
+
+ +
+ + Lesereise bearbeiten +
VERÖFF.
+
+
+ + + +
+
+
+
+
+
+
+
+
Brief vom 12. Juli 1938
+
12. Juli 1938 · Franz → Emma
+
+
×
+
+ + +
+
+
+
Zwischentext
+
Im Sommer 1938 schrieb Franz voller Zuversicht…
+
+
×
+
+ + +
+
+
+
Postkarte Aug. 1938
+
22. Aug. 1938 · Franz → Emma
+
Diese Karte ist ungewöhnlich kurz für Franz…
+
+
×
+
+ + +
+ + +
+ + +
+
+ Personen + +
+
+ +
+
+ Status & Speichern + +
+
+
+
+ + +
+
+
+
+
+ +
+

impl-ref — LE-4 Mobile

+ + + + + + + + + + + + + +
ElementWertHinweise
Layout-Anpassungen
Split entfällt@media (max-width: 768px): flex-col; Sidebar-Sektionen als Collapsibles am Endegleich wie GeschichteEditor auf Mobile
Collapsiblesdetails/summary oder eigene boolean-Toggle; Personen + Status separatgeschlossen beim ersten Laden; Fokus öffnet
Touch & Drag
Drag auf MobileLong-Press (500ms) auf dem Drag-Handle aktiviert Dragdnd-kit unterstützt Touch nativ; kein separates Config nötig
Touch Target Itemsmin-h-[44px] für jede Item-ZeileWCAG 2.2 AA; durch Padding gesichert
Add-Buttonsflex-1; volle verfügbare Breite geteiltmin-h-[44px] als Touch-Target
Savebar
Savebar Mobileflex gap-2; „Zurück zu Entwurf" komprimiert zu „Entwurf"Volltext passt nicht auf 320px
+
+
+
+ + +
+

Implementation Guide — Journey-Editor

+ +

Neue Komponente

+ + + + + + +
DateiTypBeschreibung
src/lib/geschichte/JourneyEditor.svelteSvelte-KomponenteHauptkomponente; Props: geschichte: Geschichte
src/lib/geschichte/JourneyItemRow.svelteSvelte-KomponenteEine Zeile (Dokument oder Interlude); Props: item: JourneyItem, position: number, Events: remove, noteChange
+ +

Edit-Page-Integration

+
    +
  • GeschichteEditor.svelte erhält ein neues Prop type: GeschichteType.
  • +
  • Wenn type === 'JOURNEY': rendere JourneyEditor statt TipTap-Editor. Die Sidebar (Personen, Status, Savebar) bleibt identisch.
  • +
  • Die Savebar-Logik ist in der Edit-Page (+page.svelte) verankert — JourneyEditor gibt nur Änderungen nach oben (Svelte-Events oder bindable Props), die Seite hält den Save-State.
  • +
+ +

API-Calls

+ + + + + + + + + +
AktionEndpointBody
Brief hinzufügenPOST /api/geschichten/{id}/items{documentId: UUID}
Zwischentext hinzufügenPOST /api/geschichten/{id}/items{note: string}
Notiz speichern/bearbeitenPATCH /api/geschichten/{id}/items/{itemId}{note: string | null}
Item entfernenDELETE /api/geschichten/{id}/items/{itemId}
Reihenfolge speichernPUT /api/geschichten/{id}/items/reorder[{id: UUID, position: number}]
+ +

Optimistische Updates

+
    +
  • Alle Mutationen (add, remove, reorder, noteChange) aktualisieren den lokalen State sofort, der API-Call läuft parallel.
  • +
  • Bei Fehler: lokalen State zurückrollen und einen aria-live="polite"-Fehlerhinweis anzeigen.
  • +
  • Notiz-Saving ist ein Sonderfall: es gibt kein optimistisches Update da der Wert bereits live im Textarea ist — nur blur → PATCH.
  • +
+ +

DocumentPicker-Integration

+
    +
  • Der „Brief hinzufügen"-Button öffnet die bestehende DocumentPicker-Komponente (prüfe $lib/document/ auf vorhandene Typeahead-Komponenten).
  • +
  • Nach Auswahl eines Dokuments: POST /items mit documentId, neues Item wird an das Ende der Liste angehängt und eingeblendet.
  • +
  • Bereits in der Journey enthaltene Dokumente: in der Picker-Ergebnisliste mit einem „Bereits enthalten"-Hinweis markieren und deaktivieren.
  • +
+ +

Drag-to-Reorder

+
    +
  • Bibliothek: prüfe zunächst ob @dnd-kit/core oder svelte-dnd-action bereits im package.json ist. Kein neues Package einführen ohne Absprache.
  • +
  • Nach dem Drop: neue Reihenfolge als Array [{id, position}] berechnen (position = index * 10 lässt Lücken für künftige Inserts) und PUT /items/reorder senden.
  • +
  • Keyboard-Drag: Space/Enter startet, Arrow Up/Down verschiebt, Space/Enter bestätigt, Escape abbricht. Screenreader-Announcement: „Eintrag X von Position Y nach Z verschoben".
  • +
+ +

Barrierefreiheit

+
    +
  • Items-Liste: <ol>-Element — kommuniziert die Ordnung an Screenreader.
  • +
  • Drag-Handle: role="button", tabindex="0", aria-label="Reihenfolge von '{title}' ändern".
  • +
  • Entfernen-Button: aria-label="'{title}' entfernen"; kein reines ×-Zeichen ohne Label.
  • +
  • Notiz-Textarea: aria-label="Kuratoren-Notiz für '{title}'".
  • +
  • Touch-Targets: alle interaktiven Elemente min 44×44px (WCAG 2.2 AA).
  • +
  • Fokusring: focus-visible:ring-2 focus-visible:ring-primary auf allen Buttons und Textareas.
  • +
+ +

Abgrenzung zu GeschichteEditor

+
    +
  • TipTap wird für JOURNEY nicht geladen — kein unnötiger Bundle-Load.
  • +
  • Die Sidebar (Personen, Status) ist für beide Typen identisch — kein Duplikat, die Sidebar-Komponente wird geteilt.
  • +
  • Savebar-Logik (DRAFT/PUBLISHED/Retract) ist identisch — JourneyEditor ändert sie nicht.
  • +
  • Geschichte.body dient für JOURNEY als Einleitungstext (Plaintext, kein HTML). Kein Rich-Text-Rendering auf der Leseseite nötig.
  • +
+
+ +
+ + diff --git a/docs/specs/lesereisen-reader-spec.html b/docs/specs/lesereisen-reader-spec.html new file mode 100644 index 00000000..ccde15b5 --- /dev/null +++ b/docs/specs/lesereisen-reader-spec.html @@ -0,0 +1,727 @@ + + + + + + Lesereisen — Reader-Integration · Familienarchiv + + + + +
+ + +
+
+

Lesereisen — Reader-Integration

+

Typauswahl bei /geschichten/new, Journey-Badge auf der Übersichtsliste und die neue geordnete Leseansicht auf /geschichten/[id] wenn type === 'JOURNEY'. Bestehende Story-Ansichten bleiben unverändert.

+
+
+ Familienarchiv
+ Final Spec
+ 2026-06-07 · @leonievoss
+ Issue #752 +
+
+ + +
+
R
+
+

Lesereisen — Reader

+

Alle angemeldeten Familienmitglieder können Lesereisen entdecken und in Briefsequenzen mit Kuratoren-Notizen eintauchen. BLOG_WRITERs sehen zusätzlich Bearbeiten/Löschen-Aktionen.

+
/geschichten · /geschichten/new · /geschichten/[id]
+
+
+ + +
+
Konzept
+

Eine Lesereise ist eine Geschichte mit type === 'JOURNEY'. Ihr Kerninhalt ist eine geordnete Sequenz von Briefen (JourneyItems mit document_id) und Zwischentexten (JourneyItems ohne document_id). Das optionale Feld body dient als Einleitung/Preface.

+

Diese Spec deckt drei Änderungen ab: (1) die Typauswahl auf /geschichten/new als vorgelagerter Schritt, (2) das „REISE"-Badge in der Übersichtsliste, und (3) die neue Journey-Leseansicht auf der Detailseite, die den bestehenden Prosa-Body durch eine nummerierte Briefliste ersetzt.

+

Dokument-Items zeigen Titel, Datum, Sender→Empfänger und einen Link zum Brief. Optionale Kuratoren-Notizen erscheinen als Annotation mit Mint-Linker-Rand unter dem Briefeintrag. Interlude-Items (kein Dokument) erscheinen als eingerückte Absätze mit orangenem linken Rand — klar vom Dokumenttyp unterscheidbar, aber harmonisch im Lesefluss.

+
+ + +
+
Screens — Typauswahl
+ +
+
+

LR-0 — Typauswahl /geschichten/new

+ Issue #752 · LR-0 +
+

Neuer vorgelagerter Schritt beim Erstellen einer Geschichte. Zwei Karten zur Auswahl: „Geschichte" (Prosa) und „Lesereise" (Briefsequenz). Die ausgewählte Karte wird hervorgehoben. Erst nach Auswahl wird der „Weiter"-Button aktiv. Auswahl bleibt im URL-Param erhalten (?type=JOURNEY).

+

Varianten: Keine Auswahl (Weiter-Button inaktiv) · Lesereise gewählt (hier gezeigt) · Geschichte gewählt

+ +
+
+ Desktop — 1040px · Lesereise gewählt +
+
+ + + Dokumente + Personen + Geschichten + Chronik +
+
MR
+
+
+
+
+
Neue Geschichte
+
ENTWURF
+
+
+
+
Was möchtest du erstellen?
+
+ +
+
✍️
+
Geschichte
+
Freier Prosatext über Familienerlebnisse, Erinnerungen oder historische Einordnungen — mit verlinkten Personen und Dokumenten.
+
+ +
+
📜
+
Lesereise
+
Geordnete Briefsequenz mit optionalen Kuratoren-Notizen zwischen den Briefen — für chronologische Korrespondenz-Sammlungen.
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+

impl-ref — LR-0 Typauswahl

+ + + + + + + + + + + + + + + + + + +
ElementWertHinweise
Layout
Selector areaflex flex-1 items-center justify-center bg-canvas px-6 py-10zentriert, füllt restliche Höhe
Fragefont-serif text-sm text-ink-2 text-center mb-4
Karten-Gridflex gap-42 gleich breite Karten; auf Mobile flex-col
Type-Karte
Karte (inaktiv)border border-line rounded-md p-4 bg-white cursor-pointer hover:border-primary hover:bg-surfacefocus-visible:ring-2 focus-visible:ring-primary
Karte (ausgewählt)border-2 border-orange-500 bg-orange-50 shadow-smaria-pressed="true"; kein Tailwind-Kürzel — nutze CSS-var(--orange)
Check-Kreisw-5 h-5 rounded-full bg-orange-500 flex items-center justify-center self-end mt-2nur sichtbar wenn ausgewählt
Kartentitelfont-serif text-sm text-ink
Kartenbeschreibungtext-xs text-ink-3 leading-relaxed mt-1
Navigation
Weiter-Buttonrounded border border-primary bg-primary text-white px-4 py-2 text-sm font-medium disabled:opacity-40disabled wenn keine Karte ausgewählt
URL-Param?type=STORY | ?type=JOURNEYper goto() nach Klick auf Weiter; lesefreundlich bookmarkbar
Mobileflex-col Karten; volle Breitekein Scrollbedarf auf 320px
+
+
+
+ + +
+
Screens — Übersichtsliste
+ +
+
+

LR-1 — Reise-Badge in /geschichten

+ Issue #752 · LR-1 +
+

Die Übersichtsliste erhält ein kleines „REISE"-Badge in der Metaspalte einer Journey-Zeile — unterhalb von Datum und Personenchip. Zeilen mit type === 'STORY' bleiben unverändert. Das Badge ist nicht klickbar, dient als reine visuelle Unterscheidung.

+

Varianten: Mischte Liste (hier gezeigt) · Nur-Journey-Filter · Nur-Story-Ansicht (unverändert)

+ +
+ +
+ Desktop — 1040px · gemischte Liste +
+
+ + + Dokumente + Personen + Geschichten + Chronik +
+
MR
+
+
+
+
+ Geschichten + +
+
+
+ Alle + Franz Raddatz + Emma Müller + + Person wählen +
+ +
+
+
MR
+
Maria Raddatz
+
14. März 2025
+ + FR + Franz Raddatz + +
+
+
Der Sommer in Breslau
+
Oma erzählte oft vom letzten Sommer vor dem Krieg, als die Familie noch vollständig zusammen war und niemand ahnte, was kommen würde…
+
+
+ +
+
+
KR
+
Klaus Raddatz
+
15. Mai 2025
+ + FR + Franz Raddatz + + REISE +
+
+
Briefe aus Breslau 1938–1942
+
Eine Lesereise durch den Briefwechsel zwischen Franz und Emma — von den letzten Friedenssommern bis zum Ende des Krieges.
+
+
+ +
+
+
GK
+
Gertrud Koch
+
18. Okt. 2024
+ + EM + Emma Müller + +
+
+
Die Hochzeit im Krieg
+
1943, mitten im Chaos — Emma bestand darauf, dass das Fest stattfand. Ihr Bruder kam auf Fronturlaub, drei Tage nur, aber es reichte…
+
+
+
+
+
+
+ + +
+ Mobile — 320px +
+
9:41●●●
+
+ +
+
+ Geschichten +
+
+ Alle + Franz Raddatz + + Person… +
+
+ +
+
+
MR
+ Maria Raddatz + 14. Mrz. 2025 +
+
Der Sommer in Breslau
+
Oma erzählte oft vom letzten Sommer vor dem Krieg…
+
+ +
+
+
KR
+ Klaus Raddatz + 15. Mai 2025 +
+
+
Briefe aus Breslau 1938–1942
+ REISE +
+
Eine Lesereise durch den Briefwechsel zwischen Franz und Emma…
+
+
+
+
+
+
+
+ +
+

impl-ref — LR-1 Journey-Badge in der Liste

+ + + + + + + + + + + +
ElementWertHinweise
Badge
Journey badgeinline-flex items-center px-1.5 py-px rounded-sm text-[10px] font-bold uppercase tracking-wide bg-orange-50 text-orange-700 border border-orange-200nur wenn type === 'JOURNEY'
Position Desktopunterhalb Datum-Text und Personenchip in der Metaspalte (g-meta)kein extra Abstand nötig — gap-1 der Flex-Spalte reicht
Position Mobileinline flex items-center gap-1.5 neben TitelTitel + Badge in einem flex-Wrapper; badge shrink-0
aria-labelaria-label="Lesereise"Badge ist span, kein interaktives Element
Bedingte Logik
Svelte guard{#if geschichte.type === 'JOURNEY'}<span …>REISE</span>{/if}kein Badge für STORY
+
+
+
+ + +
+
Screens — Journey-Leseansicht
+ +
+
+

LR-2 — Journey-Detail /geschichten/[id]

+ Issue #752 · LR-2 +
+

Wenn type === 'JOURNEY' ersetzt die geordnete Briefliste den Prosa-Body. Optional zeigt ein Einleitungsabsatz (body) vor den Items. Jedes Item ist entweder ein Briefeintrag (Kartentitel, Datum, Link) oder ein Interlude-Absatz (orangener linker Rand, kursiv). Die Reihenfolge ergibt sich von oben nach unten — keine Nummern. Briefeinträge können eine optionale Kuratoren-Annotation unter dem Link zeigen.

+

Varianten: Leserin ohne Schreibrecht · BLOG_WRITER (Bearbeiten/Löschen sichtbar — hier gezeigt) · Mobile

+ +
+ +
+ Desktop — 1040px · BLOG_WRITER-Ansicht +
+
+ + + Dokumente + Personen + Geschichten + Chronik +
+
MR
+
+
+
+
+
+ + Zurück zu Geschichten +
+
LESEREISE
+
Briefe aus Breslau 1938–1942
+
+
KR
+
+
Klaus Raddatz
+
zusammengestellt am 15. Mai 2025
+
+
+ + Löschen +
+
+ +
Der Briefwechsel zwischen Franz Raddatz und seiner Schwester Emma umspannt vier Jahre — von den letzten unbeschwerten Sommerwochen 1938 bis zum Kriegsende. Diese Lesereise folgt den Briefen in chronologischer Reihenfolge.
+ +
+
+
Brief vom 12. Juli 1938
+
12. Juli 1938 · von Franz Raddatz an Emma Müller
+ +
+
+ +
+
Im Sommer 1938 schrieb Franz voller Zuversicht — er hatte kaum eine Ahnung, wie bald sich die Welt um ihn herum verändern würde. Seine Briefe aus dieser Zeit tragen eine Leichtigkeit, die in den späteren Kriegsjahren vollständig verschwindet.
+
+ +
+
+
Postkarte aus Breslau, August 1938
+
22. Aug. 1938 · von Franz Raddatz an Emma Müller
+ +
+
Diese Karte ist ungewöhnlich kurz für Franz — vier Zeilen, fast hastig. Ein Zeichen der aufkommenden Unruhe in den Nachrichten, oder schlicht die Hitze des Augusts?
+
+
+
+ +
+
+
Brief vom 3. September 1939
+
3. Sept. 1939 · von Emma Müller an Franz Raddatz
+ +
+
+
+
+
+
+ + +
+ Mobile — 320px · Leserin +
+
9:41●●●
+
+ +
+
+
+ + Zurück +
+
LESEREISE
+
Briefe aus Breslau 1938–1942
+
+
KR
+
+
Klaus Raddatz
+
15. Mai 2025
+
+
···
+
+
+
Der Briefwechsel zwischen Franz und Emma — von 1938 bis Kriegsende.
+ +
+
+
Brief vom 12. Juli 1938
+
12. Juli 1938 · Franz → Emma
+ +
+
+ +
+
Im Sommer 1938 schrieb Franz voller Zuversicht — er hatte kaum eine Ahnung, wie bald sich die Welt um ihn herum verändern würde.
+
+ +
+
+
Postkarte Aug. 1938
+
22. Aug. 1938 · Franz → Emma
+ +
+
+
+
+
+
+
+
+ +
+

impl-ref — LR-2 Journey-Leseansicht

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ElementWertHinweise
Seitenstruktur
Bedingte Logik{#if geschichte.type === 'JOURNEY'} JourneyReader {:else} StoryReader {/if}in +page.svelte von /geschichten/[id]
Artikel-Containermax-w-3xl mx-auto px-4 py-8gleich wie StoryReader
Journey-Badgeinline-flex px-2 py-px rounded-sm text-[10px] font-bold uppercase tracking-widest bg-orange-50 text-orange-700 border border-orange-200 mb-2über dem Titel; nicht für STORY
Titelfont-serif text-3xl text-ink leading-tight mb-4gleich wie Story
Metabarflex items-center gap-3 pb-4 border-b border-subtle mb-4gleich wie Story
Bearbeiten/Löschennur BLOG_WRITE; auf Mobile im ··· BottomSheetgleich wie Story
Intro-Absatz
Intro (body)font-serif text-sm text-ink-2 italic leading-relaxed mb-6 pb-4 border-b border-dashed border-subtlenur rendern wenn body nicht leer; kein HTML-Rendering — plaintext
Dokument-Item
Item-Zeilemb-3kein flex nötig — Karte ist full-width
Dokumentkartebg-white border border-line rounded-sm p-3
Brieftitelfont-serif text-sm text-ink leading-snug mb-0.5document.title
Briefmetatext-xs text-ink-3 mb-2formatDate(document.documentDate) · "von X an Y"
Brief öffnen Linkinline-flex items-center gap-1 text-xs font-semibold text-ink hover:text-primaryhref="/documents/{item.document.id}"
Kuratoren-Annotation
Annotationmt-3 pl-3 border-l-2 border-mint bg-surface rounded-r-sm py-1.5 pr-2nur rendern wenn item.note vorhanden
Annotations-Texttext-xs italic text-ink-2 leading-relaxed
Interlude-Item
Interlude-Blockpl-3 border-l-2 border-orange-400 bg-orange-50 rounded-r-sm py-2 pr-3 my-4item.document === null
Interlude-Texttext-xs italic text-ink leading-relaxeditem.note; plaintext
Mobile
··· Menüml-auto text-ink-3; öffnet BottomSheet mit Bearbeiten + LöschenBLOG_WRITE; gleich wie Story
Touch Target (Brief öffnen)min-h-[44px] durch padding auf der KarteWCAG 2.2 AA
+
+
+
+ + +
+

Implementation Guide — Lesereisen Reader

+ +

Geänderte Views und Routen

+ + + + + + + +
ViewRouteÄnderung
Neue Geschichte/geschichten/newNeuer Typauswahl-Schritt als first render; setzt ?type=STORY|JOURNEY
Geschichten-Liste/geschichtenJourney-Badge in GeschichtenCard wenn type === 'JOURNEY'
Geschichte-Detail/geschichten/[id]Bedingte Verzweigung: JourneyReader | StoryReader
+ +

Neue Komponenten

+
    +
  • JourneyReader.svelte — rendert Intro + Items-Liste; Props: geschichte: GeschichteDetail
  • +
  • JourneyItemCard.svelte — ein Dokument-Item mit optionaler Annotation; Props: item: JourneyItem, position: number
  • +
  • JourneyInterlude.svelte — ein reiner Text-Interlude; Props: note: string
  • +
+ +

Datenmodell (nach #750)

+
    +
  • GeschichteType: 'STORY' | 'JOURNEY'
  • +
  • JourneyItem: { id: UUID, position: number, document: DocumentSummary | null, note: string | null }
  • +
  • Geschichte.items — geordnete Liste (nach position ASC); für STORY leer
  • +
  • Geschichte.body — für JOURNEY der optionale Einleitungstext (plaintext, kein HTML); für STORY der Rich-Text-Body
  • +
+ +

Typauswahl — Implementierungshinweise

+
    +
  • Die Typauswahl ist ein Schritt INNERHALB der /geschichten/new-Route — kein eigener URL, kein goto(). Zustand let selectedType: GeschichteType | null = null in der Komponente.
  • +
  • Erst wenn selectedType !== null ist der „Weiter"-Button aktiviert (disabled={!selectedType}).
  • +
  • Nach Klick auf „Weiter": wenn selectedType === 'JOURNEY'goto('/geschichten/new?type=JOURNEY') und zeige den Journey-Editor (aus Issue #753); wenn STORY → bestehender GeschichteEditor (unverändert).
  • +
  • Die Karten verwenden role="radio" und aria-checked für Accessibility. Keyboard: Arrow-Keys wechseln zwischen den Karten, Space/Enter wählt aus.
  • +
+ +

Journey-Badge — Implementierungshinweise

+
    +
  • Badge nur in GeschichtenCard.svelte hinzufügen — keine Änderung an der Listenlogik oder dem API-Aufruf.
  • +
  • Text: „REISE" (Kurzform für die Metaspalte); aria-label="Lesereise" für den Badge-Span.
  • +
+ +

Journey-Reader — Implementierungshinweise

+
    +
  • Items werden bereits geordnet vom Backend geliefert (ORDER BY position ASC). Keine client-seitige Sortierung nötig.
  • +
  • Ein Item ist Interlude wenn item.document === null. In diesem Fall: JourneyInterlude-Komponente rendern.
  • +
  • Der Intro-Absatz (body) wird als Plaintext gerendert — nicht als innerHTML. Im Editor wird es als einfaches Textarea gespeichert, kein HTML.
  • +
+ +

Berechtigungen

+
    +
  • „Bearbeiten" und „Löschen" nur für currentUser.permissions.includes('BLOG_WRITE') — gleich wie Story.
  • +
  • Auf Mobile: Bearbeiten/Löschen im BottomSheet hinter ··· — gleich wie Story.
  • +
+ +

Barrierefreiheit

+
    +
  • Items-Liste: <ol> semantisch für die geordnete Briefliste. Interludes sind <li>-Elemente mit aria-label="Kuratorennotiz".
  • +
  • „Brief öffnen"-Link: beschreibender Text mit Briefdatum im aria-label, z.B. aria-label="Brief vom 12. Juli 1938 öffnen".
  • +
  • Touch-Targets: jede Dokumentkarte hat mindestens 44px Höhe durch den Padding der Karte.
  • +
  • Fokusring: focus-visible:ring-2 focus-visible:ring-primary auf allen Links.
  • +
+
+ +
+ +