740 lines
49 KiB
HTML
740 lines
49 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Geschichten — Reader Journey</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500&family=DM+Sans:wght@300;400;500;600&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet"/>
|
|
<style>
|
|
:root{--color-page:#FAFAF7;--color-surface:#F5F4EE;--color-subtle:#EDECEA;--color-border:#D8D7D0;--color-text-muted:#6B6A63;--color-text:#1C1C18;--navy:#012851;--mint:#A1DCD8;--sand:#F0EFE9;--turquoise:#00C7B1;--accent-bg:rgba(161,220,216,.12);--blue-tint:#E6F1FB;--blue:#2D7DD2;--blue-dark:#185FA5;--purple-tint:#EEEDFE;--purple:#534AB7;--purple-dark:#3C3489;--green-tint:#E8F5EA;--green:#3D8C4A;--green-dark:#2E6E39;--orange-tint:#FEF0E6;--orange:#E8862A;--orange-dark:#B46820;--font-display:'Fraunces',Georgia,serif;--font-sans:'DM Sans',system-ui,sans-serif;--font-mono:'DM Mono',monospace;--radius-sm:4px;--radius-md:6px;--radius-lg:10px;--radius-xl:16px;--shadow-card:0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);--shadow-raised:0 4px 12px rgba(28,28,24,.08),0 2px 4px rgba(28,28,24,.04);--shadow-overlay:0 8px 32px rgba(28,28,24,.12),0 2px 8px rgba(28,28,24,.06);}
|
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
|
|
body{font-family:var(--font-sans);background:#E8E7E2;color:var(--color-text);font-size:14px;line-height:1.6;}
|
|
.doc{max-width:1200px;margin:0 auto;padding:48px 40px 120px;}
|
|
.doc-header{display:flex;justify-content:space-between;align-items:flex-end;padding-bottom:28px;border-bottom:1px solid var(--color-border);margin-bottom:48px;background:var(--color-page);margin:-48px -40px 48px;padding:48px 40px 28px;border-radius:var(--radius-xl) var(--radius-xl) 0 0;}
|
|
.doc-header h1{font-family:var(--font-display);font-size:28px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
|
|
.doc-header p{font-size:13px;color:var(--color-text-muted);max-width:680px;}
|
|
.doc-meta{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);text-align:right;line-height:1.9;}
|
|
.pill{display:inline-block;padding:2px 8px;border-radius:var(--radius-sm);font-size:10px;font-weight:500;letter-spacing:.05em;}
|
|
.pill-b{background:var(--blue-tint);color:var(--blue-dark);}
|
|
.pill-g{background:var(--green-tint);color:var(--green-dark);}
|
|
.section{margin-bottom:64px;}
|
|
.section-title{font-size:10px;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-muted);padding-bottom:10px;border-bottom:1px solid var(--color-border);margin-bottom:24px;}
|
|
.prose{font-size:13px;color:var(--color-text-muted);line-height:1.65;max-width:720px;margin-bottom:20px;}
|
|
.jh{padding:20px 24px;border-radius:var(--radius-xl);margin-bottom:40px;display:flex;align-items:center;gap:16px;}
|
|
.jh .jn{font-family:var(--font-display);font-size:48px;font-weight:300;line-height:1;opacity:.5;}
|
|
.jh h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:4px;}
|
|
.jh p{font-size:13px;line-height:1.5;}.jh .fl{font-family:var(--font-mono);font-size:11px;margin-top:6px;opacity:.7;}
|
|
.jh-b{background:var(--blue-tint);border:1px solid #A4CFF4;}.jh-b .jn{color:var(--blue);}.jh-b p,.jh-b .fl{color:var(--blue-dark);}
|
|
.scr{margin-bottom:56px;}
|
|
.scr-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
|
|
.scr-head h3{font-family:var(--font-display);font-size:20px;font-weight:500;letter-spacing:-.02em;}
|
|
.scr-id{font-family:var(--font-mono);font-size:11px;color:var(--color-text-muted);padding:2px 8px;border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-page);}
|
|
.scr-desc{font-size:12px;color:var(--color-text-muted);line-height:1.6;max-width:720px;margin-bottom:6px;}
|
|
.scr-var{font-size:11px;color:var(--color-text-muted);margin-bottom:20px;}.scr-var strong{color:var(--color-text);}
|
|
.previews{display:flex;gap:32px;flex-wrap:wrap;justify-content:center;align-items:flex-start;margin-bottom:20px;}
|
|
.prev-col{display:flex;flex-direction:column;align-items:center;gap:10px;}
|
|
.bp-lbl{font-family:var(--font-mono);font-size:10px;color:var(--color-text-muted);}
|
|
.desk{width:100%;max-width:1040px;background:var(--color-page);border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.06);display:flex;flex-direction:column;min-height:520px;}
|
|
.phone{width:320px;flex-shrink:0;background:var(--color-page);border-radius:36px;overflow:hidden;box-shadow:var(--shadow-overlay),0 0 0 1px rgba(0,0,0,.07);display:flex;flex-direction:column;border:6px solid #1C1C18;}
|
|
.pst{padding:10px 20px 0;display:flex;justify-content:space-between;align-items:center;font-size:12px;background:var(--color-page);}.pst b{font-weight:600;}.pst span{font-size:10px;}
|
|
.pb{flex:1;overflow-y:auto;display:flex;flex-direction:column;}
|
|
.fa-nav{height:32px;background:var(--navy);display:flex;align-items:center;padding:0 12px;gap:8px;flex-shrink:0;}
|
|
.fa-logo{font-size:7px;font-weight:900;color:#fff;letter-spacing:.8px;border-bottom:2px solid var(--mint);padding-bottom:1px;}
|
|
.fa-link{font-size:5.5px;color:rgba(255,255,255,.4);font-weight:700;text-transform:uppercase;letter-spacing:.05em;}
|
|
.fa-link.active{color:var(--mint);border-bottom:1px solid var(--mint);}
|
|
.fa-nav-r{margin-left:auto;display:flex;gap:5px;align-items:center;}
|
|
.fa-av{width:16px;height:16px;background:rgba(255,255,255,.1);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:5px;font-weight:800;color:rgba(255,255,255,.5);}
|
|
.page-body{padding:16px;background:#E8E7E2;flex:1;}
|
|
|
|
/* ── impl-ref (agent) table ── */
|
|
.agent{background:var(--color-text);color:#E8E8E2;padding:24px;border-radius:var(--radius-lg);margin-top:20px;}
|
|
.agent h4{font-size:9px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:#5A5A55;margin-bottom:12px;}
|
|
.agent pre{font-family:var(--font-mono);font-size:10px;color:#444440;margin-bottom:16px;line-height:1.8;white-space:pre-wrap;}
|
|
.at{width:100%;border-collapse:collapse;font-family:var(--font-mono);font-size:10px;}
|
|
.at thead tr{border-bottom:1px solid #2A2A26;}
|
|
.at th{text-align:left;padding:6px 10px;font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#5A5A55;font-family:var(--font-sans);}
|
|
.at td{padding:5px 10px;border-bottom:1px solid #1E1E1A;vertical-align:top;line-height:1.5;}
|
|
.at tr:last-child td{border-bottom:none;}
|
|
.at td:first-child{color:#7A7A72;}
|
|
.at td:nth-child(2){color:#E8E8E2;font-weight:500;}
|
|
.at td:nth-child(3){color:#5A5A55;}
|
|
.at .grp td{padding-top:14px;font-family:var(--font-sans);font-size:8px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#3A3A36;}
|
|
|
|
/* ── LLM guide ── */
|
|
.llm{background:var(--color-page);border:2px solid var(--navy);border-radius:var(--radius-xl);padding:32px 40px;margin-top:64px;}
|
|
.llm h2{font-family:var(--font-display);font-size:22px;font-weight:500;letter-spacing:-.02em;margin-bottom:8px;color:var(--navy);}
|
|
.llm h3{font-size:14px;font-weight:600;margin:20px 0 8px;color:var(--color-text);}
|
|
.llm h4{font-size:12px;font-weight:600;margin:14px 0 6px;color:var(--color-text-muted);}
|
|
.llm p,.llm li{font-size:13px;color:var(--color-text-muted);line-height:1.65;}
|
|
.llm ul,.llm ol{padding-left:20px;margin-bottom:12px;}
|
|
.llm li{margin-bottom:4px;}
|
|
.llm code{font-family:var(--font-mono);font-size:11px;background:var(--color-surface);padding:1px 5px;border-radius:3px;}
|
|
.llm table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px;}
|
|
.llm th,.llm td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--color-border);}
|
|
.llm th{font-weight:500;color:var(--color-text);font-size:11px;text-transform:uppercase;letter-spacing:.05em;}
|
|
.llm td{color:var(--color-text-muted);}
|
|
|
|
/* ── Mockup-specific styles ── */
|
|
|
|
/* Editorial list */
|
|
.g-list-card{background:#fff;border:1px solid #E4E2D7;border-radius:4px;box-shadow:0 1px 3px rgba(28,28,24,.06),0 1px 2px rgba(28,28,24,.04);overflow:hidden;}
|
|
.g-row{display:flex;gap:0;border-bottom:1px solid #F0EFE9;cursor:pointer;}
|
|
.g-row:last-child{border-bottom:none;}
|
|
.g-row:hover{background:#FAFAF7;}
|
|
.g-meta{width:88px;flex-shrink:0;padding:10px 10px 10px 12px;display:flex;flex-direction:column;gap:3px;border-right:1px solid #F0EFE9;}
|
|
.g-content{padding:10px 14px 10px 12px;flex:1;min-width:0;}
|
|
.g-av{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:7px;font-weight:800;color:#fff;flex-shrink:0;margin-bottom:3px;}
|
|
.av-navy{background:#012851;}
|
|
.av-purple{background:#534AB7;}
|
|
.av-blue{background:#2D7DD2;}
|
|
.av-teal{background:#0E9488;}
|
|
.g-author{font-size:7px;font-weight:700;color:#1C1C18;line-height:1.3;}
|
|
.g-date{font-size:6.5px;color:#6B6A63;line-height:1.3;}
|
|
.g-chip{display:inline-flex;align-items:center;gap:2px;padding:1px 5px;background:#F5F4EE;border:1px solid #D8D7D0;border-radius:10px;font-size:6px;font-weight:500;color:#1C1C18;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:76px;}
|
|
.g-title{font-family:Georgia,serif;font-size:11px;color:#012851;line-height:1.4;margin-bottom:2px;}
|
|
.g-title:hover{color:#185FA5;}
|
|
.g-excerpt{font-size:7.5px;color:#6B6A63;line-height:1.55;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
|
|
|
|
/* Filter pills */
|
|
.g-filters{display:flex;gap:5px;align-items:center;padding:8px 12px;background:var(--color-page);border-bottom:1px solid #EDECEA;flex-wrap:wrap;}
|
|
.g-pill{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:6.5px;font-weight:700;border:1px solid #D8D7D0;color:#6B6A63;background:transparent;cursor:pointer;}
|
|
.g-pill.active{background:#012851;color:#fff;border-color:#012851;}
|
|
.g-pill.add{border-style:dashed;color:#6B6A63;}
|
|
|
|
/* Page header (desktop) */
|
|
.g-page-hdr{display:flex;justify-content:space-between;align-items:center;padding:10px 14px 6px;}
|
|
.g-page-title{font-family:Georgia,serif;font-size:16px;font-weight:400;color:#012851;}
|
|
.g-new-btn{font-size:7px;font-weight:700;padding:4px 10px;border-radius:3px;background:#012851;color:#fff;border:none;display:flex;align-items:center;gap:3px;}
|
|
|
|
/* Empty state */
|
|
.g-empty{padding:20px;text-align:center;font-family:Georgia,serif;font-size:9px;color:#6B6A63;font-style:italic;}
|
|
|
|
/* ── Story Detail mockup ── */
|
|
.g-detail-body{padding:16px 20px;background:#E8E7E2;flex:1;}
|
|
.g-article{background:var(--color-page);border-radius:6px;padding:16px 20px;max-width:640px;margin:0 auto;}
|
|
.g-back{font-size:7px;color:#6B6A63;margin-bottom:10px;display:flex;align-items:center;gap:2px;}
|
|
.g-story-title{font-family:Georgia,serif;font-size:18px;font-weight:400;color:#012851;line-height:1.3;margin-bottom:8px;}
|
|
.g-metabar{display:flex;align-items:center;gap:6px;padding-bottom:8px;border-bottom:1px solid #EDECEA;margin-bottom:10px;}
|
|
.g-metabar-r{margin-left:auto;display:flex;align-items:center;gap:6px;}
|
|
.g-edit-btn{font-size:6.5px;font-weight:600;padding:2px 7px;border:1px solid #D8D7D0;border-radius:3px;color:#1C1C18;background:transparent;}
|
|
.g-del-link{font-size:6.5px;font-weight:600;color:#DC4C3E;}
|
|
.g-body-text{font-family:Georgia,serif;font-size:9px;line-height:1.75;color:#1C1C18;margin-bottom:12px;}
|
|
.g-body-text p{margin-bottom:7px;}
|
|
.g-sub-hdr{font-size:7px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#6B6A63;margin-bottom:6px;}
|
|
.g-persons-row{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px;}
|
|
.g-person-chip{display:inline-flex;align-items:center;gap:4px;padding:3px 8px 3px 4px;border:1px solid #D8D7D0;border-radius:12px;background:#F5F4EE;font-size:7.5px;font-weight:500;color:#1C1C18;}
|
|
.g-person-chip .av{width:14px;height:14px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:5.5px;font-weight:800;color:#fff;flex-shrink:0;}
|
|
.g-doc-cards{display:flex;flex-direction:column;gap:5px;}
|
|
.g-doc-card{display:flex;align-items:flex-start;gap:7px;padding:7px 9px;background:#fff;border:1px solid #E4E2D7;border-radius:4px;}
|
|
.g-doc-icon{width:22px;height:22px;background:#F0EFE9;border-radius:3px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
|
|
.g-doc-info{min-width:0;flex:1;}
|
|
.g-doc-title{font-size:8px;font-weight:600;color:#012851;line-height:1.3;margin-bottom:1px;}
|
|
.g-doc-meta{font-size:6.5px;color:#6B6A63;}
|
|
|
|
/* Mobile nav */
|
|
.m-nav{height:26px;background:var(--navy);display:flex;align-items:center;padding:0 10px;gap:6px;flex-shrink:0;}
|
|
.m-logo{font-size:6px;font-weight:900;color:#fff;letter-spacing:.7px;border-bottom:1.5px solid var(--mint);padding-bottom:1px;}
|
|
.m-nav-r{margin-left:auto;display:flex;gap:4px;align-items:center;}
|
|
.m-av{width:14px;height:14px;background:rgba(255,255,255,.1);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:rgba(255,255,255,.5);}
|
|
.m-ham{display:flex;flex-direction:column;gap:2px;width:12px;}
|
|
.m-ham span{height:1.5px;background:rgba(255,255,255,.6);border-radius:1px;}
|
|
|
|
/* Mobile filter strip */
|
|
.m-filters{display:flex;gap:4px;align-items:center;padding:6px 10px;background:var(--color-page);border-bottom:1px solid #EDECEA;overflow-x:auto;flex-wrap:nowrap;}
|
|
.m-filters::-webkit-scrollbar{display:none;}
|
|
|
|
/* Mobile row */
|
|
.m-row{padding:9px 10px;border-bottom:1px solid #F0EFE9;background:#fff;cursor:pointer;}
|
|
.m-row:hover{background:#FAFAF7;}
|
|
.m-row-top{display:flex;align-items:center;gap:5px;margin-bottom:4px;}
|
|
.m-author-name{font-size:7px;font-weight:700;color:#1C1C18;}
|
|
.m-date{font-size:6.5px;color:#6B6A63;margin-left:auto;}
|
|
.m-title{font-family:Georgia,serif;font-size:10px;color:#012851;line-height:1.4;margin-bottom:2px;}
|
|
.m-excerpt{font-size:7px;color:#6B6A63;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
|
|
|
|
/* Mobile detail */
|
|
.m-detail-body{padding:10px;background:#E8E7E2;flex:1;}
|
|
.m-article{background:#fff;border-radius:6px;padding:12px 12px 16px;}
|
|
.m-back{font-size:7px;color:#6B6A63;margin-bottom:8px;display:flex;align-items:center;gap:2px;}
|
|
.m-story-title{font-family:Georgia,serif;font-size:14px;font-weight:400;color:#012851;line-height:1.3;margin-bottom:6px;}
|
|
.m-metabar{display:flex;align-items:center;gap:5px;padding-bottom:6px;border-bottom:1px solid #EDECEA;margin-bottom:8px;}
|
|
.m-body-text{font-family:Georgia,serif;font-size:8.5px;line-height:1.7;color:#1C1C18;margin-bottom:10px;}
|
|
.m-body-text p{margin-bottom:5px;}
|
|
.m-sub-hdr{font-size:6.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#6B6A63;margin-bottom:5px;}
|
|
.m-persons-row{display:flex;flex-wrap:wrap;gap:3px;margin-bottom:10px;}
|
|
.m-person-chip{display:inline-flex;align-items:center;gap:3px;padding:2px 6px 2px 3px;border:1px solid #D8D7D0;border-radius:10px;background:#F5F4EE;font-size:7px;font-weight:500;color:#1C1C18;}
|
|
.m-doc-card{display:flex;align-items:flex-start;gap:5px;padding:6px 7px;background:#F5F4EE;border:1px solid #E4E2D7;border-radius:4px;margin-bottom:4px;}
|
|
.m-doc-icon{width:18px;height:18px;background:#E4E2D7;border-radius:3px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
|
|
.m-doc-title{font-size:7.5px;font-weight:600;color:#012851;margin-bottom:1px;}
|
|
.m-doc-meta{font-size:6px;color:#6B6A63;}
|
|
.m-three-dot{font-size:11px;color:#6B6A63;line-height:1;}
|
|
|
|
@media(max-width:900px){.doc{padding:24px 16px 80px;}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="doc">
|
|
|
|
<!-- ═══ DOC HEADER ═══ -->
|
|
<div class="doc-header">
|
|
<div>
|
|
<h1>Geschichten — Reader Journey</h1>
|
|
<p>Übersichtsseite <code>/geschichten</code> und Story-Detailansicht <code>/geschichten/[id]</code>. Leserinnen entdecken veröffentlichte Familiengeschichten, filtern nach Personen und lesen die vollständige Geschichte mit verlinkten Dokumenten und Personen.</p>
|
|
</div>
|
|
<div class="doc-meta">
|
|
Familienarchiv<br/>
|
|
<span class="pill pill-b">Final Spec</span><br/>
|
|
2026-05-02 · @leonievoss
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══ JOURNEY HEADER ═══ -->
|
|
<div class="jh jh-b">
|
|
<div class="jn">R</div>
|
|
<div>
|
|
<h2>Reader Journey</h2>
|
|
<p>Alle eingeloggten Familienmitglieder können veröffentlichte Geschichten lesen und nach historischen Personen filtern.</p>
|
|
<div class="fl">/geschichten · /geschichten/[id]</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ═══ SECTION 1: KONZEPT ═══ -->
|
|
<div class="section">
|
|
<div class="section-title">Konzept</div>
|
|
<p class="prose">Die Reader Journey umfasst zwei Seiten: die editoriale Übersichtsseite <code>/geschichten</code> und die Story-Detailansicht <code>/geschichten/[id]</code>. Beide Seiten sind für alle angemeldeten Familienmitglieder zugänglich, unabhängig von Schreibrechten.</p>
|
|
<p class="prose">Die Übersichtsseite zeigt alle veröffentlichten Geschichten als editoriale Liste mit vollbreiten Zeilen. Links steht die Metaspalte (Autorin, Datum, verknüpfte Person), rechts Titel und Vorschautext. Eine Personenfilter-Pill-Leiste oberhalb der Liste schränkt die Anzeige auf Geschichten ein, die eine bestimmte historische Person erwähnen.</p>
|
|
<p class="prose">Die Detailansicht zeigt die vollständige Geschichte als zentrierten Artikeltext (max-w-3xl) mit Autorinnenzeile, Fließtext (HTML aus dem Backend), einem Abschnitt mit verlinkten Personenchips und Dokumentreferenzkarten, die direkt zu den Originalbriefen und Dokumenten verlinken. Autorinnen mit dem Recht <code>BLOG_WRITE</code> sehen zusätzlich Bearbeiten- und Löschen-Aktionen.</p>
|
|
</div>
|
|
|
|
<!-- ═══ SCREEN R-1: INDEX ═══ -->
|
|
<div class="section">
|
|
<div class="section-title">Screens — Übersichtsseite</div>
|
|
|
|
<div class="scr">
|
|
<div class="scr-head">
|
|
<h3>R-1 — Übersicht /geschichten</h3>
|
|
<span class="scr-id">US-BLOG-004 · R-1</span>
|
|
</div>
|
|
<p class="scr-desc">Editoriale Listendarstellung aller veröffentlichten Geschichten. Jede Zeile: linke Metaspalte (Avatar, Autorin, Datum, Personenchip), rechte Inhaltsspalte (Serientitel, Vorschautext). Personenfilter-Pills oberhalb der Liste. Schaltfläche „+ Neue Geschichte" rechts oben nur für BLOG_WRITERs sichtbar.</p>
|
|
<p class="scr-var"><strong>Varianten:</strong> Kein Filter aktiv (alle Geschichten) · Person-Filter aktiv (gefilterte Liste) · Leerer Zustand (Filter aktiv, keine Ergebnisse)</p>
|
|
|
|
<div class="previews">
|
|
<!-- DESKTOP -->
|
|
<div class="prev-col" style="width:100%;max-width:1040px;">
|
|
<span class="bp-lbl">Desktop — 1040px</span>
|
|
<div class="desk">
|
|
<!-- Nav -->
|
|
<div class="fa-nav">
|
|
<span class="fa-logo">ARCHIV</span>
|
|
<span style="width:1px;height:14px;background:rgba(255,255,255,.1);margin:0 2px;"></span>
|
|
<span class="fa-link">Dokumente</span>
|
|
<span class="fa-link">Personen</span>
|
|
<span class="fa-link active">Geschichten</span>
|
|
<span class="fa-link">Chronik</span>
|
|
<div class="fa-nav-r">
|
|
<div class="fa-av" style="background:#012851;color:var(--mint);font-size:5px;font-weight:800;">MR</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Page body -->
|
|
<div style="background:#E8E7E2;flex:1;padding:14px 16px;">
|
|
|
|
<!-- Page header -->
|
|
<div class="g-page-hdr" style="padding:0 0 8px;">
|
|
<span class="g-page-title">Geschichten</span>
|
|
<button class="g-new-btn">
|
|
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M5 1v8M1 5h8" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
|
|
Neue Geschichte
|
|
</button>
|
|
</div>
|
|
|
|
<!-- List card -->
|
|
<div class="g-list-card">
|
|
|
|
<!-- Filter pills -->
|
|
<div class="g-filters">
|
|
<span class="g-pill active">Alle</span>
|
|
<span class="g-pill">Franz Raddatz</span>
|
|
<span class="g-pill">Emma Müller</span>
|
|
<span class="g-pill">Heinrich Kohl</span>
|
|
<span class="g-pill add">+ Person wählen</span>
|
|
</div>
|
|
|
|
<!-- Row 1 -->
|
|
<div class="g-row">
|
|
<div class="g-meta">
|
|
<div class="g-av av-navy">MR</div>
|
|
<div class="g-author">Maria Raddatz</div>
|
|
<div class="g-date">14. März 2025</div>
|
|
<span class="g-chip">
|
|
<span style="width:8px;height:8px;border-radius:50%;background:#012851;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:var(--mint);flex-shrink:0;">FR</span>
|
|
Franz Raddatz
|
|
</span>
|
|
</div>
|
|
<div class="g-content">
|
|
<div class="g-title">Der Sommer in Breslau</div>
|
|
<div class="g-excerpt">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. Es waren die letzten unbeschwerten Monate auf dem Gut…</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row 2 -->
|
|
<div class="g-row">
|
|
<div class="g-meta">
|
|
<div class="g-av av-purple">KR</div>
|
|
<div class="g-author">Klaus Raddatz</div>
|
|
<div class="g-date">2. Jan. 2025</div>
|
|
<span class="g-chip">
|
|
<span style="width:8px;height:8px;border-radius:50%;background:#012851;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:var(--mint);flex-shrink:0;">FR</span>
|
|
Franz Raddatz
|
|
</span>
|
|
</div>
|
|
<div class="g-content">
|
|
<div class="g-title">Wie Opa Franz den Hof rettete</div>
|
|
<div class="g-excerpt">Es war ein kalter November, als der Notar anklopfte. Opa hatte nur wenige Stunden Zeit, alle Unterlagen zusammenzusuchen. Die Briefe aus dieser Zeit zeugen von einem Mann, der unter enormem Druck standhaft blieb.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row 3 -->
|
|
<div class="g-row">
|
|
<div class="g-meta">
|
|
<div class="g-av av-blue">GK</div>
|
|
<div class="g-author">Gertrud Koch</div>
|
|
<div class="g-date">18. Okt. 2024</div>
|
|
<span class="g-chip">
|
|
<span style="width:8px;height:8px;border-radius:50%;background:#534AB7;display:inline-flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;color:#fff;flex-shrink:0;">EM</span>
|
|
Emma Müller
|
|
</span>
|
|
</div>
|
|
<div class="g-content">
|
|
<div class="g-title">Die Hochzeit im Krieg</div>
|
|
<div class="g-excerpt">1943, mitten im Chaos — Emma bestand darauf, dass das Fest stattfand. Sie hatte das Brautkleid seit Jahren aufgehoben. Ihr Bruder kam auf Fronturlaub, drei Tage nur, aber es reichte für die Feier.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Row 4 -->
|
|
<div class="g-row">
|
|
<div class="g-meta">
|
|
<div class="g-av av-teal">HR</div>
|
|
<div class="g-author">Hans Raddatz</div>
|
|
<div class="g-date">5. Sept. 2024</div>
|
|
</div>
|
|
<div class="g-content">
|
|
<div class="g-title">Erinnerungen an Weihnachten 1935</div>
|
|
<div class="g-excerpt">Der Geruch von Tannenzweigen und Kerzenwachs — so beschrieb Opa immer den Heiligabend auf dem Gut. Die Kinder durften erst nach dem Abendessen ins Zimmer, und das Warten war jedes Jahr das Schwerste.</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /list-card -->
|
|
</div><!-- /page-body -->
|
|
</div><!-- /desk -->
|
|
</div>
|
|
|
|
<!-- MOBILE -->
|
|
<div class="prev-col">
|
|
<span class="bp-lbl">Mobile — 320px</span>
|
|
<div class="phone">
|
|
<div class="pst"><b>9:41</b><span>●●●</span></div>
|
|
<div class="pb">
|
|
<div class="m-nav">
|
|
<span class="m-logo">ARCHIV</span>
|
|
<div class="m-nav-r">
|
|
<div class="m-av">MR</div>
|
|
<div class="m-ham"><span></span><span></span><span></span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="background:#E8E7E2;flex:1;display:flex;flex-direction:column;">
|
|
<!-- page title mobile -->
|
|
<div style="padding:8px 10px 4px;background:#E8E7E2;">
|
|
<span style="font-family:Georgia,serif;font-size:13px;color:#012851;font-weight:400;">Geschichten</span>
|
|
</div>
|
|
|
|
<!-- Filter strip -->
|
|
<div class="m-filters">
|
|
<span class="g-pill active" style="font-size:6px;padding:2px 7px;">Alle</span>
|
|
<span class="g-pill" style="font-size:6px;padding:2px 7px;">Franz Raddatz</span>
|
|
<span class="g-pill" style="font-size:6px;padding:2px 7px;">Emma Müller</span>
|
|
<span class="g-pill add" style="font-size:6px;padding:2px 7px;flex-shrink:0;">+ Person…</span>
|
|
</div>
|
|
|
|
<!-- List -->
|
|
<div style="background:#fff;flex:1;">
|
|
<!-- Mobile row 1 -->
|
|
<div class="m-row">
|
|
<div class="m-row-top">
|
|
<div class="g-av av-navy" style="width:16px;height:16px;font-size:5.5px;">MR</div>
|
|
<span class="m-author-name">Maria Raddatz</span>
|
|
<span class="m-date">14. Mrz. 2025</span>
|
|
</div>
|
|
<div class="m-title">Der Sommer in Breslau</div>
|
|
<div class="m-excerpt">Oma erzählte oft vom letzten Sommer vor dem Krieg, als die Familie noch vollständig zusammen war…</div>
|
|
</div>
|
|
|
|
<!-- Mobile row 2 -->
|
|
<div class="m-row">
|
|
<div class="m-row-top">
|
|
<div class="g-av av-purple" style="width:16px;height:16px;font-size:5.5px;">KR</div>
|
|
<span class="m-author-name">Klaus Raddatz</span>
|
|
<span class="m-date">2. Jan. 2025</span>
|
|
</div>
|
|
<div class="m-title">Wie Opa Franz den Hof rettete</div>
|
|
<div class="m-excerpt">Es war ein kalter November, als der Notar anklopfte. Opa hatte nur wenige Stunden Zeit, alle Unterlagen zusammenzusuchen…</div>
|
|
</div>
|
|
|
|
<!-- Mobile row 3 -->
|
|
<div class="m-row">
|
|
<div class="m-row-top">
|
|
<div class="g-av av-blue" style="width:16px;height:16px;font-size:5.5px;">GK</div>
|
|
<span class="m-author-name">Gertrud Koch</span>
|
|
<span class="m-date">18. Okt. 2024</span>
|
|
</div>
|
|
<div class="m-title">Die Hochzeit im Krieg</div>
|
|
<div class="m-excerpt">1943, mitten im Chaos — Emma bestand darauf, dass das Fest stattfand. Sie hatte das Brautkleid seit Jahren aufgehoben…</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- EMPTY STATE inset -->
|
|
<div class="prev-col" style="width:100%;max-width:400px;">
|
|
<span class="bp-lbl">Leerer Zustand — Filter aktiv, keine Ergebnisse</span>
|
|
<div style="background:#fff;border:1px solid #E4E2D7;border-radius:6px;overflow:hidden;box-shadow:var(--shadow-card);">
|
|
<div class="g-filters">
|
|
<span class="g-pill">Alle</span>
|
|
<span class="g-pill active">Franz Raddatz</span>
|
|
<span class="g-pill">Emma Müller</span>
|
|
</div>
|
|
<div class="g-empty">Keine Geschichten für Franz Raddatz gefunden.</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /previews -->
|
|
|
|
<!-- impl-ref R-1 -->
|
|
<div class="agent">
|
|
<h4>impl-ref — R-1 Übersicht /geschichten</h4>
|
|
<table class="at">
|
|
<thead><tr><th>Element</th><th>Wert</th><th>Hinweise</th></tr></thead>
|
|
<tbody>
|
|
<tr class="grp"><td colspan="3">Seitenstruktur</td></tr>
|
|
<tr><td>Page title</td><td>font-family:var(--font-display);font-size:24px;color:var(--navy)</td><td>Fraunces, nicht fett</td></tr>
|
|
<tr><td>Editorial list card</td><td>bg-white shadow-sm border border-brand-sand rounded-sm</td><td>wraps alle Zeilen</td></tr>
|
|
<tr class="grp"><td colspan="3">Listenzeile</td></tr>
|
|
<tr><td>List row</td><td>flex gap-0 border-b border-brand-sand last:border-0 hover:bg-surface</td><td>min-h-[44px] auf Mobile</td></tr>
|
|
<tr><td>Meta column</td><td>w-[88px] shrink-0 flex flex-col gap-1 p-3 border-r border-brand-sand</td><td>feste Breite</td></tr>
|
|
<tr><td>Author avatar</td><td>w-7 h-7 rounded-full text-[9px] font-bold text-white flex items-center justify-center</td><td>personAvatarColor(userId)</td></tr>
|
|
<tr><td>Author name</td><td>font-sans text-xs font-semibold text-ink</td><td></td></tr>
|
|
<tr><td>Date</td><td>font-sans text-xs text-ink-3</td><td>formatDate(publishedAt)</td></tr>
|
|
<tr><td>Person chip</td><td>inline-flex items-center gap-1 rounded-full bg-surface border border-line px-2 py-0.5 text-[10px] font-medium text-ink</td><td>links zu /persons/[id]; optional</td></tr>
|
|
<tr><td>Story title</td><td>font-serif text-[15px] text-ink leading-snug mb-1 hover:text-primary</td><td>link zu /geschichten/[id]</td></tr>
|
|
<tr><td>Excerpt</td><td>font-sans text-xs text-ink-3 line-clamp-2</td><td>max. 150 Zeichen aus body</td></tr>
|
|
<tr class="grp"><td colspan="3">Filter</td></tr>
|
|
<tr><td>Filter pill (inaktiv)</td><td>rounded-full border border-line px-3 py-1 text-xs font-semibold text-ink-2 hover:bg-muted</td><td>aria-pressed="false"</td></tr>
|
|
<tr><td>Filter pill (aktiv)</td><td>rounded-full bg-primary text-primary-fg px-3 py-1 text-xs font-semibold</td><td>aria-pressed="true"</td></tr>
|
|
<tr><td>Person wählen</td><td>border-dashed text-ink-3</td><td>öffnet Personen-Typeahead</td></tr>
|
|
<tr class="grp"><td colspan="3">Aktionen & Barrierefreiheit</td></tr>
|
|
<tr><td>Neue Geschichte btn</td><td>rounded border border-primary bg-primary text-primary-fg px-3 py-1.5 text-sm font-medium</td><td>nur BLOG_WRITE; auf Mobile ausgeblendet → Hamburger-Menü</td></tr>
|
|
<tr><td>Touch target (Mobile)</td><td>min-h-[44px] auf jeder Zeile</td><td>WCAG 2.2 AA</td></tr>
|
|
<tr><td>Leerer Zustand</td><td>py-12 text-center font-serif text-sm text-ink-3 italic</td><td>Zeigt Filtername im Text</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div><!-- /scr R-1 -->
|
|
</div><!-- /section -->
|
|
|
|
<!-- ═══ SCREEN R-2: STORY DETAIL ═══ -->
|
|
<div class="section">
|
|
<div class="section-title">Screens — Story-Detailansicht</div>
|
|
|
|
<div class="scr">
|
|
<div class="scr-head">
|
|
<h3>R-2 — Story-Detail /geschichten/[id]</h3>
|
|
<span class="scr-id">US-BLOG-004 · R-2</span>
|
|
</div>
|
|
<p class="scr-desc">Vollständige Leseansicht einer Geschichte. Zentrierter Artikel-Container (max-w-3xl). Zurück-Schaltfläche, großer Serientitel, Metazeile mit Avatar und Datum. Fließtext aus dem Backend (HTML). Personenchips-Sektion. Dokumentreferenzkarten. Autorinnen mit BLOG_WRITE sehen Bearbeiten/Löschen-Aktionen.</p>
|
|
<p class="scr-var"><strong>Varianten:</strong> Leserin ohne BLOG_WRITE (keine Aktionen) · BLOG_WRITER (Bearbeiten + Löschen sichtbar) · Mobile (Aktionen im … Menü)</p>
|
|
|
|
<div class="previews">
|
|
<!-- DESKTOP DETAIL -->
|
|
<div class="prev-col" style="width:100%;max-width:1040px;">
|
|
<span class="bp-lbl">Desktop — 1040px · BLOG_WRITER-Ansicht</span>
|
|
<div class="desk" style="min-height:600px;">
|
|
<!-- Nav -->
|
|
<div class="fa-nav">
|
|
<span class="fa-logo">ARCHIV</span>
|
|
<span style="width:1px;height:14px;background:rgba(255,255,255,.1);margin:0 2px;"></span>
|
|
<span class="fa-link">Dokumente</span>
|
|
<span class="fa-link">Personen</span>
|
|
<span class="fa-link active">Geschichten</span>
|
|
<span class="fa-link">Chronik</span>
|
|
<div class="fa-nav-r">
|
|
<div class="fa-av" style="background:#012851;color:var(--mint);font-size:5px;font-weight:800;">MR</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Detail body -->
|
|
<div class="g-detail-body">
|
|
<div class="g-article">
|
|
|
|
<!-- Back -->
|
|
<div class="g-back">
|
|
<svg width="7" height="7" viewBox="0 0 10 10" fill="none"><path d="M6 2L2 5l4 3" stroke="#6B6A63" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
Zurück zu Geschichten
|
|
</div>
|
|
|
|
<!-- Title -->
|
|
<div class="g-story-title">Der Sommer in Breslau</div>
|
|
|
|
<!-- Meta bar -->
|
|
<div class="g-metabar">
|
|
<div class="g-av av-navy" style="width:20px;height:20px;font-size:6.5px;">MR</div>
|
|
<div>
|
|
<div style="font-size:7.5px;font-weight:700;color:#1C1C18;line-height:1.2;">Maria Raddatz</div>
|
|
<div style="font-size:6.5px;color:#6B6A63;">veröffentlicht am 14. März 2025</div>
|
|
</div>
|
|
<div class="g-metabar-r">
|
|
<button class="g-edit-btn">Bearbeiten</button>
|
|
<span class="g-del-link">Löschen</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Divider -->
|
|
<div style="height:1px;background:#EDECEA;margin-bottom:12px;"></div>
|
|
|
|
<!-- Body text -->
|
|
<div class="g-body-text">
|
|
<p>Oma erzählte oft vom letzten Sommer vor dem Krieg, als die Familie noch vollständig zusammen war. Es war 1938, und die Hitze in Breslau schien endloser als in all den Jahren davor. Die Kinder liefen barfuß über die Steinplatten des Innenhofs, und die Erwachsenen saßen bis spät in die Nacht auf der Veranda.</p>
|
|
<p>Es war 1938, und Franz hatte gerade seinen 40. Geburtstag gefeiert. Die Briefe aus dieser Zeit zeigen einen Mann voller Zuversicht — man kann kaum glauben, was nur wenige Jahre später folgen würde. Er schrieb an seinen Bruder Heinrich: „Der Sommer gehört uns, der Winter kommt früh genug."</p>
|
|
</div>
|
|
|
|
<!-- Persons section -->
|
|
<div class="g-sub-hdr">Personen in dieser Geschichte</div>
|
|
<div class="g-persons-row">
|
|
<div class="g-person-chip">
|
|
<div class="av" style="background:#012851;color:var(--mint);">FR</div>
|
|
Franz Raddatz
|
|
</div>
|
|
<div class="g-person-chip">
|
|
<div class="av" style="background:#534AB7;color:#fff;">EM</div>
|
|
Emma Müller
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Documents section -->
|
|
<div class="g-sub-hdr" style="margin-top:10px;">Erwähnte Dokumente</div>
|
|
<div class="g-doc-cards">
|
|
<div class="g-doc-card">
|
|
<div class="g-doc-icon">
|
|
<svg width="10" height="12" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#6B6A63" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#6B6A63" stroke-width=".8" stroke-linecap="round"/></svg>
|
|
</div>
|
|
<div class="g-doc-info">
|
|
<div class="g-doc-title">Brief vom 12. Juli 1938</div>
|
|
<div class="g-doc-meta">12. Juli 1938 · von Franz Raddatz</div>
|
|
</div>
|
|
</div>
|
|
<div class="g-doc-card">
|
|
<div class="g-doc-icon">
|
|
<svg width="10" height="12" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#6B6A63" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#6B6A63" stroke-width=".8" stroke-linecap="round"/></svg>
|
|
</div>
|
|
<div class="g-doc-info">
|
|
<div class="g-doc-title">Postkarte aus Breslau, August 1938</div>
|
|
<div class="g-doc-meta">22. Aug. 1938 · von Franz Raddatz an Emma Müller</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /article -->
|
|
</div><!-- /detail-body -->
|
|
</div><!-- /desk -->
|
|
</div>
|
|
|
|
<!-- MOBILE DETAIL -->
|
|
<div class="prev-col">
|
|
<span class="bp-lbl">Mobile — 320px · Leserin ohne Schreibrecht</span>
|
|
<div class="phone" style="min-height:560px;">
|
|
<div class="pst"><b>9:41</b><span>●●●</span></div>
|
|
<div class="pb">
|
|
<div class="m-nav">
|
|
<span class="m-logo">ARCHIV</span>
|
|
<div class="m-nav-r">
|
|
<div class="m-av">MR</div>
|
|
<div class="m-ham"><span></span><span></span><span></span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="m-detail-body">
|
|
<div class="m-article">
|
|
<div class="m-back">
|
|
<svg width="6" height="6" viewBox="0 0 10 10" fill="none"><path d="M6 2L2 5l4 3" stroke="#6B6A63" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
Zurück zu Geschichten
|
|
</div>
|
|
|
|
<div class="m-story-title">Der Sommer in Breslau</div>
|
|
|
|
<div class="m-metabar">
|
|
<div class="g-av av-navy" style="width:16px;height:16px;font-size:5.5px;flex-shrink:0;">MR</div>
|
|
<div>
|
|
<div style="font-size:7px;font-weight:700;color:#1C1C18;line-height:1.2;">Maria Raddatz</div>
|
|
<div style="font-size:6px;color:#6B6A63;">14. März 2025</div>
|
|
</div>
|
|
<div style="margin-left:auto;">
|
|
<div class="m-three-dot">···</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="height:1px;background:#EDECEA;margin-bottom:8px;"></div>
|
|
|
|
<div class="m-body-text">
|
|
<p>Oma erzählte oft vom letzten Sommer vor dem Krieg, als die Familie noch vollständig zusammen war. Es war 1938, und die Hitze in Breslau schien endloser als in all den Jahren davor.</p>
|
|
<p>Es war 1938, und Franz hatte gerade seinen 40. Geburtstag gefeiert. Die Briefe aus dieser Zeit zeigen einen Mann voller Zuversicht — man kann kaum glauben, was nur wenige Jahre später folgen würde.</p>
|
|
</div>
|
|
|
|
<div class="m-sub-hdr">Personen in dieser Geschichte</div>
|
|
<div class="m-persons-row">
|
|
<div class="m-person-chip">
|
|
<div class="av" style="background:#012851;color:var(--mint);width:12px;height:12px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;flex-shrink:0;">FR</div>
|
|
Franz Raddatz
|
|
</div>
|
|
<div class="m-person-chip">
|
|
<div class="av" style="background:#534AB7;color:#fff;width:12px;height:12px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:4.5px;font-weight:800;flex-shrink:0;">EM</div>
|
|
Emma Müller
|
|
</div>
|
|
</div>
|
|
|
|
<div class="m-sub-hdr" style="margin-top:8px;">Erwähnte Dokumente</div>
|
|
<div class="m-doc-card">
|
|
<div class="m-doc-icon">
|
|
<svg width="8" height="10" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#6B6A63" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#6B6A63" stroke-width=".8" stroke-linecap="round"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="m-doc-title">Brief vom 12. Juli 1938</div>
|
|
<div class="m-doc-meta">12. Juli 1938 · von Franz Raddatz</div>
|
|
</div>
|
|
</div>
|
|
<div class="m-doc-card">
|
|
<div class="m-doc-icon">
|
|
<svg width="8" height="10" viewBox="0 0 10 12" fill="none"><rect x="1" y="1" width="8" height="10" rx="1" stroke="#6B6A63" stroke-width="1"/><path d="M3 4h4M3 6.5h4M3 9h2" stroke="#6B6A63" stroke-width=".8" stroke-linecap="round"/></svg>
|
|
</div>
|
|
<div>
|
|
<div class="m-doc-title">Postkarte aus Breslau, Aug. 1938</div>
|
|
<div class="m-doc-meta">22. Aug. 1938 · Franz an Emma</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /previews -->
|
|
|
|
<!-- impl-ref R-2 -->
|
|
<div class="agent">
|
|
<h4>impl-ref — R-2 Story-Detail /geschichten/[id]</h4>
|
|
<table class="at">
|
|
<thead><tr><th>Element</th><th>Wert</th><th>Hinweise</th></tr></thead>
|
|
<tbody>
|
|
<tr class="grp"><td colspan="3">Artikel-Container</td></tr>
|
|
<tr><td>Article container</td><td>max-w-3xl mx-auto px-4 py-10</td><td>zentriert, volle Breite auf Mobile</td></tr>
|
|
<tr><td>Story title</td><td>font-family:var(--font-display);font-size:clamp(22px,4vw,32px);color:var(--navy)</td><td>Fraunces, nicht fett</td></tr>
|
|
<tr><td>Back button</td><td><BackButton /> aus $lib/components/BackButton.svelte</td><td>history.back(); nicht <a href></td></tr>
|
|
<tr class="grp"><td colspan="3">Metazeile</td></tr>
|
|
<tr><td>Meta bar</td><td>flex items-center gap-3 mt-4 mb-6</td><td></td></tr>
|
|
<tr><td>Author avatar</td><td>w-8 h-8 rounded-full text-xs font-bold text-white flex items-center justify-center</td><td>personAvatarColor(author.id)</td></tr>
|
|
<tr><td>Published date</td><td>font-sans text-xs text-ink-3</td><td>„veröffentlicht am " + formatDate()</td></tr>
|
|
<tr><td>Bearbeiten btn</td><td>rounded border border-line px-3 py-1.5 text-sm font-medium text-ink hover:bg-muted</td><td>nur BLOG_WRITE; auf Mobile im … Menü</td></tr>
|
|
<tr><td>Löschen link</td><td>text-sm text-red-600 font-medium hover:underline</td><td>nur BLOG_WRITE; Confirm-Dialog davor</td></tr>
|
|
<tr class="grp"><td colspan="3">Fließtext</td></tr>
|
|
<tr><td>Body text</td><td>font-serif text-base leading-relaxed text-ink prose</td><td>rendered HTML aus Backend; kein XSS (DOMPurify)</td></tr>
|
|
<tr class="grp"><td colspan="3">Personen & Dokumente</td></tr>
|
|
<tr><td>Person chips section</td><td>flex flex-wrap gap-2 mt-8</td><td>Abschnittsüberschrift xs uppercase muted</td></tr>
|
|
<tr><td>Person chip</td><td>inline-flex items-center gap-2 rounded-full border border-line bg-surface px-3 py-1.5 text-sm font-medium</td><td>links zu /persons/[id]</td></tr>
|
|
<tr><td>Doc reference card</td><td>flex gap-3 items-start bg-white border border-brand-sand rounded-sm p-3 hover:shadow-sm</td><td>links zu /documents/[id]</td></tr>
|
|
<tr><td>Doc icon</td><td>w-9 h-9 bg-surface rounded flex items-center justify-center shrink-0</td><td>Dateisymbol SVG</td></tr>
|
|
<tr class="grp"><td colspan="3">Mobile</td></tr>
|
|
<tr><td>… Menü (Mobile)</td><td>ml-auto text-ink-3; öffnet BottomSheet mit Bearbeiten + Löschen</td><td>BLOG_WRITE-Aktionen auf Mobile</td></tr>
|
|
<tr><td>Person chips (Mobile)</td><td>flex-wrap, volle Breite</td><td>kein horizontales Scrollen</td></tr>
|
|
<tr><td>Doc cards (Mobile)</td><td>flex-col gap-2</td><td>stapeln vertikal</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div><!-- /scr R-2 -->
|
|
</div><!-- /section -->
|
|
|
|
<!-- ═══ LLM IMPLEMENTATION GUIDE ═══ -->
|
|
<div class="llm">
|
|
<h2>Implementation Guide — Reader Journey</h2>
|
|
|
|
<h3>Views & Routen</h3>
|
|
<table>
|
|
<thead><tr><th>View</th><th>Route</th><th>Component</th><th>Datenquelle</th></tr></thead>
|
|
<tbody>
|
|
<tr><td>Index</td><td>/geschichten</td><td>GeschichtenIndex.svelte</td><td>GET /api/geschichten?status=PUBLISHED</td></tr>
|
|
<tr><td>Detail</td><td>/geschichten/[id]</td><td>GeschichteDetail.svelte</td><td>GET /api/geschichten/{id}</td></tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<h3>Datenmodell je Story (Listenitem)</h3>
|
|
<ul>
|
|
<li><code>id</code> — UUID</li>
|
|
<li><code>title</code> — string</li>
|
|
<li><code>body</code> — string (HTML, serverseitig bereinigt mit DOMPurify vor dem Rendern)</li>
|
|
<li><code>status</code> — <code>DRAFT | PUBLISHED</code></li>
|
|
<li><code>author</code> — AppUser (id, firstName, lastName)</li>
|
|
<li><code>persons</code> — Person[] (id, firstName, lastName) — für Chips & Filter</li>
|
|
<li><code>documents</code> — Document[] (id, title, documentDate, sender) — für Referenzkarten</li>
|
|
<li><code>publishedAt</code> — ISO-8601-Timestamp</li>
|
|
</ul>
|
|
|
|
<h3>Wiederverwendbare Komponenten & Utilities</h3>
|
|
<ul>
|
|
<li><code>PersonChipRow</code> — bestehende Komponente aus <code>$lib/components/</code>; Props: <code>persons: Person[]</code></li>
|
|
<li><code>personAvatarColor(userId)</code> — bestehende Utility; gibt Tailwind-Bg-Klasse zurück</li>
|
|
<li><code>formatDate(iso)</code> — bestehende Utility; gibt „14. März 2025" zurück</li>
|
|
<li><code>BackButton</code> — <code>$lib/components/BackButton.svelte</code>; ruft <code>history.back()</code> auf</li>
|
|
</ul>
|
|
|
|
<h3>Personenfilter — Implementierungshinweise</h3>
|
|
<ul>
|
|
<li>Filter-State in der URL als Query-Parameter: <code>?person=UUID</code>. So ist der gefilterte Zustand direkt verlinkbar und bookmarkbar.</li>
|
|
<li>Server-side Load-Funktion übergibt <code>?personId=UUID</code> an die API. Die API filtert auf Stories, die diese Person in <code>persons[]</code> enthalten.</li>
|
|
<li>Filter-Pills werden aus dem aggregierten Set aller Personen aus geladenen Stories gebaut — nicht als eigener API-Aufruf.</li>
|
|
<li>„+ Person wählen" öffnet ein Inline-Dropdown (bestehende <code>PersonTypeahead</code>-Komponente), fügt die Person zu den Pills hinzu und navigiert mit <code>?person=UUID</code>.</li>
|
|
</ul>
|
|
|
|
<h3>Berechtigung BLOG_WRITE</h3>
|
|
<ul>
|
|
<li>Die Schaltflächen „+ Neue Geschichte", „Bearbeiten" und „Löschen" werden nur gerendert, wenn <code>currentUser.permissions.includes('BLOG_WRITE')</code> wahr ist.</li>
|
|
<li>Nicht nur ausblenden — Backend-Endpunkte für Schreib-/Löschoperationen sind ebenfalls durch <code>@RequirePermission(Permission.BLOG_WRITE)</code> geschützt.</li>
|
|
<li>Auf Mobile werden Bearbeiten/Löschen aus dem Layout entfernt und erscheinen in einem BottomSheet, das über das ··· Menü in der Metazeile geöffnet wird.</li>
|
|
</ul>
|
|
|
|
<h3>Barrierefreiheit</h3>
|
|
<ul>
|
|
<li>Alle Story-Titellinks tragen beschreibenden Text (Titel der Geschichte, kein „hier klicken").</li>
|
|
<li>Personenfilter-Pills verwenden <code>aria-pressed="true|false"</code>.</li>
|
|
<li>Touch-Targets auf Mobile ≥ 44px (<code>min-h-[44px]</code> auf jeder Listenzeile).</li>
|
|
<li>Fokusring auf allen interaktiven Elementen (Tailwind <code>focus-visible:ring-2 focus-visible:ring-primary</code>).</li>
|
|
<li>Löschen-Aktion zeigt einen Bestätigungs-Dialog (<code>window.confirm</code> oder Modal) vor dem API-Aufruf.</li>
|
|
</ul>
|
|
|
|
<h3>Routing & Navigation</h3>
|
|
<ul>
|
|
<li>Jede Listenzeile ist eine <code><a href="/geschichten/{id}"></code> — kein JavaScript-onClick nötig.</li>
|
|
<li>Zurück-Schaltfläche auf der Detailansicht nutzt <code>BackButton</code>-Komponente (history.back()), nicht einen festen Href.</li>
|
|
<li>Personenchips auf der Detailansicht verlinken zu <code>/persons/{id}</code>.</li>
|
|
<li>Dokumentreferenzkarten verlinken zu <code>/documents/{id}</code>.</li>
|
|
</ul>
|
|
|
|
</div><!-- /llm -->
|
|
|
|
</div><!-- /doc -->
|
|
</body>
|
|
</html>
|