1008 lines
65 KiB
HTML
1008 lines
65 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Korrespondenz — Final Design Spec · Familienarchiv</title>
|
||
<style>
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:'Helvetica Neue',Arial,sans-serif;background:#ECEAE4;color:#1A1A1A;line-height:1.5}
|
||
.doc{max-width:1440px;margin:0 auto;padding:48px 32px}
|
||
|
||
/* ── Masthead ─── */
|
||
.mast{background:#0D2240;border-radius:10px;padding:32px 40px;margin-bottom:48px}
|
||
.mast-top{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:16px}
|
||
.mast h1{font-size:22px;font-weight:900;color:#fff;letter-spacing:-.4px;margin-bottom:6px}
|
||
.mast p{font-size:12px;color:rgba(255,255,255,.5);max-width:620px;line-height:1.7}
|
||
.mast-badge{font-size:9px;font-weight:800;padding:3px 9px;border-radius:20px;text-transform:uppercase;letter-spacing:.8px;white-space:nowrap;flex-shrink:0;margin-top:4px}
|
||
.mb-final{background:#A6DAD8;color:#002850}
|
||
.decisions{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:20px;border-top:1px solid rgba(255,255,255,.1);padding-top:16px}
|
||
.dec{background:rgba(255,255,255,.06);border-radius:6px;padding:10px 12px}
|
||
.dec-label{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:rgba(255,255,255,.35);margin-bottom:5px}
|
||
.dec-value{font-size:9.5px;font-weight:700;color:#fff;line-height:1.5}
|
||
.dec-value s{color:rgba(255,255,255,.3);font-weight:400}
|
||
|
||
/* ── Section headings ─── */
|
||
.sec{margin-bottom:64px}
|
||
.sec+.sec{border-top:2px dashed #C8C4BE;padding-top:56px}
|
||
.sec-h{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:1.2px;color:#888;margin-bottom:20px;display:flex;align-items:center;gap:10px}
|
||
.sec-h::after{content:'';flex:1;height:1px;background:#D8D4CE}
|
||
.sec-num{background:#0D2240;color:#fff;font-size:9px;font-weight:900;padding:2px 7px;border-radius:10px}
|
||
|
||
/* ── Screen grid ─── */
|
||
.sg{display:grid;gap:20px;align-items:start}
|
||
.sg-3{grid-template-columns:1fr 1fr 1fr}
|
||
.sg-2{grid-template-columns:1fr 1fr}
|
||
.sg-2a{grid-template-columns:1.3fr 1fr}
|
||
.sg-mob{grid-template-columns:1fr 220px}
|
||
.sb{display:flex;flex-direction:column}
|
||
.sl{font-size:9px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:6px;display:flex;align-items:center;gap:6px}
|
||
.sz{background:#E8E4DF;color:#666;padding:1px 5px;border-radius:3px;font-size:8px}
|
||
.state{padding:1px 6px;border-radius:3px;font-size:8px;font-weight:700}
|
||
.st-empty{background:#FEF3C7;color:#92400E}
|
||
.st-partial{background:#DBEAFE;color:#1E40AF}
|
||
.st-active{background:#DCFCE7;color:#166534}
|
||
.sc{font-size:8.5px;color:#888;margin-top:6px;font-style:italic;line-height:1.5}
|
||
|
||
/* ── Annotation callouts ─── */
|
||
.ann-wrap{position:relative}
|
||
.ann{display:inline-block;font-size:7.5px;font-weight:700;color:#C2410C;background:#FFF7ED;border:1px solid #FDBA74;border-radius:3px;padding:1px 5px;white-space:nowrap}
|
||
.ann-block{background:#FFF7ED;border:1px solid #FDBA74;border-radius:5px;padding:8px 10px;font-size:10px;color:#7C2D12;line-height:1.5;margin-top:10px}
|
||
.ann-block strong{font-weight:800}
|
||
.ann-block ul{padding-left:14px;display:flex;flex-direction:column;gap:3px;margin-top:5px}
|
||
|
||
/* ── Chrome ─── */
|
||
.wf{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 18px rgba(0,0,0,.08)}
|
||
.wf-bar{height:24px;background:#E8E4DF;border-bottom:1px solid #C8C4BE;display:flex;align-items:center;padding:0 9px;gap:4px}
|
||
.dot{width:7px;height:7px;border-radius:50%;background:#C8C4BE}
|
||
.dot.r{background:#F87171}.dot.y{background:#FCD34D}.dot.g{background:#4ADE80}
|
||
.urlbar{flex:1;height:11px;background:#D8D4CE;border-radius:3px;margin-left:6px;display:flex;align-items:center;padding:0 5px}
|
||
.urlbar span{font-size:7.5px;color:#888;font-family:monospace}
|
||
.N{height:42px;background:#0D2240;display:flex;align-items:center;padding:0 16px;gap:12px;flex-shrink:0}
|
||
.logo{font-size:9px;font-weight:900;color:#fff;letter-spacing:1px}
|
||
.nl{font-size:7.5px;color:rgba(255,255,255,.4);font-weight:700;text-transform:uppercase;letter-spacing:.5px}
|
||
.nl.on{color:#fff;border-bottom:2px solid #A6DAD8;padding-bottom:2px}
|
||
.nr{margin-left:auto;display:flex;gap:7px;align-items:center}
|
||
.nico{width:20px;height:20px;background:rgba(255,255,255,.1);border-radius:4px}
|
||
.MAIN{padding:14px 18px;display:flex;flex-direction:column;gap:10px;background:#ECEAE4}
|
||
|
||
/* ── Strip ─── */
|
||
.STRIP-R1{background:#fff;border-bottom:1px solid #EAE7E0;padding:9px 18px;display:flex;align-items:flex-end;gap:9px}
|
||
.STRIP-R2{background:#F7F5F2;border-bottom:1.5px solid #E0DDD6;padding:5px 18px;display:flex;align-items:center;gap:10px}
|
||
.FIELD{flex:1;min-width:0}
|
||
.FL{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:3px}
|
||
.FL .opt{font-weight:400;font-style:italic;color:#C8C4BE;margin-left:3px}
|
||
.FI{height:30px;border:1.5px solid #D1D5DB;border-radius:3px;background:#fff;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#333;gap:6px}
|
||
.FI.set{border-color:#002850}
|
||
.FI.focus{border-color:#002850;box-shadow:0 0 0 2px rgba(0,40,80,.07)}
|
||
.FI.placeholder{color:#C8C4BE;font-style:italic}
|
||
.SWAP{width:28px;height:28px;border:1.5px solid #C8C4BE;border-radius:3px;background:#F0EDE8;display:flex;align-items:center;justify-content:center;font-size:11px;color:#888;flex-shrink:0;align-self:flex-end}
|
||
.SWAP.on{border-color:#002850;color:#002850}
|
||
/* Row 2 tokens */
|
||
.R2-LABEL{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#AAA;white-space:nowrap}
|
||
.R2-DATE{height:22px;border:1.5px solid #D1D5DB;border-radius:3px;background:#fff;display:flex;align-items:center;padding:0 7px;font-size:8px;color:#AAA;font-style:italic;width:80px;flex-shrink:0}
|
||
.R2-DATE.set{color:#333;font-style:normal;border-color:#002850}
|
||
.R2-DASH{font-size:10px;color:#C8C4BE;flex-shrink:0}
|
||
.R2-COUNT{font-size:8px;font-weight:700;color:#888;white-space:nowrap;margin-left:auto}
|
||
.R2-COUNT.filtered{color:#002850}
|
||
.R2-SORT{height:22px;border:1.5px solid #D1D5DB;border-radius:3px;background:#fff;display:flex;align-items:center;padding:0 8px;font-size:8px;font-weight:700;color:#555;gap:3px;cursor:pointer;white-space:nowrap;flex-shrink:0}
|
||
.R2-SORT.active{border-color:#002850;color:#002850}
|
||
|
||
/* ── Suggestion dropdown ─── */
|
||
.SUGG{background:#fff;border:1.5px solid #002850;border-top:none;border-radius:0 0 4px 4px;box-shadow:0 5px 12px rgba(0,0,0,.1)}
|
||
.SUGG-H{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#AAA;padding:5px 9px 3px;border-bottom:1px solid #F0EDE8}
|
||
.SUGG-R{display:flex;align-items:center;gap:7px;padding:6px 9px;cursor:pointer;border-bottom:1px solid #F7F5F2}
|
||
.SUGG-R:hover{background:#F7F5F2}
|
||
.SUGG-R:last-child{border-bottom:none}
|
||
.SUGG-NAME{flex:1;font-size:8.5px;font-weight:700;color:#0D2240}
|
||
.SUGG-BAR{width:40px;height:3px;border-radius:2px;background:#E0DDD6;overflow:hidden}
|
||
.SUGG-FILL{height:100%;background:#002850}
|
||
.SUGG-CNT{font-size:7.5px;color:#AAA}
|
||
.SUGG-ALL{font-size:7.5px;color:#888;font-style:italic}
|
||
/* Divider row */
|
||
.SUGG-DIV{font-size:7px;color:#C8C4BE;padding:4px 9px;border-top:1px solid #F0EDE8}
|
||
.AV{border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:900;flex-shrink:0}
|
||
.AV-xs{width:16px;height:16px;font-size:5.5px}
|
||
.AV-sm{width:20px;height:20px;font-size:6.5px}
|
||
.AV-navy{background:#002850;color:#fff}
|
||
.AV-outline{background:#fff;color:#444;border:1.5px solid #C8C4BE}
|
||
.AV-sand{background:#E8E4DF;color:#666}
|
||
|
||
/* ── Asymmetry bar ─── */
|
||
.ASYM{padding:8px 18px;background:#F7F5F2;border-bottom:1px solid #E8E4DF;display:flex;flex-direction:column;gap:4px}
|
||
.ASYM-LABELS{display:flex;justify-content:space-between;font-size:7.5px;font-weight:700}
|
||
.ASYM-LABELS .s{color:#002850}
|
||
.ASYM-LABELS .r{color:#0F5755}
|
||
.ASYM-BAR{height:5px;border-radius:3px;background:#E0DDD6;overflow:hidden;display:flex}
|
||
.ASYM-OUT{height:100%;background:#002850}
|
||
.ASYM-IN{height:100%;background:#A6DAD8}
|
||
|
||
/* ── Log ─── */
|
||
.LOG{background:#fff;border:1.5px solid #E0DDD6;border-radius:4px;overflow:hidden}
|
||
.LOG-YEAR{padding:6px 14px;background:#F0EDE6;border-top:2px solid #C8C4BE;border-bottom:1px solid #D8D4CE;display:flex;align-items:baseline;gap:8px}
|
||
.LOG-YEAR-N{font-size:15px;font-weight:900;color:#002850;letter-spacing:-.5px}
|
||
.LOG-YEAR-C{font-size:7.5px;color:#AAA;font-weight:700}
|
||
.LOG-ROW{padding:10px 14px;border-left:3px solid transparent;border-bottom:1px solid #EDEBE4;display:flex;align-items:flex-start;gap:9px;cursor:pointer;text-decoration:none}
|
||
.LOG-ROW:hover{background:#F7F5F2}
|
||
.LOG-ROW:last-child{border-bottom:none}
|
||
.LOG-ROW.out{border-left-color:#002850}
|
||
.LOG-ROW.in{border-left-color:#A6DAD8}
|
||
.LOG-DIR{font-size:9px;font-weight:900;flex-shrink:0;padding-top:1px;width:14px}
|
||
.LOG-DIR.out{color:#002850}
|
||
.LOG-DIR.in{color:#0F5755}
|
||
.LOG-BODY{flex:1;min-width:0}
|
||
.LOG-TITLE{font-size:9px;font-weight:700;color:#0D2240;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.LOG-META{font-size:7.5px;color:#888;display:flex;align-items:center;gap:5px}
|
||
.LOG-META-SEP{color:#D1CCC8}
|
||
.LOG-ACTION{flex-shrink:0;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:3px;background:#F7F5F2;border:1px solid #E8E4DF;opacity:0}
|
||
.LOG-ROW:hover .LOG-ACTION{opacity:1}
|
||
/* Status dot */
|
||
.S-DOT{width:6px;height:6px;border-radius:50%;flex-shrink:0}
|
||
.S-UPLOADED{background:#22C55E}
|
||
.S-TRANSCRIBED{background:#3B82F6}
|
||
.S-REVIEWED{background:#A855F7}
|
||
.S-ARCHIVED{background:#6B7280}
|
||
.S-PLACEHOLDER{background:#F59E0B}
|
||
|
||
/* ── Empty state ─── */
|
||
.EMPTY{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:56px 24px;text-align:center}
|
||
.EMPTY-ICON{width:52px;height:52px;background:#F0EDE6;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:24px;margin-bottom:16px}
|
||
.EMPTY-H{font-size:14px;font-weight:800;color:#0D2240;font-family:Georgia,serif;margin-bottom:5px}
|
||
.EMPTY-S{font-size:10.5px;color:#888;max-width:280px;line-height:1.7;margin-bottom:22px}
|
||
.EMPTY-INPUT{width:260px;height:36px;border:2px solid #002850;border-radius:4px;display:flex;align-items:center;padding:0 12px;font-size:9px;color:#C8C4BE;font-style:italic;gap:8px;box-shadow:0 0 0 4px rgba(0,40,80,.06);margin-bottom:18px}
|
||
.EMPTY-OR{font-size:8px;text-transform:uppercase;letter-spacing:1px;color:#C8C4BE;font-weight:700;margin-bottom:10px}
|
||
.EMPTY-RECENT-L{font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#AAA;margin-bottom:8px}
|
||
.EMPTY-CHIPS{display:flex;gap:6px;flex-wrap:wrap;justify-content:center}
|
||
.EMPTY-CHIP{display:inline-flex;align-items:center;gap:5px;background:#fff;border:1.5px solid #E0DDD6;border-radius:20px;padding:5px 11px;font-size:8.5px;font-weight:700;color:#0D2240;cursor:pointer;transition:border-color .1s}
|
||
.EMPTY-CHIP:hover{border-color:#002850}
|
||
|
||
/* ── Single-person hint ─── */
|
||
.SPMODE{padding:6px 18px;background:#FFF7ED;border-bottom:1px solid #FDBA74;font-size:8px;color:#92400E;display:flex;align-items:center;gap:5px}
|
||
.SPMODE strong{font-weight:800}
|
||
|
||
/* ── Mobile chrome ─── */
|
||
.WF-M{background:#fff;border:2px solid #B8B4AE;border-radius:16px;overflow:hidden;box-shadow:0 4px 18px rgba(0,0,0,.08);width:220px}
|
||
.WF-M-STATUS{height:18px;background:#0D2240;display:flex;align-items:center;justify-content:space-between;padding:0 10px}
|
||
.WF-M-TIME{font-size:7px;color:#fff;font-weight:700}
|
||
.WF-M-ICONS{display:flex;gap:3px}
|
||
.WF-M-ICON{width:6px;height:6px;background:rgba(255,255,255,.5);border-radius:1px}
|
||
.N-M{height:40px;background:#0D2240;display:flex;align-items:center;padding:0 12px;justify-content:space-between}
|
||
.MAIN-SM{padding:10px 12px;display:flex;flex-direction:column;gap:8px;background:#ECEAE4}
|
||
.STRIP-R1-SM{background:#fff;border-bottom:1px solid #EAE7E0;padding:8px 12px;display:flex;flex-direction:column;gap:6px}
|
||
.STRIP-R2-SM{background:#F7F5F2;border-bottom:1.5px solid #E0DDD6;padding:5px 12px;display:flex;align-items:center;gap:7px}
|
||
.PH{height:7px;background:#E8E4DF;border-radius:2px;margin-bottom:4px}
|
||
.w80{width:80%}.w70{width:70%}.w60{width:60%}.w50{width:50%}.w40{width:40%}
|
||
|
||
/* ── Changelog / decision list ─── */
|
||
.CHANGES{background:#fff;border:1.5px solid #E0DDD6;border-radius:8px;padding:20px 24px;margin-bottom:40px}
|
||
.CHANGES h2{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:#888;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid #E8E4DF}
|
||
.CHANGES-GRID{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
||
.C-COL h3{font-size:10px;font-weight:800;color:#444;margin-bottom:8px}
|
||
.C-COL ul{list-style:none;display:flex;flex-direction:column;gap:5px}
|
||
.C-COL ul li{font-size:11px;color:#555;padding-left:16px;position:relative;line-height:1.5}
|
||
.C-COL.new li::before{content:'✦';position:absolute;left:0;color:#002850;font-size:8px}
|
||
.C-COL.remove li::before{content:'✗';position:absolute;left:0;color:#DC2626}
|
||
.C-COL.keep li::before{content:'→';position:absolute;left:0;color:#888}
|
||
|
||
/* ── Impl notes ─── */
|
||
.IMPL{background:#0D2240;border-radius:8px;padding:20px 24px;margin-top:48px}
|
||
.IMPL h2{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:rgba(255,255,255,.4);margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid rgba(255,255,255,.08)}
|
||
.IMPL-GRID{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
|
||
.IMPL-COL h3{font-size:9.5px;font-weight:800;color:rgba(255,255,255,.6);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px}
|
||
.IMPL-COL ul{list-style:none;display:flex;flex-direction:column;gap:5px}
|
||
.IMPL-COL ul li{font-size:10.5px;color:rgba(255,255,255,.75);padding-left:14px;position:relative;line-height:1.5}
|
||
.IMPL-COL ul li::before{content:'›';position:absolute;left:0;color:rgba(255,255,255,.3)}
|
||
.IMPL-COL code{font-family:monospace;font-size:9.5px;background:rgba(255,255,255,.08);padding:1px 4px;border-radius:3px;color:#A6DAD8}
|
||
|
||
/* ── Spec disclaimer ─── */
|
||
.spec-disclaimer{background:#FFF8E1;border:1.5px solid #FFC107;border-radius:6px;padding:11px 16px;font-size:11px;color:#6D4C00;margin-bottom:32px;line-height:1.6}
|
||
.spec-disclaimer strong{font-weight:800}
|
||
|
||
/* ── Agent Implementation Reference (impl-ref) ─────────────────────────
|
||
Appears after every visual section. Mockup CSS values are at ~55% scale
|
||
and must NOT be used as implementation values. Use these tables instead.
|
||
──────────────────────────────────────────────────────────────────────── */
|
||
.impl-ref{background:#0d1117;border-radius:8px;margin-top:20px;overflow:hidden;border:1px solid #30363d}
|
||
.impl-ref-hdr{background:#161b22;padding:9px 16px;font-size:9.5px;font-weight:800;color:#f0883e;border-bottom:1px solid #30363d;display:flex;align-items:center;gap:8px;letter-spacing:.4px;text-transform:uppercase}
|
||
.impl-ref-hdr::before{content:'⚙';font-size:12px}
|
||
.impl-ref-hdr span{color:rgba(240,136,62,.55);font-weight:400;margin-left:auto;font-size:9px;text-transform:none;letter-spacing:0}
|
||
.impl-ref table{width:100%;border-collapse:collapse;font-size:10px}
|
||
.impl-ref th{text-align:left;font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:#8b949e;padding:8px 14px;border-bottom:1px solid #21262d}
|
||
.impl-ref td{padding:6px 14px;border-bottom:1px solid #161b22;vertical-align:top;line-height:1.6;color:#c9d1d9}
|
||
.impl-ref tr:last-child td{border-bottom:none}
|
||
.impl-ref td:first-child{color:#79c0ff;font-weight:700;white-space:nowrap;width:190px}
|
||
.impl-ref td code{font-family:'SFMono-Regular',Consolas,monospace;font-size:9.5px;background:#161b22;color:#a5d6ff;padding:1px 5px;border-radius:3px;white-space:nowrap}
|
||
.impl-ref .ir-px{color:#7ee787;font-family:monospace;font-size:9.5px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="doc">
|
||
|
||
<!-- ══════════════════════════════════
|
||
MASTHEAD
|
||
══════════════════════════════════ -->
|
||
<div class="mast">
|
||
<div class="mast-top">
|
||
<div>
|
||
<h1>Korrespondenz — Final Design Spec</h1>
|
||
<p>Correspondence Log with Compact Strip + Permanent Second Row. All design decisions from the exploration session locked in.</p>
|
||
</div>
|
||
<span class="mast-badge mb-final">Final · Ready for implementation</span>
|
||
</div>
|
||
<div class="decisions">
|
||
<div class="dec">
|
||
<div class="dec-label">Page name</div>
|
||
<div class="dec-value"><s>Gespräche</s><br>→ Korrespondenz</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Timeline renderer</div>
|
||
<div class="dec-value"><s>Chat bubbles</s><br>→ Correspondence Log</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Filter</div>
|
||
<div class="dec-value">Compact strip<br>2 rows · always visible</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Receiver</div>
|
||
<div class="dec-value"><s>Required</s><br>→ Optional (single-person mode)</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Discovery</div>
|
||
<div class="dec-value">Top correspondents<br>in person B dropdown</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Ghost cards</div>
|
||
<div class="dec-value"><s>Considered</s><br>→ Dropped</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Hub sidebar</div>
|
||
<div class="dec-value"><s>Considered</s><br>→ Dropped (person detail)</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Secondary filters</div>
|
||
<div class="dec-value">Permanent row 2<br>Von / Bis / Sort / Count</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="spec-disclaimer">
|
||
<strong>📐 Mockup scale notice —</strong> all font-size, height, padding, and spacing values in the mockup CSS below are scaled to ~55% of their real implementation values so they fit on screen. <strong>Do not copy sizes from the mockup HTML/CSS.</strong> Each section ends with an <strong>⚙ Implementation Reference</strong> table listing the exact Tailwind classes and real pixel values to use in code.
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════
|
||
CHANGES
|
||
══════════════════════════════════ -->
|
||
<div class="CHANGES">
|
||
<h2>What changes vs. current implementation</h2>
|
||
<div class="CHANGES-GRID">
|
||
<div class="C-COL new">
|
||
<h3>New / changed</h3>
|
||
<ul>
|
||
<li>Nav label: "Gespräche" → "Korrespondenz" (i18n key update)</li>
|
||
<li>Filter card → compact 2-row strip (redesign ConversationFilterBar)</li>
|
||
<li>Row 2 always visible: Von · Bis date inputs + live letter count + sort toggle</li>
|
||
<li>Receiver field: required → optional; single-person mode works without it</li>
|
||
<li>Person B input shows top correspondents as suggestions when person A is set (uses existing <code>restrictToCorrespondentsOf</code> — just surface the results)</li>
|
||
<li>Timeline renderer: chat bubbles → correspondence log cards (redesign ConversationTimeline)</li>
|
||
<li>Log card: direction arrow (→/←) + left border color + title + date + sender/recipient + status dot</li>
|
||
<li>Asymmetry bar visible when both persons selected</li>
|
||
<li>Empty state: centered prompt with person search + recent chips (remove "select both" gate)</li>
|
||
<li>Single-person mode hint strip: amber bar explaining scope</li>
|
||
</ul>
|
||
</div>
|
||
<div class="C-COL keep">
|
||
<h3>Kept unchanged</h3>
|
||
<ul>
|
||
<li>PersonTypeahead component — used in both fields as-is</li>
|
||
<li><code>restrictToCorrespondentsOf</code> prop — drives the suggestions</li>
|
||
<li>Swap button (⇄) — same behaviour</li>
|
||
<li><code>/api/documents/conversation</code> endpoint — no backend change for bilateral view</li>
|
||
<li>URL params: <code>?senderId=…&receiverId=…&from=…&to=…&dir=…</code></li>
|
||
<li>SvelteKit navigation with <code>goto()</code></li>
|
||
<li>Year divider logic from ConversationTimeline</li>
|
||
<li>canWrite / new document link</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════
|
||
SECTION 1 — EMPTY STATE
|
||
══════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h"><span class="sec-num">1</span> Empty state — no person selected</div>
|
||
|
||
<div class="sg sg-2a">
|
||
<div class="sb">
|
||
<div class="sl">Desktop <span class="sz">≥768px</span> <span class="state st-empty">No selection</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz</span></div></div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl">Dokumente</span><span class="nl">Personen</span>
|
||
<span class="nl on">Korrespondenz</span>
|
||
<div class="nr"><div class="nico"></div><div class="nico"></div></div>
|
||
</div>
|
||
<!-- Strip: row 1 — both empty -->
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD">
|
||
<div class="FL">Person</div>
|
||
<div class="FI placeholder"><span style="font-size:11px;color:#DDD">🔍</span> Name eingeben…</div>
|
||
</div>
|
||
<div class="SWAP">⇄</div>
|
||
<div class="FIELD">
|
||
<div class="FL">Korrespondent <span class="opt">— optional</span></div>
|
||
<div class="FI placeholder" style="background:#F9F8F6;border-style:dashed">Alle Korrespondenten</div>
|
||
</div>
|
||
</div>
|
||
<!-- Strip: row 2 — disabled -->
|
||
<div class="STRIP-R2" style="opacity:.4;pointer-events:none">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE">Von…</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE">Bis…</div>
|
||
<div class="R2-COUNT" style="margin-left:auto">—</div>
|
||
<div class="R2-SORT">Neueste ↓</div>
|
||
</div>
|
||
<!-- Empty body -->
|
||
<div class="EMPTY">
|
||
<div class="EMPTY-ICON">✉</div>
|
||
<div class="EMPTY-H">Korrespondenz durchsuchen</div>
|
||
<div class="EMPTY-S">Wähle eine Person aus dem Archiv um deren Briefe zu sehen — mit oder ohne Korrespondent.</div>
|
||
<div class="EMPTY-INPUT"><span style="font-size:13px;color:#DDD">🔍</span> <span>Person suchen…</span></div>
|
||
<div class="EMPTY-OR">oder</div>
|
||
<div class="EMPTY-RECENT-L">Zuletzt geöffnet</div>
|
||
<div class="EMPTY-CHIPS">
|
||
<div class="EMPTY-CHIP"><div class="AV AV-xs AV-navy" style="margin-right:2px">OF</div>Otto Familienname</div>
|
||
<div class="EMPTY-CHIP"><div class="AV AV-xs AV-outline" style="margin-right:2px">MW</div>Maria Weber</div>
|
||
<div class="EMPTY-CHIP"><div class="AV AV-xs AV-outline" style="margin-right:2px">KF</div>Klaus Fischer</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Row 2 dimmed but visible — communicates the feature exists before it's usable. Clicking the "Person suchen" input focuses the strip's Person field. Recent chips use localStorage; shown only if history exists.</div>
|
||
</div>
|
||
|
||
<div class="sb">
|
||
<div class="sl">Mobile <span class="sz">375px</span></div>
|
||
<div style="display:flex;justify-content:center">
|
||
<div class="WF-M">
|
||
<div class="WF-M-STATUS"><span class="WF-M-TIME">09:41</span><div class="WF-M-ICONS"><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div></div></div>
|
||
<div class="N-M"><span class="logo" style="font-size:8.5px">FAMILIENARCHIV</span><span style="color:rgba(255,255,255,.7);font-size:17px">☰</span></div>
|
||
<!-- Mobile strip: stacked -->
|
||
<div class="STRIP-R1-SM">
|
||
<div>
|
||
<div class="FL">Person</div>
|
||
<div class="FI placeholder" style="height:36px;font-size:9px"><span style="font-size:11px;color:#DDD">🔍</span> Name eingeben…</div>
|
||
</div>
|
||
<div>
|
||
<div class="FL">Korrespondent <span class="opt">— optional</span></div>
|
||
<div class="FI placeholder" style="height:36px;font-size:9px;background:#F9F8F6;border-style:dashed">Alle Korrespondenten</div>
|
||
</div>
|
||
</div>
|
||
<div class="STRIP-R2-SM" style="opacity:.4">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE" style="width:60px;font-size:7.5px">Von…</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE" style="width:60px;font-size:7.5px">Bis…</div>
|
||
<div class="R2-SORT" style="font-size:7.5px;height:20px;margin-left:auto">Neueste ↓</div>
|
||
</div>
|
||
<div class="EMPTY" style="padding:32px 16px">
|
||
<div class="EMPTY-ICON" style="width:40px;height:40px;font-size:18px;margin-bottom:12px">✉</div>
|
||
<div class="EMPTY-H" style="font-size:12px">Korrespondenz durchsuchen</div>
|
||
<div class="EMPTY-S" style="font-size:9.5px;margin-bottom:16px">Person oben eingeben um Briefe zu sehen.</div>
|
||
<div class="EMPTY-CHIPS" style="gap:5px">
|
||
<div class="EMPTY-CHIP" style="font-size:8px;padding:4px 9px"><div class="AV AV-xs AV-navy" style="margin-right:2px">OF</div>Otto F.</div>
|
||
<div class="EMPTY-CHIP" style="font-size:8px;padding:4px 9px"><div class="AV AV-xs AV-outline" style="margin-right:2px">MW</div>Maria W.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Mobile: both person fields stacked full-width (44px touch target). Row 2 stacked beneath. Recent chips condensed to initials + first name.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Filter Strip & Empty State <span>Real values · mockup above is ~55% scale</span></div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Strip Row 1 container</td>
|
||
<td><code>flex items-end gap-4 px-4 sm:px-6 py-3 bg-surface border-b border-line</code></td>
|
||
<td><span class="ir-px">h ~56px, px 16–24px, py 12px</span></td>
|
||
<td>White background, 1px bottom border</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Field label (.FL)</td>
|
||
<td><code>text-xs font-bold uppercase tracking-widest text-ink-2 mb-1.5</code></td>
|
||
<td><span class="ir-px">12px / 700</span></td>
|
||
<td>"optional" suffix: <code>font-normal not-italic text-ink-3</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Text input / typeahead</td>
|
||
<td><code>h-10 w-full px-3 text-sm border border-line bg-surface text-ink placeholder:text-ink-3 focus:border-ink focus:ring-1 focus:ring-ink focus:outline-none</code></td>
|
||
<td><span class="ir-px">40px tall, 14px text</span></td>
|
||
<td>Optional field: <code>border-dashed bg-muted</code> when empty</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Swap button</td>
|
||
<td><code>h-10 w-10 flex shrink-0 items-center justify-center border border-line text-ink-2 hover:text-ink hover:border-ink transition-colors self-end</code></td>
|
||
<td><span class="ir-px">40×40px</span></td>
|
||
<td>Active (both set): <code>border-ink text-ink</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Strip Row 2 container</td>
|
||
<td><code>flex items-center gap-3 px-4 sm:px-6 py-2 bg-canvas border-b border-line</code></td>
|
||
<td><span class="ir-px">h ~36px, py 8px</span></td>
|
||
<td>When no person selected: <code>opacity-40 pointer-events-none</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Row 2 period label</td>
|
||
<td><code>text-xs font-bold uppercase tracking-widest text-ink-3 shrink-0</code></td>
|
||
<td><span class="ir-px">12px / 700</span></td>
|
||
<td>"Zeitraum" label before the date fields</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Date input (Von / Bis)</td>
|
||
<td><code>h-8 w-24 px-2 text-xs border border-line bg-surface text-ink placeholder:text-ink-3 focus:border-ink focus:outline-none</code></td>
|
||
<td><span class="ir-px">32px tall, 12px text, 96px wide</span></td>
|
||
<td>When set: <code>border-ink</code>. Format: dd.mm.yyyy</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Letter count</td>
|
||
<td><code>ml-auto text-sm font-bold text-ink-2</code></td>
|
||
<td><span class="ir-px">14px / 700</span></td>
|
||
<td>When filtered (≠ total): <code>text-primary</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort toggle button</td>
|
||
<td><code>h-8 px-3 text-xs font-bold border border-line text-ink-2 hover:text-ink hover:border-ink transition-colors</code></td>
|
||
<td><span class="ir-px">32px tall, 12px text</span></td>
|
||
<td>Active: <code>border-primary text-primary</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Empty state icon circle</td>
|
||
<td><code>w-16 h-16 rounded-full bg-muted flex items-center justify-center text-3xl mb-4</code></td>
|
||
<td><span class="ir-px">64×64px, 30px icon</span></td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Empty state heading</td>
|
||
<td><code>font-serif text-xl font-bold text-ink mb-2</code></td>
|
||
<td><span class="ir-px">20px / 700</span></td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Empty state sub-text</td>
|
||
<td><code>text-sm text-ink-2 max-w-xs text-center leading-relaxed mb-6</code></td>
|
||
<td><span class="ir-px">14px</span></td>
|
||
<td></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Recent person chip</td>
|
||
<td><code>inline-flex items-center gap-2 px-3 py-1.5 border border-line bg-surface text-sm font-semibold text-ink hover:border-primary transition-colors</code></td>
|
||
<td><span class="ir-px">h ~32px, 14px text</span></td>
|
||
<td>Avatar: <code>w-5 h-5 rounded-full text-[10px]</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════
|
||
SECTION 2 — SINGLE-PERSON MODE
|
||
══════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h"><span class="sec-num">2</span> Single-person mode — Person A set, picking correspondent</div>
|
||
|
||
<div class="sg sg-3">
|
||
<!-- Suggestions open -->
|
||
<div class="sb">
|
||
<div class="sl">Person B input focused <span class="state st-partial">Suggestions shown</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz?senderId=otto-id</span></div></div>
|
||
<div class="N"><span class="logo">FAMILIENARCHIV</span><span class="nl">Dokumente</span><span class="nl">Personen</span><span class="nl on">Korrespondenz</span><div class="nr"><div class="nico"></div></div></div>
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD">
|
||
<div class="FL">Person</div>
|
||
<div class="FI set"><div class="AV AV-xs AV-navy">OF</div>Otto Familienname</div>
|
||
</div>
|
||
<div class="SWAP on">⇄</div>
|
||
<!-- Person B: focused, suggestion dropdown -->
|
||
<div class="FIELD" style="position:relative">
|
||
<div class="FL">Korrespondent <span class="opt">— optional</span></div>
|
||
<div class="FI focus"><span style="font-size:10px;color:#C8C4BE">🔍</span><span style="color:#C8C4BE;font-style:italic;font-size:8.5px">Ottos Korrespondenten…</span></div>
|
||
<div class="SUGG">
|
||
<div class="SUGG-H">Häufigste Korrespondenten</div>
|
||
<div class="SUGG-R">
|
||
<div class="AV AV-xs AV-outline">MW</div>
|
||
<div class="SUGG-NAME">Maria Weber</div>
|
||
<div class="SUGG-BAR"><div class="SUGG-FILL" style="width:88%"></div></div>
|
||
<div class="SUGG-CNT">32 Briefe</div>
|
||
</div>
|
||
<div class="SUGG-R">
|
||
<div class="AV AV-xs AV-outline">KF</div>
|
||
<div class="SUGG-NAME">Klaus Fischer</div>
|
||
<div class="SUGG-BAR"><div class="SUGG-FILL" style="width:50%"></div></div>
|
||
<div class="SUGG-CNT">11 Briefe</div>
|
||
</div>
|
||
<div class="SUGG-R">
|
||
<div class="AV AV-xs AV-outline">HM</div>
|
||
<div class="SUGG-NAME">Helene Müller</div>
|
||
<div class="SUGG-BAR"><div class="SUGG-FILL" style="width:18%"></div></div>
|
||
<div class="SUGG-CNT">4 Briefe</div>
|
||
</div>
|
||
<div class="SUGG-DIV">oder ohne Einschränkung</div>
|
||
<div class="SUGG-R">
|
||
<div class="AV AV-xs AV-sand">—</div>
|
||
<div class="SUGG-NAME" style="font-style:italic;color:#888">Alle Korrespondenten Ottos</div>
|
||
<div class="SUGG-CNT SUGG-ALL">47 Briefe</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="STRIP-R2">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE">Von…</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE">Bis…</div>
|
||
<div class="R2-COUNT" style="margin-left:auto">47 Briefe</div>
|
||
<div class="R2-SORT">Neueste ↓</div>
|
||
</div>
|
||
<!-- Hint bar -->
|
||
<div class="SPMODE">
|
||
<span style="font-size:11px">📋</span>
|
||
<span><strong>Alle Briefe Ottos</strong> — wähle einen Korrespondenten oben um einzugrenzen</span>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1943</span><span class="LOG-YEAR-C">5 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief an Maria — letzte Nachrichten</div><div class="LOG-META">3. Sept. 1943<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief an Klaus Fischer</div><div class="LOG-META">12. Sept. 1943<span class="LOG-META-SEP">·</span>Klaus Fischer<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW in"><div class="LOG-DIR in">←</div><div class="LOG-BODY"><div class="LOG-TITLE">Antwort von Klaus</div><div class="LOG-META">18. Sept. 1943<span class="LOG-META-SEP">·</span>Klaus Fischer<div class="S-DOT S-REVIEWED" style="margin-left:3px"></div></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Dropdown uses <code>restrictToCorrespondentsOf</code> — only actual correspondents shown. "Alle Korrespondenten" row is the explicit opt-out. Log shows immediately (no blank screen), hint bar explains scope.</div>
|
||
</div>
|
||
|
||
<!-- Log showing (no correspondent) -->
|
||
<div class="sb">
|
||
<div class="sl">Single-person log <span class="state st-partial">No correspondent</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz?senderId=otto-id</span></div></div>
|
||
<div class="N"><span class="logo">FAMILIENARCHIV</span><span class="nl">Dokumente</span><span class="nl">Personen</span><span class="nl on">Korrespondenz</span><div class="nr"><div class="nico"></div></div></div>
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD"><div class="FL">Person</div><div class="FI set"><div class="AV AV-xs AV-navy">OF</div>Otto Familienname</div></div>
|
||
<div class="SWAP">⇄</div>
|
||
<div class="FIELD"><div class="FL">Korrespondent <span class="opt">— optional</span></div><div class="FI placeholder" style="border-style:dashed">Alle Korrespondenten</div></div>
|
||
</div>
|
||
<div class="STRIP-R2">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE">Von…</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE">Bis…</div>
|
||
<div class="R2-COUNT" style="margin-left:auto">47 Briefe</div>
|
||
<div class="R2-SORT">Neueste ↓</div>
|
||
</div>
|
||
<div class="SPMODE">
|
||
<span style="font-size:11px">📋</span>
|
||
<span><strong>Alle Briefe Ottos</strong> — wähle einen Korrespondenten oben um einzugrenzen</span>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1943</span><span class="LOG-YEAR-C">5 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief an Maria — letzte Nachrichten</div><div class="LOG-META">3. Sept. 1943<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief an Klaus Fischer</div><div class="LOG-META">12. Sept. 1943<span class="LOG-META-SEP">·</span>Klaus Fischer<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW in"><div class="LOG-DIR in">←</div><div class="LOG-BODY"><div class="LOG-TITLE">Antwort von Klaus</div><div class="LOG-META">18. Sept. 1943<span class="LOG-META-SEP">·</span>Klaus Fischer<div class="S-DOT S-REVIEWED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1942</span><span class="LOG-YEAR-C">8 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief aus dem Feld</div><div class="LOG-META">14. März 1942<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Neuigkeiten aus München</div><div class="LOG-META">22. Jan. 1942<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-TRANSCRIBED" style="margin-left:3px"></div></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">In single-person mode the recipient/sender name appears in the meta line — the only way to see who each letter is addressed to without filtering. Dashed border on correspondent field signals it's optional.</div>
|
||
</div>
|
||
|
||
<!-- Date range set in single-person mode -->
|
||
<div class="sb">
|
||
<div class="sl">Date range active <span class="state st-partial">Filtered + sorted</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz?senderId=otto-id&from=1940-01-01&to=1943-12-31&dir=ASC</span></div></div>
|
||
<div class="N"><span class="logo">FAMILIENARCHIV</span><span class="nl">Dokumente</span><span class="nl">Personen</span><span class="nl on">Korrespondenz</span><div class="nr"><div class="nico"></div></div></div>
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD"><div class="FL">Person</div><div class="FI set"><div class="AV AV-xs AV-navy">OF</div>Otto Familienname</div></div>
|
||
<div class="SWAP">⇄</div>
|
||
<div class="FIELD"><div class="FL">Korrespondent <span class="opt">— optional</span></div><div class="FI placeholder" style="border-style:dashed">Alle Korrespondenten</div></div>
|
||
</div>
|
||
<div class="STRIP-R2">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE set">01.01.1940</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE set">31.12.1943</div>
|
||
<div class="R2-COUNT filtered" style="margin-left:auto">13 Briefe</div>
|
||
<div class="R2-SORT active">Älteste ↑</div>
|
||
</div>
|
||
<div class="SPMODE">
|
||
<span style="font-size:11px">📋</span>
|
||
<span><strong>Alle Briefe Ottos</strong> · 1940–1943 · Älteste zuerst</span>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1940</span><span class="LOG-YEAR-C">3 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Erster Brief aus dem Krieg</div><div class="LOG-META">3. Sept. 1940<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief über die Zustände</div><div class="LOG-META">15. Nov. 1940<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-TRANSCRIBED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1941</span><span class="LOG-YEAR-C">4 Briefe</span></div>
|
||
<div class="LOG-ROW in"><div class="LOG-DIR in">←</div><div class="LOG-BODY"><div class="LOG-TITLE">Marias Antwort — Weihnachten</div><div class="LOG-META">22. Dez. 1941<span class="LOG-META-SEP">·</span>Maria Weber<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">When a date range is set, the hint bar updates to summarise active filters. Count in row 2 turns navy and updates live. Both date inputs show navy border when set.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════
|
||
SECTION 3 — BILATERAL MODE (both selected)
|
||
══════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h"><span class="sec-num">3</span> Bilateral mode — both persons selected</div>
|
||
|
||
<div class="sg sg-2a">
|
||
<!-- Full bilateral view -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop <span class="sz">≥768px</span> <span class="state st-active">Both selected</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz?senderId=otto-id&receiverId=maria-id</span></div></div>
|
||
<div class="N"><span class="logo">FAMILIENARCHIV</span><span class="nl">Dokumente</span><span class="nl">Personen</span><span class="nl on">Korrespondenz</span><div class="nr"><div class="nico"></div></div></div>
|
||
<!-- Strip row 1 -->
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD"><div class="FL">Person</div><div class="FI set"><div class="AV AV-xs AV-navy">OF</div>Otto Familienname</div></div>
|
||
<div class="SWAP on">⇄</div>
|
||
<div class="FIELD"><div class="FL">Korrespondent</div><div class="FI set"><div class="AV AV-xs AV-outline">MW</div>Maria Weber</div></div>
|
||
</div>
|
||
<!-- Strip row 2 — active, count live -->
|
||
<div class="STRIP-R2">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE">Von…</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE">Bis…</div>
|
||
<div class="R2-COUNT" style="margin-left:auto">32 Briefe</div>
|
||
<div class="R2-SORT">Neueste ↓</div>
|
||
</div>
|
||
<!-- Asymmetry bar — only in bilateral mode -->
|
||
<div class="ASYM">
|
||
<div class="ASYM-LABELS">
|
||
<span class="s">28 von Otto →</span>
|
||
<span class="r">4 von Maria ←</span>
|
||
</div>
|
||
<div class="ASYM-BAR">
|
||
<div class="ASYM-OUT" style="width:87.5%"></div>
|
||
<div class="ASYM-IN" style="width:12.5%"></div>
|
||
</div>
|
||
</div>
|
||
<!-- Log -->
|
||
<div class="MAIN">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1943</span><span class="LOG-YEAR-C">3 Briefe</span></div>
|
||
<div class="LOG-ROW out">
|
||
<div class="LOG-DIR out">→</div>
|
||
<div class="LOG-BODY">
|
||
<div class="LOG-TITLE">Brief an Maria — letzte Nachrichten</div>
|
||
<div class="LOG-META">3. Sept. 1943<span class="LOG-META-SEP">·</span>Prag<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div>
|
||
</div>
|
||
<div class="LOG-ACTION">›</div>
|
||
</div>
|
||
<div class="LOG-ROW in">
|
||
<div class="LOG-DIR in">←</div>
|
||
<div class="LOG-BODY">
|
||
<div class="LOG-TITLE">Marias Antwort — September</div>
|
||
<div class="LOG-META">10. Sept. 1943<span class="LOG-META-SEP">·</span>Wien<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div>
|
||
</div>
|
||
<div class="LOG-ACTION">›</div>
|
||
</div>
|
||
<div class="LOG-ROW out">
|
||
<div class="LOG-DIR out">→</div>
|
||
<div class="LOG-BODY">
|
||
<div class="LOG-TITLE">Abschiedsbrief</div>
|
||
<div class="LOG-META">28. Sept. 1943<span class="LOG-META-SEP">·</span>Ostfront<div class="S-DOT S-TRANSCRIBED" style="margin-left:3px"></div></div>
|
||
</div>
|
||
<div class="LOG-ACTION">›</div>
|
||
</div>
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1942</span><span class="LOG-YEAR-C">7 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief aus dem Feld</div><div class="LOG-META">14. März 1942<span class="LOG-META-SEP">·</span>Frankreich<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Neuigkeiten aus München</div><div class="LOG-META">22. Jan. 1942<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW in"><div class="LOG-DIR in">←</div><div class="LOG-BODY"><div class="LOG-TITLE">Weihnachtsbrief von Maria</div><div class="LOG-META">20. Dez. 1942<span class="LOG-META-SEP">·</span>Wien<div class="S-DOT S-REVIEWED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Gedanken zu Weihnachten</div><div class="LOG-META">24. Dez. 1942<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
</div>
|
||
|
||
<!-- canWrite: new document link -->
|
||
<div style="display:flex;align-items:center;justify-content:flex-end;padding:2px 0">
|
||
<a href="#" style="display:inline-flex;align-items:center;gap:4px;font-size:8.5px;font-weight:700;color:rgba(0,40,80,.5);text-decoration:none">
|
||
<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path></svg>
|
||
Neues Dokument in dieser Korrespondenz
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Asymmetry bar only appears in bilateral mode — hidden in single-person mode. Location shown in meta when present. Hover reveals "›" action chevron per row. Sender/recipient omitted from meta in bilateral mode (implicit).</div>
|
||
</div>
|
||
|
||
<!-- Mobile bilateral -->
|
||
<div class="sb">
|
||
<div class="sl">Mobile <span class="sz">375px</span> <span class="state st-active">Both selected</span></div>
|
||
<div style="display:flex;justify-content:center">
|
||
<div class="WF-M">
|
||
<div class="WF-M-STATUS"><span class="WF-M-TIME">09:41</span><div class="WF-M-ICONS"><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div></div></div>
|
||
<div class="N-M"><span class="logo" style="font-size:8.5px">FAMILIENARCHIV</span><span style="color:rgba(255,255,255,.7);font-size:17px">☰</span></div>
|
||
<!-- Mobile strip: stacked persons + swap row -->
|
||
<div class="STRIP-R1-SM">
|
||
<div style="display:flex;align-items:center;gap:7px">
|
||
<div class="FI set" style="flex:1;height:34px;font-size:8.5px"><div class="AV AV-xs AV-navy" style="margin-right:3px">OF</div>Otto F.</div>
|
||
<div class="SWAP on" style="width:24px;height:24px;flex-shrink:0;font-size:10px">⇄</div>
|
||
<div class="FI set" style="flex:1;height:34px;font-size:8.5px"><div class="AV AV-xs AV-outline" style="margin-right:3px">MW</div>Maria W.</div>
|
||
</div>
|
||
</div>
|
||
<div class="STRIP-R2-SM">
|
||
<div class="R2-DATE" style="width:55px;font-size:7.5px">Von…</div>
|
||
<div class="R2-DASH" style="font-size:9px">–</div>
|
||
<div class="R2-DATE" style="width:55px;font-size:7.5px">Bis…</div>
|
||
<div style="font-size:7.5px;color:#888;margin-left:auto;white-space:nowrap">32 Br.</div>
|
||
<div class="R2-SORT" style="font-size:7px;height:20px;padding:0 6px">Neu ↓</div>
|
||
</div>
|
||
<!-- Asym bar -->
|
||
<div class="ASYM" style="padding:6px 12px">
|
||
<div class="ASYM-LABELS" style="font-size:7px"><span class="s">28 von Otto →</span><span class="r">4 von Maria ←</span></div>
|
||
<div class="ASYM-BAR" style="height:4px"><div class="ASYM-OUT" style="width:87.5%"></div><div class="ASYM-IN" style="width:12.5%"></div></div>
|
||
</div>
|
||
<div class="MAIN-SM">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR" style="padding:4px 10px"><span class="LOG-YEAR-N" style="font-size:12px">1943</span><span class="LOG-YEAR-C">3</span></div>
|
||
<div class="LOG-ROW out" style="padding:8px 10px"><div class="LOG-DIR out" style="font-size:8px">→</div><div class="LOG-BODY"><div class="LOG-TITLE" style="font-size:8px">Brief — letzte Nachrichten</div><div class="LOG-META" style="font-size:7px">3. Sept. 1943<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW in" style="padding:8px 10px"><div class="LOG-DIR in" style="font-size:8px">←</div><div class="LOG-BODY"><div class="LOG-TITLE" style="font-size:8px">Marias Antwort</div><div class="LOG-META" style="font-size:7px">10. Sept. 1943<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-ROW out" style="padding:8px 10px"><div class="LOG-DIR out" style="font-size:8px">→</div><div class="LOG-BODY"><div class="LOG-TITLE" style="font-size:8px">Abschiedsbrief</div><div class="LOG-META" style="font-size:7px">28. Sept. 1943<div class="S-DOT S-TRANSCRIBED" style="margin-left:3px"></div></div></div></div>
|
||
<div class="LOG-YEAR" style="padding:4px 10px"><span class="LOG-YEAR-N" style="font-size:12px">1942</span><span class="LOG-YEAR-C">7</span></div>
|
||
<div class="LOG-ROW out" style="padding:8px 10px"><div class="LOG-DIR out" style="font-size:8px">→</div><div class="LOG-BODY"><div class="LOG-TITLE" style="font-size:8px">Brief aus dem Feld</div><div class="LOG-META" style="font-size:7px">14. März 1942<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Mobile: persons side-by-side (condensed names) with swap between. Row 2 compressed. Each log row ≥44px touch target. Full card tap → document detail.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════
|
||
SECTION 4 — BILATERAL WITH DATE FILTER
|
||
══════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h"><span class="sec-num">4</span> Bilateral + date filter active</div>
|
||
|
||
<div class="sg sg-2">
|
||
<div class="sb">
|
||
<div class="sl">Date range set <span class="state st-active">Filtered bilateral</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot r"></div><div class="dot y"></div><div class="dot g"></div><div class="urlbar"><span>/korrespondenz?senderId=otto-id&receiverId=maria-id&from=1921-01-01&to=1935-12-31&dir=ASC</span></div></div>
|
||
<div class="N"><span class="logo">FAMILIENARCHIV</span><span class="nl">Dokumente</span><span class="nl">Personen</span><span class="nl on">Korrespondenz</span><div class="nr"><div class="nico"></div></div></div>
|
||
<div class="STRIP-R1">
|
||
<div class="FIELD"><div class="FL">Person</div><div class="FI set"><div class="AV AV-xs AV-navy">OF</div>Otto Familienname</div></div>
|
||
<div class="SWAP on">⇄</div>
|
||
<div class="FIELD"><div class="FL">Korrespondent</div><div class="FI set"><div class="AV AV-xs AV-outline">MW</div>Maria Weber</div></div>
|
||
</div>
|
||
<div class="STRIP-R2">
|
||
<div class="R2-LABEL">Zeitraum</div>
|
||
<div class="R2-DATE set">01.01.1921</div>
|
||
<div class="R2-DASH">–</div>
|
||
<div class="R2-DATE set">31.12.1935</div>
|
||
<div class="R2-COUNT filtered" style="margin-left:auto">20 Briefe</div>
|
||
<div class="R2-SORT active">Älteste ↑</div>
|
||
</div>
|
||
<div class="ASYM">
|
||
<div class="ASYM-LABELS"><span class="s">18 von Otto →</span><span class="r">2 von Maria ←</span></div>
|
||
<div class="ASYM-BAR"><div class="ASYM-OUT" style="width:90%"></div><div class="ASYM-IN" style="width:10%"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="LOG">
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1921</span><span class="LOG-YEAR-C">8 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Brief an Maria — Reise nach Wien</div><div class="LOG-META">12. März 1921<span class="LOG-META-SEP">·</span>Wien<div class="S-DOT S-TRANSCRIBED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Nachricht zum Geburtstag</div><div class="LOG-META">4. April 1921<div class="S-DOT S-ARCHIVED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW in"><div class="LOG-DIR in">←</div><div class="LOG-BODY"><div class="LOG-TITLE">Marias Antwort auf Geburtstag</div><div class="LOG-META">10. April 1921<span class="LOG-META-SEP">·</span>Wien<div class="S-DOT S-REVIEWED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Bericht aus dem Büro</div><div class="LOG-META">22. Mai 1921<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
<div class="LOG-YEAR"><span class="LOG-YEAR-N">1922</span><span class="LOG-YEAR-C">12 Briefe</span></div>
|
||
<div class="LOG-ROW out"><div class="LOG-DIR out">→</div><div class="LOG-BODY"><div class="LOG-TITLE">Neujahrsgrüße 1922</div><div class="LOG-META">2. Jan. 1922<div class="S-DOT S-UPLOADED" style="margin-left:3px"></div></div></div><div class="LOG-ACTION">›</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Date inputs show the active range. Count updates to the filtered set (20, not 32). Sort label changes to "Älteste ↑". Asymmetry bar recalculates for the visible set.</div>
|
||
</div>
|
||
|
||
<!-- Annotation -->
|
||
<div class="sb" style="padding-top:40px">
|
||
<div class="ann-block">
|
||
<strong>Status dots — colour legend</strong>
|
||
<ul>
|
||
<li><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#F59E0B;margin-right:4px;vertical-align:middle"></span> PLACEHOLDER — Platzhalter, keine Datei</li>
|
||
<li><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#22C55E;margin-right:4px;vertical-align:middle"></span> UPLOADED — Datei vorhanden</li>
|
||
<li><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#3B82F6;margin-right:4px;vertical-align:middle"></span> TRANSCRIBED — Transkribiert</li>
|
||
<li><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#A855F7;margin-right:4px;vertical-align:middle"></span> REVIEWED — Überprüft</li>
|
||
<li><span style="display:inline-block;width:7px;height:7px;border-radius:50%;background:#6B7280;margin-right:4px;vertical-align:middle"></span> ARCHIVED — Archiviert</li>
|
||
</ul>
|
||
</div>
|
||
<div class="ann-block" style="margin-top:10px">
|
||
<strong>Direction border colours</strong>
|
||
<ul>
|
||
<li><span style="display:inline-block;width:4px;height:14px;background:#002850;margin-right:6px;vertical-align:middle;border-radius:1px"></span> Sent (→) — Navy #002850</li>
|
||
<li><span style="display:inline-block;width:4px;height:14px;background:#A6DAD8;margin-right:6px;vertical-align:middle;border-radius:1px"></span> Received (←) — Mint #A6DAD8</li>
|
||
</ul>
|
||
</div>
|
||
<div class="ann-block" style="margin-top:10px">
|
||
<strong>Row 2 behaviour rules</strong>
|
||
<ul>
|
||
<li>Always rendered in the DOM</li>
|
||
<li>Dimmed (opacity: 0.4) when no person is selected</li>
|
||
<li>Fully active as soon as any person is set</li>
|
||
<li>Count updates on every filter change via <code>documents.length</code></li>
|
||
<li>Sort button: click toggles <code>dir</code> param between ASC ↔ DESC</li>
|
||
<li>Date inputs: type or date picker; ISO sent in URL, German displayed</li>
|
||
</ul>
|
||
</div>
|
||
<div class="ann-block" style="margin-top:10px">
|
||
<strong>Asymmetry bar — when shown</strong>
|
||
<ul>
|
||
<li>Only rendered when both <code>senderId</code> and <code>receiverId</code> are set</li>
|
||
<li>Calculates from <code>documents</code> array: <code>filter(d => d.sender?.id === senderId).length</code></li>
|
||
<li>Hidden in single-person mode</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Correspondence Log <span>Real values · mockup above is ~55% scale</span></div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Log container</td>
|
||
<td><code>border border-line rounded-sm overflow-hidden bg-surface</code></td>
|
||
<td></td>
|
||
<td>White card wrapping year bands + rows</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Year band (.LOG-YEAR)</td>
|
||
<td><code>flex items-baseline gap-3 px-4 py-2 bg-muted border-b border-line border-t border-t-line-2</code></td>
|
||
<td><span class="ir-px">h ~40px, py 8px, px 16px</span></td>
|
||
<td>First year band: omit <code>border-t</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Year number</td>
|
||
<td><code>text-2xl font-bold text-ink leading-none</code></td>
|
||
<td><span class="ir-px">24px / 700</span></td>
|
||
<td>This is the most commonly undersized element — 24px minimum</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Year letter count</td>
|
||
<td><code>text-xs text-ink-3 font-medium</code></td>
|
||
<td><span class="ir-px">12px</span></td>
|
||
<td>"5 Briefe" — always visible next to year</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Log row (.LOG-ROW)</td>
|
||
<td><code>flex items-start gap-3 px-4 py-3 border-b border-line last:border-b-0 hover:bg-muted transition-colors cursor-pointer min-h-[44px] border-l-2</code></td>
|
||
<td><span class="ir-px">min 44px tall, py 12px, px 16px</span></td>
|
||
<td>Sent: <code>border-l-primary</code>. Received: <code>border-l-accent</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction arrow</td>
|
||
<td><code>text-sm font-black shrink-0 pt-0.5 w-4 text-center</code></td>
|
||
<td><span class="ir-px">14px / 900, 16px wide</span></td>
|
||
<td>Sent: <code>text-primary</code> "→". Received: <code>text-[#0F5755]</code> "←"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Row body</td>
|
||
<td><code>flex-1 min-w-0</code></td>
|
||
<td></td>
|
||
<td>Flex column inside: title + meta</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Document title</td>
|
||
<td><code>text-sm font-semibold text-ink leading-snug truncate</code></td>
|
||
<td><span class="ir-px">14px / 600</span></td>
|
||
<td>Single line, truncate with ellipsis on overflow</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Meta line (date · sender · status)</td>
|
||
<td><code>text-xs text-ink-2 mt-0.5 flex items-center gap-1.5</code></td>
|
||
<td><span class="ir-px">12px</span></td>
|
||
<td>Separator: <code>text-line</code>. Status dot: <code>w-2 h-2 rounded-full shrink-0</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Row action chevron</td>
|
||
<td><code>shrink-0 w-6 h-6 flex items-center justify-center border border-line bg-muted text-ink-3 opacity-0 group-hover:opacity-100 transition-opacity</code></td>
|
||
<td><span class="ir-px">24×24px</span></td>
|
||
<td>Add <code>group</code> to LOG-ROW; chevron fades in on hover</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Asymmetry bar container</td>
|
||
<td><code>px-4 sm:px-6 py-2 bg-canvas border-b border-line</code></td>
|
||
<td><span class="ir-px">py 8px</span></td>
|
||
<td>Only rendered when both senderId and receiverId are set</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Asymmetry bar track</td>
|
||
<td><code>h-1.5 rounded-full bg-line overflow-hidden flex mt-1</code></td>
|
||
<td><span class="ir-px">6px tall</span></td>
|
||
<td>Navy fill: <code>bg-primary</code>. Mint fill: <code>bg-accent</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Single-person hint bar</td>
|
||
<td><code>px-4 sm:px-6 py-2 bg-amber-50 border-b border-amber-200 text-xs font-medium text-amber-800 flex items-center gap-2</code></td>
|
||
<td><span class="ir-px">h ~36px, 12px text</span></td>
|
||
<td>Amber warning tone. Only when senderId set but no receiverId.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════
|
||
IMPLEMENTATION NOTES
|
||
══════════════════════════════════ -->
|
||
<div class="IMPL">
|
||
<h2>Implementation notes</h2>
|
||
<div class="IMPL-GRID">
|
||
<div class="IMPL-COL">
|
||
<h3>ConversationFilterBar.svelte</h3>
|
||
<ul>
|
||
<li>Replace the large <code>p-8</code> card with a two-row strip</li>
|
||
<li>Row 1: flex row, <code>border-bottom: 1px solid #EAE7E0</code>, <code>bg-white</code></li>
|
||
<li>Row 2: flex row, <code>bg-surface</code> (#F7F5F2), <code>border-bottom: 1.5px solid #E0DDD6</code></li>
|
||
<li>Row 2 always mounted; <code>opacity-40 pointer-events-none</code> when no person set</li>
|
||
<li>Receiver field: remove required validation, add dashed border style when empty</li>
|
||
<li>Suggestion dropdown: populate from <code>restrictToCorrespondentsOf</code> results when field focused + person A set</li>
|
||
<li>Add "Alle Korrespondenten" row at bottom of dropdown as explicit opt-out</li>
|
||
<li>Sort: click toggles <code>dir</code> via <code>ontoggleSort</code> — keep existing handler</li>
|
||
<li>Count: derived from <code>documents.length</code> passed as prop</li>
|
||
</ul>
|
||
</div>
|
||
<div class="IMPL-COL">
|
||
<h3>ConversationTimeline.svelte</h3>
|
||
<ul>
|
||
<li>Remove: central line div, chat bubble markup, left/right justify logic</li>
|
||
<li>Replace with: <code>LOG</code> container, <code>LOG-YEAR</code> bands, <code>LOG-ROW</code> cards</li>
|
||
<li>Direction: <code>isOut = doc.sender?.id === senderId</code> → navy border + "→" arrow</li>
|
||
<li>In bilateral mode: hide sender/recipient in meta (implicit). In single-person mode: show other party name</li>
|
||
<li>Asymmetry bar: new component or inline block, only when <code>senderId && receiverId</code></li>
|
||
<li>Summary bar: keep <code>data-testid="conv-summary"</code> but move count to Row 2 of filter strip</li>
|
||
<li>Keep <code>canWrite</code> new-document link — move to bottom of log list</li>
|
||
<li>Location in meta: show when <code>doc.location</code> is set</li>
|
||
<li>Status dot: map <code>doc.status</code> to dot colour (5 states)</li>
|
||
</ul>
|
||
</div>
|
||
<div class="IMPL-COL">
|
||
<h3>+page.svelte / +page.server.ts</h3>
|
||
<ul>
|
||
<li>Remove hard gate: <code>{#if !senderId || !receiverId}</code> block replaced with empty-state component + single-person mode support</li>
|
||
<li>Single-person API: when only <code>senderId</code> set, call <code>GET /api/documents</code> filtered by sender (or extend <code>/api/documents/conversation</code> to allow null receiver)</li>
|
||
<li>Recent persons: store last 3 visited person IDs in <code>localStorage</code>, resolve names on mount</li>
|
||
<li>Hint bar: show when <code>senderId && !receiverId</code></li>
|
||
<li>Page title: <code>m.conv_heading()</code> → update i18n key value to "Korrespondenz"</li>
|
||
<li>Nav label: update <code>+layout.svelte</code> nav link text key</li>
|
||
<li>Existing spec tests in <code>page.svelte.spec.ts</code>: update selectors for new log markup, add single-person mode tests</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|