Entdeckung verlinkter Geschichten über die Personendetailseite. Lesende, die nach Franz Raddatz suchen, finden automatisch alle veröffentlichten Geschichten, die ihn erwähnen — als neue Karte am Ende der rechten Spalte.
Neugierige Leserinnen und Leser suchen Personen und finden dort alle Geschichten, die über sie erzählt wurden — ohne separaten Suchlauf.
Die Personendetailseite hat bereits eine informationsdichte rechte Spalte: Briefpartner, Beziehungen, gesendete und empfangene Briefe. Die Geschichten-Karte wird ganz am Ende dieser Spalte angehängt — sie erscheint nur, wenn mindestens eine veröffentlichte Geschichte diese Person erwähnt. Ist keine vorhanden, fehlt die Karte vollständig; kein Leerszustand, keine Platzhalter.
Innerhalb der Karte gilt das redaktionelle Listen-Layout: Metadaten links (Avatar, Autorenname, Datum), Titel und Ausschnitt rechts — konsistent mit der /geschichten-Übersichtsseite. BLOG_WRITERs sehen im Karten-Header einen Schnellzugriff, um eine neue Geschichte mit dieser Person vorauszufüllen.
Die Karte ist bewusst passiv: Sie zeigt, was andere über diese Person geschrieben haben. Sie ist kein Aufruf zum Schreiben, sondern ein stiller Hinweis auf vorhandene Erinnerungen.
Vollständige Personendetailseite mit der neuen Geschichten-Karte am Ende der rechten Spalte. Franz Raddatz hat drei veröffentlichte Geschichten, die ihn erwähnen.
Desktop · 1040px — Zweispaltiges Layout (35 % / 65 %), Karte erscheint als letztes Element rechts.
| Element | Wert / Klasse | Hinweis |
|---|---|---|
| Karten-Wrapper | ||
| Geschichten-Karte | mt-6 bg-white shadow-sm border border-brand-sand rounded-sm p-6 | Identisches Pattern wie alle anderen rechten Spalten-Karten |
| Karten-Header | flex items-center justify-between mb-5 | |
| Section-Heading | text-xs font-bold uppercase tracking-widest text-gray-400 | Projekt-Standard, identisch mit anderen Karten |
| "+ Geschichte schreiben" | text-[10px] text-turquoise font-semibold hover:underline | Link zu /geschichten/new?personId={id}, nur mit BLOG_WRITE |
| Redaktionelle Liste (Stories) | ||
| Listen-Wrapper | flex flex-col divide-y divide-brand-sand | |
| Story-Zeile | flex gap-3 py-3 first:pt-0 last:pb-0 | min-h-[44px] auf Mobile (Touch-Target WCAG 2.2) |
| Meta-Spalte | w-[72px] shrink-0 flex flex-col gap-0.5 | Feste Breite, kein Overflow |
| Autoren-Avatar | w-6 h-6 rounded-full text-[9px] font-bold text-white flex items-center justify-center | personAvatarColor(author.id) aus existierendem Util |
| Autorenname | font-sans text-[10px] font-semibold text-ink leading-tight | |
| Datum | font-sans text-[10px] text-ink-3 | formatDate(publishedAt) |
| Story-Titel (Link) | block font-serif text-[12px] text-ink hover:text-primary hover:underline leading-snug | Link zu /geschichten/{id} |
| Ausschnitt | font-sans text-[10px] text-ink-3 line-clamp-1 mt-0.5 | Erste ~80 Zeichen des body-Texts (HTML-Tags gestripped) |
| Karten-Footer | ||
| "Alle Geschichten"-Link | mt-3 block font-sans text-[10px] text-ink-3 hover:text-primary | Nur wenn geschichten.length >= 3. Link: /geschichten?personId={id} |
| Konditionelles Rendering | ||
| Karte sichtbar | {#if geschichten.length > 0} | Kein Leerszustand — Stille ist korrekt (US-BLOG-005) |
| Max. angezeigte Geschichten | 3 in der Karte | Server-seitig mit &limit=3 limitieren |
Auf Mobile kollabiert das 2-Spalten-Layout zu einer einzigen Spalte. Die Geschichten-Karte erscheint unter allen anderen Karten — genau in der Reihenfolge der Desktop-Ansicht von oben nach unten.
Mobile · 320px — SingleColumn, vollbreite Karten. Jede Geschichten-Zeile hat min-h-[44px] als Touch-Target.
Wenn keine veröffentlichten Geschichten diese Person erwähnen, erscheint die Karte nicht. Kein Leerszustand, keine Platzhalter — die Seite endet einfach bei den erhaltenen Briefen.
Stille ist korrekt — US-BLOG-005 schreibt explizit vor: „Given a document has no published stories, when I view the document detail page, then no 'Geschichten' section is shown (no empty state needed — silence is correct)." Das gilt analog für die Personenseite. Die Karte wird nur gerendert, wenn geschichten.length > 0. Keine leere Karte, kein „Noch keine Geschichten"-Text, kein Aufruf zum Schreiben an Lesende.
| Endpunkt | Änderung | Hinweis |
|---|---|---|
GET /api/geschichten?personId={id}&status=PUBLISHED&limit=3 | Neuer Filter-Parameter | Nur PUBLISHED zurückgeben, auch ohne BLOG_WRITE. Limit serverseitig. |
GET /api/persons/{id} Loader | Mitladen der Geschichten | Im +page.server.ts parallel zu sentDocuments laden. |
persons/[id]/+page.server.ts — geschichten parallel laden, in pageData exponierenpersons/[id]/+page.svelte — GeschichtenCard am Ende der rechten Spalte rendern (mt-6), nur wenn data.geschichten.length > 0$lib/components/GeschichtenCard.svelte| Prop | Typ | Verwendung |
|---|---|---|
geschichten | Geschichte[] | Die Geschichten-Liste (max. 3 vom Server) |
personId | string | undefined | Für "alle anzeigen"- und "schreiben"-Link |
canWrite | boolean | Steuert "+ Geschichte schreiben" Sichtbarkeit |
personAvatarColor(id) — bereits vorhanden in $lib/utils/personFormat.tsformatDate(date) — bereits vorhanden in $lib/utils/date.tsbody strippen, erste 80 Zeichen nehmenmin-h-[44px] je Zeile (WCAG 2.2)<section> mit aria-labelledby auf die ÜberschriftDie Komponente wird nur gerendert, wenn geschichten.length > 0. Keine leere Karte, kein Platzhaltertext, kein Aufruf zum Schreiben an Lesende ohne BLOG_WRITE-Berechtigung. Stille ist das korrekte Design für fehlende Geschichten.