Wireframe spec for the Persons section redesign (issue #157): - Enriched person cards with alias, life dates, document count - 2-column detail layout (person info sidebar + activity area) - Dedicated /persons/[id]/edit route with sticky save bar - Danger Zone accordion for merge (collapsed by default) - All fields on new person form (birth year, death year, notes) - Full coverage: list, detail, edit, new, edge cases, implementation notes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1646 lines
103 KiB
HTML
1646 lines
103 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Persons Section — Concept A Specification · 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:1560px;margin:0 auto;padding:48px 32px}
|
||
.doc-masthead{margin-bottom:56px;border-bottom:2px solid #C8C4BE;padding-bottom:28px}
|
||
.doc-masthead h1{font-size:26px;font-weight:800;color:#002850;letter-spacing:-.5px}
|
||
.doc-masthead p{margin-top:6px;color:#666;font-size:14px;max-width:680px;line-height:1.6}
|
||
.doc-masthead .meta{margin-top:10px;font-size:11px;color:#AAA;font-weight:600;letter-spacing:1px;text-transform:uppercase}
|
||
.section{margin-bottom:72px}
|
||
.section+.section{border-top:2px dashed #C8C4BE;padding-top:64px}
|
||
.sec-intro{display:flex;align-items:flex-start;gap:20px;margin-bottom:28px}
|
||
.sec-num{font-size:52px;font-weight:900;color:#DDD;line-height:1;flex-shrink:0;width:64px}
|
||
.sec-meta{}
|
||
.sec-badge{display:inline-block;font-size:10px;font-weight:800;padding:3px 10px;border-radius:20px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
|
||
.badge-arch{background:#F0F0F0;color:#555}
|
||
.badge-users{background:#E3EEFF;color:#1D4ED8}
|
||
.badge-persons{background:#E3EEFF;color:#1D4ED8}
|
||
.badge-groups{background:#E5F5EC;color:#15803D}
|
||
.badge-tags{background:#FEF3C7;color:#B45309}
|
||
.badge-system{background:#FEE2E2;color:#B91C1C}
|
||
.badge-edge{background:#F3E8FF;color:#7C3AED}
|
||
.sec-title{font-size:20px;font-weight:800;color:#002850;margin-bottom:4px}
|
||
.sec-tagline{font-size:13px;color:#666;max-width:620px;line-height:1.6}
|
||
.screens{display:flex;gap:20px;align-items:flex-start;margin-bottom:16px;flex-wrap:wrap}
|
||
.screens.cols2{display:grid;grid-template-columns:1fr 1fr;gap:20px}
|
||
.screens.cols3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
|
||
.screens.cols4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:14px}
|
||
.screen-block{display:flex;flex-direction:column;min-width:0}
|
||
.screen-label{font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:8px;display:flex;align-items:center;gap:8px}
|
||
.sz{background:#E8E4DF;color:#666;padding:1px 6px;border-radius:3px;font-size:9px}
|
||
.state-tag{padding:1px 7px;border-radius:3px;font-size:9px;font-weight:700;background:#DBEAFE;color:#1E40AF}
|
||
.state-tag.new{background:#DCFCE7;color:#166534}
|
||
.state-tag.edit{background:#FEF3C7;color:#92400E}
|
||
.state-tag.del{background:#FEE2E2;color:#991B1B}
|
||
.state-tag.empty{background:#F3F4F6;color:#374151}
|
||
.state-tag.err{background:#FEE2E2;color:#991B1B}
|
||
.state-tag.warn{background:#FEF3C7;color:#92400E}
|
||
.screen-cap{font-size:9px;color:#888;margin-top:6px;text-align:center;font-style:italic;line-height:1.5}
|
||
.wf{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.08);position:relative}
|
||
.wf-bar{height:26px;background:#E8E4DF;border-bottom:1px solid #C8C4BE;display:flex;align-items:center;padding:0 10px;gap:5px}
|
||
.dot{width:8px;height:8px;border-radius:50%;background:#C8C4BE}
|
||
.urlbar{flex:1;height:13px;background:#D8D4CE;border-radius:3px;margin-left:8px}
|
||
.NAV{height:44px;background:#0D2240;display:flex;align-items:center;padding:0 18px;gap:14px}
|
||
.NAV-m{height:46px;background:#0D2240;display:flex;align-items:center;padding:0 14px;justify-content:space-between}
|
||
.logo{font-size:10px;font-weight:900;color:#fff;letter-spacing:1px}
|
||
.nl{font-size:8px;color:rgba(255,255,255,.55);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:8px;align-items:center}
|
||
.nico{width:22px;height:22px;background:rgba(255,255,255,.12);border-radius:5px}
|
||
.nlang{font-size:8px;color:rgba(255,255,255,.5);font-weight:700;display:flex;gap:4px}
|
||
.nlang .on{color:#fff}
|
||
.EN{width:120px;background:#0D2240;flex-shrink:0;display:flex;flex-direction:column}
|
||
.EN-head{padding:10px 12px 6px;font-size:7.5px;font-weight:800;color:rgba(255,255,255,.3);text-transform:uppercase;letter-spacing:1px}
|
||
.EN-item{padding:11px 14px;display:flex;flex-direction:column;gap:3px;cursor:pointer;border-left:3px solid transparent;flex-shrink:0}
|
||
.EN-item.on{background:rgba(255,255,255,.1);border-left-color:#A6DAD8}
|
||
.EN-lbl{font-size:9px;font-weight:800;color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.5px}
|
||
.EN-item.on .EN-lbl{color:#fff}
|
||
.EN-cnt{font-size:13px;font-weight:900;color:rgba(255,255,255,.2)}
|
||
.EN-item.on .EN-cnt{color:rgba(255,255,255,.65)}
|
||
.EN-spacer{flex:1}
|
||
.EN-item.sys{border-top:1px solid rgba(255,255,255,.1);margin-top:auto}
|
||
.LP{width:240px;flex-shrink:0;border-right:1px solid #E0DDD6;display:flex;flex-direction:column;background:#F7F5F2}
|
||
.LP-head{padding:10px 14px;border-bottom:1px solid #E0DDD6;background:#F0EDE8;display:flex;align-items:center;justify-content:space-between}
|
||
.LP-title{font-size:10px;font-weight:800;color:#0D2240;text-transform:uppercase;letter-spacing:.5px}
|
||
.LP-search{margin:8px 10px 4px;height:28px;border:1.5px solid #D1D5DB;border-radius:5px;background:#fff;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px}
|
||
.LP-item{padding:9px 14px;border-bottom:1px solid #EAE7E2;cursor:pointer;display:flex;align-items:center;justify-content:space-between}
|
||
.LP-item:hover{background:#EEEAE5}
|
||
.LP-item.on{background:#EEF2FF;border-right:3px solid #002850}
|
||
.LP-name{font-size:10px;font-weight:700;color:#1A1A1A}
|
||
.LP-item.on .LP-name{color:#002850}
|
||
.LP-sub{font-size:8px;color:#999;margin-top:1px}
|
||
.LP-item.on .LP-sub{color:#7B9FD4}
|
||
.LP-chev{font-size:11px;color:#CCC}
|
||
.LP-item.on .LP-chev{color:#002850}
|
||
.LP-empty{padding:24px 14px;text-align:center;font-size:9px;color:#BBB;font-style:italic}
|
||
.DP{flex:1;display:flex;flex-direction:column;min-width:0;background:#fff}
|
||
.DP-head{padding:14px 20px;border-bottom:1px solid #E8E4DF;background:#F7F5F2;display:flex;align-items:flex-start;justify-content:space-between;flex-shrink:0}
|
||
.DP-title{font-size:14px;font-weight:800;color:#0D2240}
|
||
.DP-sub{font-size:9px;color:#888;margin-top:2px}
|
||
.DP-body{padding:16px 20px;flex:1;display:flex;flex-direction:column;gap:0;overflow:hidden}
|
||
.DP-empty{flex:1;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;padding:32px}
|
||
.DP-empty-icon{font-size:32px;opacity:.2}
|
||
.DP-empty-msg{font-size:11px;color:#AAA;text-align:center;line-height:1.6}
|
||
.DP-footer{background:#fff;border-top:1.5px solid #E8E4DF;padding:10px 20px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;box-shadow:0 -2px 8px rgba(0,0,0,.05)}
|
||
.BODY{display:flex;min-height:0;flex:1}
|
||
.BTN{display:inline-flex;align-items:center;gap:4px;font-size:8px;font-weight:800;padding:5px 10px;border-radius:4px;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;white-space:nowrap}
|
||
.BTN-sm{font-size:7.5px;padding:3px 8px}
|
||
.BTN-xs{font-size:7px;padding:2px 6px}
|
||
.BTN-primary{background:#002850;color:#fff}
|
||
.BTN-outline{border:1.5px solid #002850;color:#002850;background:transparent}
|
||
.BTN-ghost{color:#777;background:transparent}
|
||
.BTN-danger{border:1.5px solid #DC2626;color:#DC2626;background:#FEF2F2}
|
||
.BTN-danger-fill{background:#DC2626;color:#fff}
|
||
.BTN-warn{background:#D97706;color:#fff}
|
||
.BTN-green{background:#15803D;color:#fff}
|
||
.BTN-amber{border:1.5px solid #D97706;color:#D97706;background:#FFFBEB}
|
||
.FG{margin-bottom:10px}
|
||
.FG-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px}
|
||
.FG-row3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:10px}
|
||
.FL{display:block;font-size:8px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;margin-bottom:3px}
|
||
.FL .req{color:#DC2626}
|
||
.FI{width:100%;height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB}
|
||
.FI.focus{border-color:#002850;background:#fff;box-shadow:0 0 0 3px rgba(0,40,80,.07)}
|
||
.FI.filled{display:flex;align-items:center;padding:0 8px;font-size:9px;color:#333}
|
||
.FTA{width:100%;height:52px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB}
|
||
.FTA.filled{padding:6px 8px;font-size:9px;color:#333;line-height:1.4}
|
||
.FI.err{border-color:#DC2626;background:#FFF5F5}
|
||
.ferr{font-size:8px;color:#DC2626;margin-top:2px}
|
||
.SH{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px;padding:10px 0 6px;border-top:1px solid #F0EDE6;margin-top:4px}
|
||
.SH:first-child{border-top:none;margin-top:0;padding-top:0}
|
||
.CH{display:inline-flex;align-items:center;font-size:7.5px;font-weight:800;padding:2px 6px;border-radius:10px;text-transform:uppercase;letter-spacing:.3px}
|
||
.CH+.CH{margin-left:3px}
|
||
.CH-blue{background:#DBEAFE;color:#1E40AF;border:1px solid #BFDBFE}
|
||
.CH-red{background:#FEE2E2;color:#991B1B;border:1px solid #FCA5A5}
|
||
.CH-green{background:#DCFCE7;color:#166534;border:1px solid #BBF7D0}
|
||
.CH-grey{background:#F3F4F6;color:#374151;border:1px solid #E5E7EB}
|
||
.CH-warn{background:#FEF3C7;color:#92400E;border:1px solid #FDE68A}
|
||
.CH-amber{background:#FEF9C3;color:#854D0E;border:1px solid #FEF08A}
|
||
.CH-navy{background:#EEF2FF;color:#002850;border:1px solid #C7D2FE}
|
||
.CH-mint{background:#D6F0EE;color:#0F5B58;border:1px solid #A6DAD8}
|
||
.AL{padding:8px 10px;border-radius:5px;font-size:9px;line-height:1.5}
|
||
.AL-warn{background:#FFFBEB;border:1px solid #FDE68A;color:#92400E}
|
||
.AL-info{background:#EFF6FF;border:1px solid #BFDBFE;color:#1E40AF}
|
||
.AL-err{background:#FEF2F2;border:1px solid #FCA5A5;color:#991B1B}
|
||
.AL-ok{background:#F0FDF4;border:1px solid #BBF7D0;color:#166534}
|
||
.DZ{border:1.5px solid #FCA5A5;border-radius:6px;padding:12px 14px;margin-top:4px;background:#FFF5F5}
|
||
.DZ-title{font-size:10px;font-weight:800;color:#991B1B;margin-bottom:4px;display:flex;align-items:center;gap:5px}
|
||
.DZ-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:8px}
|
||
.DZ-confirm{background:#FEE2E2;border:1.5px solid #FCA5A5;border-radius:4px;padding:8px 10px;margin-top:6px}
|
||
.DZ-confirm-msg{font-size:9px;color:#7F1D1D;font-weight:600;margin-bottom:6px}
|
||
.SC{border:1.5px solid #E8E4DF;border-radius:6px;padding:12px 14px;margin-bottom:10px}
|
||
.SC.warn{border-color:#FDE68A;background:#FFFBEB}
|
||
.SC.danger{border-color:#FCA5A5;background:#FFF5F5}
|
||
.SC-title{font-size:11px;font-weight:800;color:#1A1A1A;margin-bottom:3px;display:flex;align-items:center;gap:6px}
|
||
.SC-badge{font-size:7.5px;padding:1px 5px;border-radius:3px;font-weight:800;text-transform:uppercase}
|
||
.SC.warn .SC-badge{background:#FDE68A;color:#92400E}
|
||
.SC.danger .SC-badge{background:#FCA5A5;color:#7F1D1D}
|
||
.SC-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:10px}
|
||
.IB{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:5px;font-size:13px;border:1px solid #E8E4DF;background:#fff;color:#666;cursor:pointer}
|
||
.IB.edit{color:#2563EB;border-color:#BFDBFE;background:#EFF6FF}
|
||
.IB.del{color:#DC2626;border-color:#FCA5A5;background:#FEF2F2}
|
||
.DECISION{background:#F0F7FF;border:1.5px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin:16px 0}
|
||
.DECISION-title{font-size:10px;font-weight:800;color:#1E40AF;text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px;display:flex;align-items:center;gap:6px}
|
||
.DECISION ul{display:flex;flex-direction:column;gap:4px;padding-left:0}
|
||
.DECISION li{font-size:11px;color:#1E3A5F;line-height:1.5;list-style:none;padding-left:14px;position:relative}
|
||
.DECISION li::before{content:'→';position:absolute;left:0;color:#60A5FA}
|
||
.SPEC{background:#fff;border:1px solid #E8E4DF;border-radius:8px;padding:16px;margin-top:16px}
|
||
.SPEC-title{font-size:10px;font-weight:800;color:#555;text-transform:uppercase;letter-spacing:1px;margin-bottom:10px}
|
||
.SPEC-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
||
.SPEC-col{}
|
||
.SPEC-rule{margin-bottom:8px}
|
||
.SPEC-rule-num{font-size:9px;font-weight:800;color:#002850;margin-bottom:2px}
|
||
.SPEC-rule-text{font-size:11px;color:#444;line-height:1.5}
|
||
.SPEC-rule-code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px;color:#1A1A1A}
|
||
.BP-table{width:100%;border-collapse:collapse;font-size:11px;margin-top:8px}
|
||
.BP-table th{text-align:left;padding:8px 12px;font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #E8E4DF;background:#F7F5F2}
|
||
.BP-table td{padding:8px 12px;border-bottom:1px solid #F0EDE6;color:#444;vertical-align:top}
|
||
.BP-table tr:last-child td{border-bottom:none}
|
||
.BP-table code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px}
|
||
.SUM-table{width:100%;border-collapse:collapse;font-size:11px}
|
||
.SUM-table th{text-align:left;padding:9px 14px;font-size:10px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #E8E4DF;background:#F7F5F2}
|
||
.SUM-table td{padding:8px 14px;border-bottom:1px solid #F0EDE6;color:#444;vertical-align:middle}
|
||
.SUM-table tr:nth-child(even) td{background:#FAFAF7}
|
||
.PH{height:8px;background:#E8E4DF;border-radius:3px;margin-bottom:5px}
|
||
.PH.w30{width:30%}.PH.w50{width:50%}.PH.w70{width:70%}.PH.w40{width:40%}.PH.w60{width:60%}
|
||
.URL-LINE{background:#F0EDE8;border:1px solid #DDD8D0;border-radius:4px;padding:4px 10px;font-size:9px;font-family:monospace;color:#555;margin-bottom:8px}
|
||
.URL-LINE span.qs{color:#1D4ED8}
|
||
.DECISION{background:#F0F7FF;border:1.5px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin:16px 0}
|
||
.mobile-flow{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap}
|
||
.mobile-step{display:flex;flex-direction:column;align-items:center;gap:4px}
|
||
.mobile-step-label{font-size:8px;color:#888;font-style:italic;text-align:center}
|
||
.mobile-arrow{font-size:20px;color:#CCC;align-self:center;margin-top:36px}
|
||
.wf-m{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 16px rgba(0,0,0,.08);position:relative;width:155px}
|
||
code{font-size:10px;font-family:monospace;background:#F3F4F6;padding:1px 4px;border-radius:2px;color:#1A1A1A}
|
||
|
||
/* ── Persons-specific ── */
|
||
.MAIN{flex:1;padding:16px 20px;overflow:hidden;display:flex;flex-direction:column;gap:12px;min-width:0}
|
||
.MAIN-wide{flex:1;padding:20px 28px;overflow:hidden;display:flex;flex-direction:column;gap:14px;min-width:0}
|
||
|
||
/* Stats bar */
|
||
.STATS-BAR{display:flex;align-items:center;gap:16px;padding:8px 0 4px}
|
||
.STATS-BAR-item{display:flex;align-items:baseline;gap:5px}
|
||
.STATS-BAR-val{font-size:15px;font-weight:900;color:#002850;line-height:1}
|
||
.STATS-BAR-label{font-size:8px;color:#AAA;text-transform:uppercase;letter-spacing:.5px}
|
||
.STATS-BAR-sep{font-size:12px;color:#D1D5DB;font-weight:300}
|
||
|
||
/* Person grid */
|
||
.PERSON-GRID{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
|
||
.PERSON-GRID-2{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
|
||
|
||
/* Person card in grid */
|
||
.PG-card{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:14px 12px;display:flex;flex-direction:column;align-items:center;gap:7px;cursor:pointer;position:relative;transition:box-shadow .15s}
|
||
.PG-card:hover{box-shadow:0 2px 12px rgba(0,0,0,.09);border-color:#A6DAD8;border-left:3px solid #A6DAD8}
|
||
.PG-initials{width:48px;height:48px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:800;color:#fff;flex-shrink:0;font-family:Georgia,serif}
|
||
.PG-name{font-size:10px;font-weight:700;color:#1A1A1A;text-align:center;font-family:Georgia,serif}
|
||
.PG-alias{font-size:8.5px;color:#888;font-style:italic;text-align:center}
|
||
.PG-dates{font-size:8px;color:#AAA;text-align:center}
|
||
.PG-doccount{font-size:7.5px;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:10px;padding:2px 7px;color:#666}
|
||
|
||
/* Detail layout */
|
||
.DETAIL-LAYOUT{display:grid;grid-template-columns:35fr 65fr;gap:20px;align-items:start}
|
||
.DETAIL-LAYOUT-stacked{display:flex;flex-direction:column;gap:16px}
|
||
|
||
/* Person card (detail sidebar) */
|
||
.PERSON-CARD{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.05)}
|
||
.PERSON-CARD-topbar{height:4px;background:#002850}
|
||
.PERSON-CARD-body{padding:20px 16px}
|
||
.PC-avatar{width:64px;height:64px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:800;color:#fff;font-family:Georgia,serif;margin:0 auto 12px}
|
||
.PC-avatar-lg{width:80px;height:80px;font-size:26px}
|
||
.PC-name{font-size:15px;font-weight:800;color:#0D2240;text-align:center;font-family:Georgia,serif;line-height:1.3;margin-bottom:3px}
|
||
.PC-alias{font-size:10px;color:#888;font-style:italic;text-align:center;margin-bottom:6px}
|
||
.PC-dates{font-size:9px;color:#666;text-align:center;margin-bottom:10px}
|
||
.PC-notes-label{font-size:7.5px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1px;margin-bottom:3px}
|
||
.PC-notes{font-size:9px;color:#555;line-height:1.5;background:#F9FAFB;border-radius:4px;padding:8px;border:1px solid #F0EDE6;margin-bottom:12px}
|
||
|
||
/* Activity area */
|
||
.ACTIVITY{display:flex;flex-direction:column;gap:14px}
|
||
.ACT-section{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:14px 16px}
|
||
.ACT-section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
|
||
.ACT-title{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px}
|
||
.ACT-badge{font-size:8px;font-weight:800;background:#EEF2FF;color:#002850;border-radius:10px;padding:1px 7px}
|
||
|
||
/* Document row */
|
||
.DOC-ROW{display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid #F0EDE6}
|
||
.DOC-ROW:last-child{border-bottom:none}
|
||
.DOC-ROW-icon{width:22px;height:26px;background:#E8E4DF;border-radius:3px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:9px;color:#888}
|
||
.DOC-ROW-icon.sent{background:#EEF2FF;color:#002850}
|
||
.DOC-ROW-icon.recv{background:#D6F0EE;color:#0F5B58}
|
||
.DOC-ROW-title{font-size:9px;font-weight:600;color:#1A1A1A;flex:1;line-height:1.3}
|
||
.DOC-ROW-meta{font-size:8px;color:#AAA;flex-shrink:0}
|
||
.DOC-ROW-status{}
|
||
|
||
/* Correspondent chip */
|
||
.CORR-chip{display:inline-flex;align-items:center;gap:5px;background:#F7F5F2;border:1px solid #E0DDD6;border-radius:20px;padding:4px 10px;font-size:8.5px;font-weight:700;color:#333;cursor:pointer}
|
||
.CORR-chip:hover{background:#EEF2FF;border-color:#A6DAD8}
|
||
.CORR-av{width:16px;height:16px;background:#002850;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:5.5px;color:#fff;font-weight:800;font-family:Georgia,serif;flex-shrink:0}
|
||
.CORR-count{font-size:7.5px;color:#999}
|
||
|
||
/* Sticky save bar */
|
||
.SAVE-BAR{background:#fff;border-top:1.5px solid #E8E4DF;padding:10px 20px;display:flex;align-items:center;justify-content:space-between;box-shadow:0 -2px 8px rgba(0,0,0,.06);flex-shrink:0}
|
||
|
||
/* Back link */
|
||
.BACK-LINK{font-size:8px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:.5px;display:inline-flex;align-items:center;gap:5px;margin-bottom:10px;cursor:pointer}
|
||
.BACK-LINK:hover{color:#002850}
|
||
.BACK-ARROW{font-size:11px}
|
||
|
||
/* Empty dashed box */
|
||
.EMPTY-BOX{border:2px dashed #D1D5DB;border-radius:8px;padding:28px 16px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:8px}
|
||
.EMPTY-ICON{font-size:28px;opacity:.2}
|
||
.EMPTY-MSG{font-size:10px;color:#AAA;line-height:1.5}
|
||
.EMPTY-CTA{font-size:8px;font-weight:800;background:#002850;color:#fff;padding:5px 12px;border-radius:4px;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;margin-top:4px}
|
||
|
||
/* Danger zone accordion */
|
||
.DZ-ACCORD{border:1.5px solid #FCA5A5;border-radius:6px;overflow:hidden;margin-top:16px}
|
||
.DZ-ACCORD-head{padding:10px 14px;background:#FFF5F5;display:flex;align-items:center;justify-content:space-between;cursor:pointer}
|
||
.DZ-ACCORD-label{font-size:9px;font-weight:800;color:#991B1B;text-transform:uppercase;letter-spacing:.5px;display:flex;align-items:center;gap:6px}
|
||
.DZ-ACCORD-chev{font-size:11px;color:#FCA5A5}
|
||
.DZ-ACCORD-body{border-top:1px solid #FCA5A5;padding:12px 14px;background:#fff}
|
||
.DZ-ACCORD-desc{font-size:8.5px;color:#777;line-height:1.5;margin-bottom:10px}
|
||
|
||
/* Search result count */
|
||
.RESULT-COUNT{font-size:9px;color:#888;font-style:italic}
|
||
|
||
/* Page heading area */
|
||
.PAGE-HDR{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:8px}
|
||
.PAGE-TITLE{font-size:14px;font-weight:800;color:#0D2240}
|
||
.PAGE-SUB{font-size:9px;color:#999;margin-top:2px}
|
||
.FORM-CARD{background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:16px 18px;margin-bottom:14px}
|
||
.FORM-CARD-title{font-size:8px;font-weight:800;color:#AAA;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:12px}
|
||
|
||
/* Section divider */
|
||
.SEC-DIV{border:none;border-top:1px solid #F0EDE6;margin:10px 0}
|
||
|
||
/* Show more link */
|
||
.SHOW-MORE{font-size:8.5px;color:#002850;font-weight:700;text-align:center;padding:6px 0;cursor:pointer;display:block;border-top:1px solid #F0EDE6;margin-top:2px}
|
||
.SHOW-MORE:hover{color:#1D4ED8}
|
||
|
||
/* Sort toggle */
|
||
.SORT-TOGGLE{font-size:7.5px;color:#888;font-weight:700;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:3px;padding:1px 5px;cursor:pointer}
|
||
|
||
/* Unsaved banner */
|
||
.UNSAVED-BANNER{background:#FFFBEB;border:1.5px solid #FDE68A;border-radius:6px;padding:8px 12px;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}
|
||
.UNSAVED-MSG{font-size:9px;color:#92400E;font-weight:600}
|
||
|
||
/* Save error banner */
|
||
.ERR-BANNER{background:#FEF2F2;border:1.5px solid #FCA5A5;border-radius:6px;padding:8px 12px;margin-bottom:10px}
|
||
.ERR-BANNER-msg{font-size:9px;color:#991B1B;font-weight:600}
|
||
|
||
/* Typeahead field */
|
||
.TYPEAHEAD{position:relative}
|
||
.TYPEAHEAD-INPUT{width:100%;height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic}
|
||
.TYPEAHEAD-INPUT.focus{border-color:#002850}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="doc">
|
||
|
||
<!-- HEADER -->
|
||
<div class="doc-masthead">
|
||
<h1>Persons Section — Concept A: Enriched Directory</h1>
|
||
<p>Complete developer-ready screen spec for the Persons section redesign. Covers the person list, detail view (2-column layout), edit form (dedicated route), new person form, and all edge cases. Every screen, state, and entity is specified. A developer should be able to implement the full feature from this spec alone.</p>
|
||
<div class="meta">Familienarchiv · Persons Spec · Concept A · v1.0 · 2026-03</div>
|
||
</div>
|
||
|
||
<!-- S0 ARCHITECTURE -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">0</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-arch">Architecture</span>
|
||
<div class="sec-title">Routes, Layout Model & Breakpoints</div>
|
||
<div class="sec-tagline">Four routes. 2-column detail layout on desktop. Dedicated edit route with sticky save bar. Merge panel hidden in Danger Zone accordion.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screens cols2" style="margin-bottom:24px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">Route map</div>
|
||
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden">
|
||
<table class="SUM-table">
|
||
<thead><tr><th>Route</th><th>Purpose</th><th>Key state</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><code>/persons</code></td><td>Person directory — 4-column grid, search, stats bar</td><td>search query param</td></tr>
|
||
<tr><td><code>/persons/new</code></td><td>Create new person — all 6 fields</td><td>form validation</td></tr>
|
||
<tr><td><code>/persons/[id]</code></td><td>Person detail — 2-col layout, activity area</td><td>person id in path</td></tr>
|
||
<tr><td><code>/persons/[id]/edit</code></td><td>Edit form — sticky save bar, Danger Zone accordion</td><td>dirty state, merge</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="screen-block">
|
||
<div class="screen-label">Breakpoint behaviour</div>
|
||
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden">
|
||
<table class="BP-table">
|
||
<thead><tr><th>Viewport</th><th>List layout</th><th>Detail layout</th><th>Edit layout</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><code><640px</code> Mobile</td><td>1-col list</td><td>Stacked single col</td><td>Full-page form</td></tr>
|
||
<tr><td><code>640–1023px</code> Tablet</td><td>2-col grid</td><td>Stacked single col</td><td>Full-page form</td></tr>
|
||
<tr><td><code>≥1024px</code> Desktop</td><td>4-col grid</td><td>2-col sidebar+main</td><td>Full-page form</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Layout diagram -->
|
||
<div class="screens" style="margin-bottom:24px">
|
||
<div class="screen-block" style="flex:1">
|
||
<div class="screen-label">2-column detail layout anatomy <span class="sz">≥1024px</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide" style="height:300px">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to overview</div>
|
||
<div style="display:grid;grid-template-columns:35fr 65fr;gap:20px;align-items:start">
|
||
<!-- Sidebar annotation -->
|
||
<div style="position:relative">
|
||
<div style="position:absolute;top:-20px;left:0;right:0;text-align:center;font-size:8px;font-weight:800;color:#1D4ED8;background:#E3EEFF;border-radius:3px;padding:2px 4px">PERSON CARD · 35%</div>
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body">
|
||
<div class="PC-avatar">OF</div>
|
||
<div class="PC-name">Otto Fischer</div>
|
||
<div class="PC-alias">„Großvater Otto"</div>
|
||
<div class="PC-dates">✦ 1882 † 1944</div>
|
||
<div style="margin-top:8px">
|
||
<div class="PC-notes-label">Notes</div>
|
||
<div class="PC-notes">Patriarchal figure of the Fischer family…</div>
|
||
</div>
|
||
<div style="text-align:center"><div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center">Edit person</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Activity annotation -->
|
||
<div style="position:relative">
|
||
<div style="position:absolute;top:-20px;left:0;right:0;text-align:center;font-size:8px;font-weight:800;color:#B45309;background:#FEF3C7;border-radius:3px;padding:2px 4px">ACTIVITY AREA · 65%</div>
|
||
<div class="ACTIVITY">
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head"><div class="ACT-title">Frequent Correspondents</div></div>
|
||
<div style="display:flex;gap:6px;flex-wrap:wrap">
|
||
<div class="CORR-chip"><div class="CORR-av">HM</div>Hans Müller <span class="CORR-count">×4</span></div>
|
||
<div class="CORR-chip"><div class="CORR-av">AS</div>Anna Schmidt <span class="CORR-count">×2</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="ACT-section" style="padding-bottom:6px">
|
||
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">5</div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon sent">▤</div><div class="DOC-ROW-title">Brief an den König</div><div class="DOC-ROW-meta">12 Nov 1938</div><div class="CH CH-navy" style="font-size:7px;margin-left:5px">Uploaded</div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon sent">▤</div><div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div><div class="DOC-ROW-meta">3 Mar 1922</div><div class="CH CH-green" style="font-size:7px;margin-left:5px">Archived</div></div>
|
||
<div class="SHOW-MORE">Show 3 more…</div>
|
||
</div>
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">3</div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon recv">▤</div><div class="DOC-ROW-title">Scan ohne Titel</div><div class="DOC-ROW-meta">25 Nov 1938</div><div class="CH CH-warn" style="font-size:7px;margin-left:5px">Scan pending</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="DECISION">
|
||
<div class="DECISION-title">📐 Key design decisions</div>
|
||
<ul>
|
||
<li>Edit moved to <code>/persons/[id]/edit</code> — removes in-place toggle; PersonCard is view-only; edit state no longer lives in $state on the detail page.</li>
|
||
<li>Merge panel moved inside a collapsible Danger Zone accordion at the bottom of the edit page — reduces cognitive load on the detail view.</li>
|
||
<li>"Full Name" label removed from view mode — the <h1> / PC-name already shows the name; duplicate removed per audit finding.</li>
|
||
<li>Stats bar on list page: <code>persons.length</code> + <code>totalDocs</code> — requires <code>documentCount</code> field on PersonDTO (or computed client-side from separate query).</li>
|
||
<li>New person form gains birth year, death year, notes — brings parity with edit form.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S1 PERSON LIST -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">1</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-persons">List</span>
|
||
<div class="sec-title">Person Directory <code style="font-size:14px">/persons</code></div>
|
||
<div class="sec-tagline">4-column card grid on desktop. Stats bar. Search. Each card shows initials circle, full name, alias, life dates, doc count chip. Hover: mint left-border + shadow.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 1A Desktop full list -->
|
||
<div class="screens" style="margin-bottom:24px">
|
||
<div class="screen-block" style="flex:1">
|
||
<div class="screen-label">1-A · Desktop full list <span class="sz">1440px</span> <span class="state-tag">default</span></div>
|
||
<div class="URL-LINE">/persons</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<!-- Header row -->
|
||
<div class="PAGE-HDR">
|
||
<div>
|
||
<div class="PAGE-TITLE">Persons</div>
|
||
<div class="STATS-BAR">
|
||
<div class="STATS-BAR-item"><div class="STATS-BAR-val">4</div><div class="STATS-BAR-label">Persons</div></div>
|
||
<div class="STATS-BAR-sep">·</div>
|
||
<div class="STATS-BAR-item"><div class="STATS-BAR-val">14</div><div class="STATS-BAR-label">Documents</div></div>
|
||
</div>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<div style="width:180px;height:28px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px">🔍 Search persons…</div>
|
||
<div class="BTN BTN-primary">+ New person</div>
|
||
</div>
|
||
</div>
|
||
<!-- Grid -->
|
||
<div class="PERSON-GRID" style="padding-bottom:16px">
|
||
<!-- Card 1 - Otto Fischer -->
|
||
<div class="PG-card" style="border-left:3px solid #A6DAD8;box-shadow:0 2px 12px rgba(0,0,0,.09)">
|
||
<div class="PG-initials">OF</div>
|
||
<div class="PG-name">Otto Fischer</div>
|
||
<div class="PG-alias">„Großvater Otto"</div>
|
||
<div class="PG-dates">✦ 1882 · † 1944</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
<!-- Card 2 - Hans Müller -->
|
||
<div class="PG-card">
|
||
<div class="PG-initials">HM</div>
|
||
<div class="PG-name">Hans Müller</div>
|
||
<div class="PG-dates">✦ 1890 · † 1962</div>
|
||
<div class="PG-doccount">2 docs</div>
|
||
</div>
|
||
<!-- Card 3 - Anna Schmidt -->
|
||
<div class="PG-card">
|
||
<div class="PG-initials">AS</div>
|
||
<div class="PG-name">Anna Schmidt</div>
|
||
<div class="PG-alias">„Oma Anna"</div>
|
||
<div class="PG-dates">✦ 1905</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
<!-- Card 4 - Maria Weber -->
|
||
<div class="PG-card">
|
||
<div class="PG-initials">MW</div>
|
||
<div class="PG-name">Maria Weber</div>
|
||
<div class="PG-dates" style="color:#D1D5DB;font-style:italic">no dates</div>
|
||
<div class="PG-doccount">1 doc</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Card 1 shown in hover state (mint left border + shadow). No alias shown for Hans Müller and Maria Weber — those fields are simply omitted when empty. "no dates" placeholder shown in muted italic when both fields absent.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 1B Tablet + Mobile side by side -->
|
||
<div class="screens cols2" style="margin-bottom:24px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">1-B · Tablet <span class="sz">768px</span></div>
|
||
<div class="URL-LINE">/persons</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nr"><div class="nico"></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="PAGE-HDR">
|
||
<div>
|
||
<div class="PAGE-TITLE" style="font-size:12px">Persons</div>
|
||
<div class="STATS-BAR" style="gap:10px">
|
||
<div class="STATS-BAR-item"><div class="STATS-BAR-val" style="font-size:13px">4</div><div class="STATS-BAR-label">Persons</div></div>
|
||
<div class="STATS-BAR-sep">·</div>
|
||
<div class="STATS-BAR-item"><div class="STATS-BAR-val" style="font-size:13px">14</div><div class="STATS-BAR-label">Docs</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="BTN BTN-primary BTN-sm">+ New</div>
|
||
</div>
|
||
<div style="height:26px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:9px;color:#AAA;font-style:italic;gap:4px;margin-bottom:10px">🔍 Search persons…</div>
|
||
<div class="PERSON-GRID-2">
|
||
<div class="PG-card">
|
||
<div class="PG-initials">OF</div>
|
||
<div class="PG-name">Otto Fischer</div>
|
||
<div class="PG-alias">„Großvater Otto"</div>
|
||
<div class="PG-dates">✦ 1882 · † 1944</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
<div class="PG-card">
|
||
<div class="PG-initials">HM</div>
|
||
<div class="PG-name">Hans Müller</div>
|
||
<div class="PG-dates">✦ 1890 · † 1962</div>
|
||
<div class="PG-doccount">2 docs</div>
|
||
</div>
|
||
<div class="PG-card">
|
||
<div class="PG-initials">AS</div>
|
||
<div class="PG-name">Anna Schmidt</div>
|
||
<div class="PG-alias">„Oma Anna"</div>
|
||
<div class="PG-dates">✦ 1905</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
<div class="PG-card">
|
||
<div class="PG-initials">MW</div>
|
||
<div class="PG-name">Maria Weber</div>
|
||
<div class="PG-dates" style="color:#D1D5DB;font-style:italic">no dates</div>
|
||
<div class="PG-doccount">1 doc</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-block">
|
||
<div class="screen-label">1-C · Mobile <span class="sz">375px</span></div>
|
||
<div class="URL-LINE">/persons</div>
|
||
<div class="wf" style="max-width:260px">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN" style="padding:12px">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">
|
||
<div>
|
||
<div class="PAGE-TITLE" style="font-size:11px">Persons</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">4 persons · 14 docs</div>
|
||
</div>
|
||
<div class="BTN BTN-primary BTN-xs">+ New</div>
|
||
</div>
|
||
<div style="height:24px;border:1.5px solid #D1D5DB;border-radius:4px;background:#F9FAFB;display:flex;align-items:center;padding:0 8px;font-size:8px;color:#AAA;font-style:italic;gap:4px;margin-bottom:8px">🔍 Search…</div>
|
||
<!-- Mobile: 1-col list style cards -->
|
||
<div style="display:flex;flex-direction:column;gap:6px">
|
||
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
|
||
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">OF</div>
|
||
<div style="flex:1;min-width:0">
|
||
<div class="PG-name" style="text-align:left">Otto Fischer</div>
|
||
<div class="PG-alias" style="text-align:left;margin-top:1px">„Großvater Otto"</div>
|
||
<div style="display:flex;gap:8px;margin-top:2px">
|
||
<div class="PG-dates" style="text-align:left">✦ 1882 · † 1944</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:12px;color:#CCC">›</div>
|
||
</div>
|
||
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
|
||
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">HM</div>
|
||
<div style="flex:1;min-width:0">
|
||
<div class="PG-name" style="text-align:left">Hans Müller</div>
|
||
<div style="display:flex;gap:8px;margin-top:2px">
|
||
<div class="PG-dates" style="text-align:left">✦ 1890 · † 1962</div>
|
||
<div class="PG-doccount">2 docs</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:12px;color:#CCC">›</div>
|
||
</div>
|
||
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
|
||
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">AS</div>
|
||
<div style="flex:1;min-width:0">
|
||
<div class="PG-name" style="text-align:left">Anna Schmidt</div>
|
||
<div class="PG-alias" style="text-align:left;margin-top:1px">„Oma Anna"</div>
|
||
<div style="display:flex;gap:8px;margin-top:2px">
|
||
<div class="PG-dates" style="text-align:left">✦ 1905</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:12px;color:#CCC">›</div>
|
||
</div>
|
||
<div style="background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:10px 12px;display:flex;align-items:center;gap:10px;cursor:pointer">
|
||
<div class="PG-initials" style="width:36px;height:36px;font-size:11px;flex-shrink:0">MW</div>
|
||
<div style="flex:1;min-width:0">
|
||
<div class="PG-name" style="text-align:left">Maria Weber</div>
|
||
<div style="display:flex;gap:8px;margin-top:2px">
|
||
<div class="PG-doccount">1 doc</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:12px;color:#CCC">›</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Mobile: cards switch to horizontal row layout (initials left, text right, chevron right). Touch-friendly min-height. No centered text.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 1D Empty state + 1E Search -->
|
||
<div class="screens cols2" style="margin-bottom:16px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">1-D · Empty state <span class="sz">desktop</span> <span class="state-tag empty">empty</span></div>
|
||
<div class="URL-LINE">/persons</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="PAGE-HDR" style="margin-bottom:20px">
|
||
<div>
|
||
<div class="PAGE-TITLE">Persons</div>
|
||
<div style="font-size:9px;color:#AAA;margin-top:2px">0 persons · 0 documents</div>
|
||
</div>
|
||
<div class="BTN BTN-primary">+ New person</div>
|
||
</div>
|
||
<div class="EMPTY-BOX" style="padding:48px 24px">
|
||
<div class="EMPTY-ICON">👤</div>
|
||
<div style="font-size:13px;font-weight:700;color:#CCC">No persons yet</div>
|
||
<div class="EMPTY-MSG">Add the first family member to begin building the archive's person directory.</div>
|
||
<div class="EMPTY-CTA">Add the first family member</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-block">
|
||
<div class="screen-label">1-E · Search results <span class="sz">desktop</span> <span class="state-tag">filtered</span></div>
|
||
<div class="URL-LINE">/persons<span class="qs">?q=Fischer</span></div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="PAGE-HDR" style="margin-bottom:8px">
|
||
<div>
|
||
<div class="PAGE-TITLE">Persons</div>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:10px">
|
||
<div style="width:180px;height:28px;border:1.5px solid #002850;border-radius:4px;background:#fff;box-shadow:0 0 0 3px rgba(0,40,80,.07);display:flex;align-items:center;padding:0 8px;font-size:9px;color:#333;gap:4px">🔍 Fischer</div>
|
||
<div class="BTN BTN-primary">+ New person</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:9px;color:#888;margin-bottom:12px;font-style:italic">1 result for "Fischer" <span style="font-size:8px;color:#AAA;margin-left:8px;cursor:pointer">Clear ×</span></div>
|
||
<div class="PERSON-GRID">
|
||
<div class="PG-card">
|
||
<div class="PG-initials">OF</div>
|
||
<div class="PG-name">Otto Fischer</div>
|
||
<div class="PG-alias">„Großvater Otto"</div>
|
||
<div class="PG-dates">✦ 1882 · † 1944</div>
|
||
<div class="PG-doccount">8 docs</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Search filters by first name, last name, or alias. Result count shown below header. "Clear ×" resets query param. Search box has focus ring when active.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S2 PERSON DETAIL -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">2</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-persons">Detail</span>
|
||
<div class="sec-title">Person Detail <code style="font-size:14px">/persons/[id]</code></div>
|
||
<div class="sec-tagline">2-column layout on desktop. Left sidebar: Person Card (35%). Right: Activity Area — Frequent Correspondents, Sent Documents, Received Documents (65%). Stacked on tablet/mobile.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 2A Desktop full detail -->
|
||
<div class="screens" style="margin-bottom:24px">
|
||
<div class="screen-block" style="flex:1">
|
||
<div class="screen-label">2-A · Desktop detail — Otto Fischer <span class="sz">1440px</span> <span class="state-tag">view</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to overview</div>
|
||
<!-- 2-col layout -->
|
||
<div class="DETAIL-LAYOUT">
|
||
<!-- Left: Person Card -->
|
||
<div>
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body">
|
||
<div class="PC-avatar PC-avatar-lg">OF</div>
|
||
<div class="PC-name">Otto Fischer</div>
|
||
<div class="PC-alias">„Großvater Otto"</div>
|
||
<div class="PC-dates">✦ 1882 · † 1944</div>
|
||
<hr class="SEC-DIV">
|
||
<div class="PC-notes-label">Notes</div>
|
||
<div class="PC-notes">Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).</div>
|
||
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:4px">✏ Edit person</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Right: Activity -->
|
||
<div class="ACTIVITY">
|
||
<!-- Frequent Correspondents -->
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head">
|
||
<div class="ACT-title">Frequent Correspondents</div>
|
||
<div style="font-size:8px;color:#AAA;font-style:italic">(click to view conversation)</div>
|
||
</div>
|
||
<div style="display:flex;gap:6px;flex-wrap:wrap">
|
||
<div class="CORR-chip" title="Click to view conversation">
|
||
<div class="CORR-av">HM</div>
|
||
Hans Müller
|
||
<span class="CORR-count">×4</span>
|
||
<span style="font-size:9px;margin-left:2px">💬</span>
|
||
</div>
|
||
<div class="CORR-chip" title="Click to view conversation">
|
||
<div class="CORR-av">AS</div>
|
||
Anna Schmidt
|
||
<span class="CORR-count">×2</span>
|
||
<span style="font-size:9px;margin-left:2px">💬</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Sent Documents -->
|
||
<div class="ACT-section" style="padding-bottom:0">
|
||
<div class="ACT-section-head">
|
||
<div class="ACT-title">Sent Documents</div>
|
||
<div style="display:flex;align-items:center;gap:6px">
|
||
<div class="ACT-badge">5</div>
|
||
<div class="SORT-TOGGLE">Date ▾</div>
|
||
</div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon sent">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Brief an den König</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Berlin · 12 Nov 1938</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon sent">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Freiburg · 3 Mar 1922</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon sent">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Pachtvertrag Südfeld</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Karlsruhe · 14 Jul 1910</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div>
|
||
</div>
|
||
<div class="SHOW-MORE">Show 2 more…</div>
|
||
</div>
|
||
<!-- Received Documents -->
|
||
<div class="ACT-section" style="padding-bottom:0">
|
||
<div class="ACT-section-head">
|
||
<div class="ACT-title">Received Documents</div>
|
||
<div style="display:flex;align-items:center;gap:6px">
|
||
<div class="ACT-badge">3</div>
|
||
<div class="SORT-TOGGLE">Date ▾</div>
|
||
</div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon recv">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Scan ohne Titel</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon recv">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Scan ohne Titel</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
|
||
</div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon recv">▤</div>
|
||
<div>
|
||
<div class="DOC-ROW-title">Scan ohne Titel</div>
|
||
<div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Left sidebar has 2px navy top accent bar. Avatar 80px. No "Full Name" label — name shown directly as PC-name h1. Notes section only rendered when notes field is non-empty. Edit button navigates to /persons/[id]/edit.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 2B Tablet + 2C Mobile -->
|
||
<div class="screens cols2" style="margin-bottom:24px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">2-B · Tablet stacked <span class="sz">768px</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nr"><div class="nico"></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="BACK-LINK" style="margin-bottom:8px"><span class="BACK-ARROW">←</span> Back</div>
|
||
<!-- Stacked: person card full width -->
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body" style="display:flex;align-items:center;gap:14px;padding:14px 16px">
|
||
<div class="PC-avatar" style="margin:0;flex-shrink:0">OF</div>
|
||
<div>
|
||
<div class="PC-name" style="text-align:left;font-size:13px">Otto Fischer</div>
|
||
<div class="PC-alias" style="text-align:left">„Großvater Otto"</div>
|
||
<div class="PC-dates" style="text-align:left">✦ 1882 · † 1944</div>
|
||
</div>
|
||
<div style="margin-left:auto"><div class="BTN BTN-outline BTN-sm">✏ Edit</div></div>
|
||
</div>
|
||
</div>
|
||
<!-- Activity below -->
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head"><div class="ACT-title">Frequent Correspondents</div></div>
|
||
<div style="display:flex;gap:6px;flex-wrap:wrap">
|
||
<div class="CORR-chip"><div class="CORR-av">HM</div>Hans Müller <span class="CORR-count">×4</span></div>
|
||
<div class="CORR-chip"><div class="CORR-av">AS</div>Anna Schmidt <span class="CORR-count">×2</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="ACT-section" style="padding-bottom:0">
|
||
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">5</div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon sent">▤</div><div class="DOC-ROW-title">Brief an den König</div><div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon sent">▤</div><div class="DOC-ROW-title">Grundbucheintrag Hof Fischer</div><div style="margin-left:auto"><div class="CH CH-green" style="font-size:7px">Archived</div></div></div>
|
||
<div class="SHOW-MORE">Show 3 more…</div>
|
||
</div>
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">3</div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon recv">▤</div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div></div>
|
||
<div class="DOC-ROW"><div class="DOC-ROW-icon recv">▤</div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-block">
|
||
<div class="screen-label">2-C · Mobile <span class="sz">375px</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4</div>
|
||
<div class="wf" style="max-width:260px">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN" style="padding:12px;gap:10px">
|
||
<div class="BACK-LINK" style="margin-bottom:4px"><span class="BACK-ARROW">←</span> Back</div>
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body" style="padding:12px 14px;text-align:center">
|
||
<div class="PC-avatar" style="width:52px;height:52px;font-size:16px">OF</div>
|
||
<div class="PC-name" style="font-size:13px;margin-top:8px">Otto Fischer</div>
|
||
<div class="PC-alias">„Großvater Otto"</div>
|
||
<div class="PC-dates">✦ 1882 · † 1944</div>
|
||
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:10px">✏ Edit person</div>
|
||
</div>
|
||
</div>
|
||
<div class="ACT-section" style="padding:10px 12px">
|
||
<div class="ACT-section-head"><div class="ACT-title">Correspondents</div></div>
|
||
<div style="display:flex;gap:4px;flex-wrap:wrap">
|
||
<div class="CORR-chip" style="font-size:8px"><div class="CORR-av">HM</div>Hans M. <span class="CORR-count">×4</span></div>
|
||
<div class="CORR-chip" style="font-size:8px"><div class="CORR-av">AS</div>Anna S. <span class="CORR-count">×2</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="ACT-section" style="padding:10px 12px;padding-bottom:0">
|
||
<div class="ACT-section-head"><div class="ACT-title">Sent</div><div class="ACT-badge">5</div></div>
|
||
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon sent" style="width:18px;height:22px">▤</div><div class="DOC-ROW-title" style="font-size:8.5px">Brief an den König</div></div>
|
||
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon sent" style="width:18px;height:22px">▤</div><div class="DOC-ROW-title" style="font-size:8.5px">Grundbucheintrag…</div></div>
|
||
<div class="SHOW-MORE" style="font-size:8px">Show 3 more…</div>
|
||
</div>
|
||
<div class="ACT-section" style="padding:10px 12px">
|
||
<div class="ACT-section-head"><div class="ACT-title">Received</div><div class="ACT-badge">3</div></div>
|
||
<div class="DOC-ROW" style="padding:5px 0"><div class="DOC-ROW-icon recv" style="width:18px;height:22px">▤</div><div class="DOC-ROW-title" style="font-size:8.5px">Scan ohne Titel ×3</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 2D Minimal data person -->
|
||
<div class="screens" style="margin-bottom:16px">
|
||
<div class="screen-block" style="max-width:700px">
|
||
<div class="screen-label">2-D · Minimal data person — Hans Müller <span class="sz">desktop</span> <span class="state-tag">no alias · no notes · no death year</span></div>
|
||
<div class="URL-LINE">/persons/b2c3d4e5</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to overview</div>
|
||
<div class="DETAIL-LAYOUT">
|
||
<div>
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body">
|
||
<div class="PC-avatar PC-avatar-lg">HM</div>
|
||
<div class="PC-name">Hans Müller</div>
|
||
<!-- No alias — section omitted -->
|
||
<div class="PC-dates">✦ 1890</div>
|
||
<!-- No notes — section omitted entirely -->
|
||
<div style="margin-top:10px">
|
||
<div style="font-size:8px;color:#D1D5DB;font-style:italic;text-align:center;padding:4px 0">No notes added</div>
|
||
</div>
|
||
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:8px">✏ Edit person</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="ACTIVITY">
|
||
<!-- No correspondents — section omitted -->
|
||
<div class="ACT-section" style="padding-bottom:0">
|
||
<div class="ACT-section-head"><div class="ACT-title">Sent Documents</div><div class="ACT-badge">1</div></div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon sent">▤</div>
|
||
<div><div class="DOC-ROW-title">Brief an den König</div><div style="font-size:8px;color:#AAA;margin-top:1px">Berlin · 12 Nov 1938</div></div>
|
||
<div style="margin-left:auto"><div class="CH CH-navy" style="font-size:7px">Uploaded</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head"><div class="ACT-title">Received Documents</div><div class="ACT-badge">1</div></div>
|
||
<div class="DOC-ROW">
|
||
<div class="DOC-ROW-icon recv">▤</div>
|
||
<div><div class="DOC-ROW-title">Scan ohne Titel</div><div style="font-size:8px;color:#AAA;margin-top:1px">Hamburg · 25 Nov 1938</div></div>
|
||
<div style="margin-left:auto"><div class="CH CH-warn" style="font-size:7px">Scan pending</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Optional sections (alias, notes, Frequent Correspondents) collapse gracefully when empty. Death year omitted — only birth year shown. "No notes added" placeholder in muted italic; entire Notes card section still renders but with placeholder text. Correspondents section not shown when no co-correspondents exist.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S3 EDIT PERSON -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">3</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-persons">Edit</span>
|
||
<div class="sec-title">Edit Person <code style="font-size:14px">/persons/[id]/edit</code></div>
|
||
<div class="sec-tagline">Dedicated route. Full-bleed sticky save bar at bottom. 2-column field grid. Danger Zone accordion at the very bottom. Merge panel lives here, not on detail view.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 3A Desktop edit -->
|
||
<div class="screens" style="margin-bottom:24px">
|
||
<div class="screen-block" style="flex:1">
|
||
<div class="screen-label">3-A · Desktop edit form <span class="sz">1440px</span> <span class="state-tag edit">edit</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:480px">
|
||
<div class="MAIN-wide" style="flex:1;overflow:hidden">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<div class="PAGE-TITLE" style="margin-bottom:16px">Edit person: Otto Fischer</div>
|
||
<div class="FORM-CARD">
|
||
<div class="FORM-CARD-title">Personal Details</div>
|
||
<!-- Row 1: First + Last name -->
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI filled">Otto</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI filled">Fischer</div>
|
||
</div>
|
||
</div>
|
||
<!-- Row 2: Alias -->
|
||
<div class="FG">
|
||
<div class="FL">Nickname / Alias <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI filled">Großvater Otto</div>
|
||
</div>
|
||
<!-- Row 3: Birth + Death year -->
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">Birth year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI filled">1882</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI filled">1944</div>
|
||
</div>
|
||
</div>
|
||
<!-- Notes -->
|
||
<div class="FG">
|
||
<div class="FL">Notes <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FTA filled" style="height:60px">Patriarchal figure of the Fischer family. Farmer from Baden-Württemberg. Married to Helene Fischer (née Braun).</div>
|
||
</div>
|
||
</div>
|
||
<!-- Danger Zone accordion (collapsed) -->
|
||
<div class="DZ-ACCORD">
|
||
<div class="DZ-ACCORD-head">
|
||
<div class="DZ-ACCORD-label">⚠ Danger Zone <span class="CH CH-red" style="margin-left:4px">Destructive actions</span></div>
|
||
<div class="DZ-ACCORD-chev">›</div>
|
||
</div>
|
||
<!-- Collapsed: only header visible -->
|
||
<div style="padding:8px 14px;background:#FFF5F5;border-top:1px solid #FCA5A5">
|
||
<div style="font-size:8.5px;color:#888;display:flex;align-items:center;gap:6px;cursor:pointer">
|
||
<span>Merge with another person…</span>
|
||
<span style="color:#CCC">›</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Sticky save bar -->
|
||
<div class="SAVE-BAR">
|
||
<div class="BTN BTN-ghost">Discard changes</div>
|
||
<div class="BTN BTN-primary">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Back link says "← Back to Otto Fischer" — links to /persons/[id]. Page heading uses person full name. Danger Zone accordion collapsed by default; only the "Merge with another person…" affordance is visible. Sticky save bar uses full-bleed pattern from CLAUDE.md.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 3B Validation error -->
|
||
<div class="screens cols2" style="margin-bottom:24px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">3-B · Validation error <span class="sz">desktop</span> <span class="state-tag err">error</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:320px">
|
||
<div class="MAIN-wide" style="flex:1;overflow:hidden">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<div class="PAGE-TITLE" style="margin-bottom:12px">Edit person: Otto Fischer</div>
|
||
<div class="FORM-CARD">
|
||
<div class="FORM-CARD-title">Personal Details</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI err" style="border-color:#DC2626;background:#FFF5F5"></div>
|
||
<div class="ferr">First name is required</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI filled">Fischer</div>
|
||
</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Nickname / Alias</div>
|
||
<div class="FI filled">Großvater Otto</div>
|
||
</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">Birth year</div>
|
||
<div class="FI filled">1882</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year</div>
|
||
<div class="FI filled">1944</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="SAVE-BAR">
|
||
<div class="BTN BTN-ghost">Discard changes</div>
|
||
<div class="BTN BTN-primary">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Errors shown on submit — not live. Affected field gets red border + error message below. Save button remains enabled (not disabled). Multiple fields can show errors simultaneously.</div>
|
||
</div>
|
||
|
||
<!-- 3C Danger Zone expanded -->
|
||
<div class="screen-block">
|
||
<div class="screen-label">3-C · Danger Zone expanded — Merge panel <span class="sz">desktop</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:400px">
|
||
<div class="MAIN-wide" style="flex:1;overflow:hidden">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<div class="PAGE-TITLE" style="margin-bottom:12px">Edit person: Otto Fischer</div>
|
||
<!-- Form card (abbreviated) -->
|
||
<div class="FORM-CARD" style="padding:10px 14px">
|
||
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
|
||
<div class="FG-row">
|
||
<div class="FG"><div class="FL">First name <span class="req">*</span></div><div class="FI filled">Otto</div></div>
|
||
<div class="FG"><div class="FL">Last name <span class="req">*</span></div><div class="FI filled">Fischer</div></div>
|
||
</div>
|
||
<div style="font-size:8px;color:#AAA;font-style:italic">… more fields above …</div>
|
||
</div>
|
||
<!-- Danger Zone — EXPANDED -->
|
||
<div class="DZ-ACCORD">
|
||
<div class="DZ-ACCORD-head" style="background:#FFF5F5">
|
||
<div class="DZ-ACCORD-label">⚠ Danger Zone <span class="CH CH-red" style="margin-left:4px">Destructive actions</span></div>
|
||
<div class="DZ-ACCORD-chev" style="transform:rotate(90deg)">›</div>
|
||
</div>
|
||
<div class="DZ-ACCORD-body">
|
||
<div style="font-size:10px;font-weight:800;color:#991B1B;margin-bottom:6px">Merge with another person</div>
|
||
<div class="DZ-ACCORD-desc">Select a target person. All documents and links from <strong>Otto Fischer</strong> will be transferred to the target, and this person will be permanently deleted. This action cannot be undone.</div>
|
||
<div class="FG" style="margin-bottom:10px">
|
||
<div class="FL">Search for person to merge into…</div>
|
||
<div class="TYPEAHEAD-INPUT focus">Search persons…</div>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
||
<div class="BTN BTN-danger-fill BTN-sm">Merge Otto Fischer →</div>
|
||
<div class="BTN BTN-ghost BTN-sm">Cancel</div>
|
||
</div>
|
||
<div class="AL AL-warn" style="font-size:8px">⚠ This action cannot be undone. All documents linked to Otto Fischer will be reassigned.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="SAVE-BAR">
|
||
<div class="BTN BTN-ghost">Discard changes</div>
|
||
<div class="BTN BTN-primary">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Danger Zone expanded by clicking the header row (Svelte $state boolean toggle). Merge typeahead uses PersonTypeahead component. Red "Merge" button disabled until a target person is selected. Warning banner always visible inside expanded panel.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 3D Mobile edit -->
|
||
<div class="screens" style="margin-bottom:16px">
|
||
<div class="screen-block" style="max-width:300px">
|
||
<div class="screen-label">3-D · Mobile edit <span class="sz">375px</span> <span class="state-tag edit">edit</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf" style="max-width:260px">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:500px">
|
||
<div class="MAIN" style="padding:12px;flex:1;overflow:hidden;gap:8px">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit: Otto Fischer</div>
|
||
<div class="FORM-CARD" style="padding:10px 12px">
|
||
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
|
||
<!-- Single-column on mobile -->
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI filled">Otto</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI filled">Fischer</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Nickname / Alias</div>
|
||
<div class="FI filled">Großvater Otto</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Birth year</div>
|
||
<div class="FI filled">1882</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year</div>
|
||
<div class="FI filled">1944</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Notes</div>
|
||
<div class="FTA filled" style="height:50px;font-size:8px">Patriarchal figure of the Fischer family…</div>
|
||
</div>
|
||
</div>
|
||
<!-- Danger Zone collapsed -->
|
||
<div class="DZ-ACCORD">
|
||
<div class="DZ-ACCORD-head">
|
||
<div class="DZ-ACCORD-label" style="font-size:8px">⚠ Danger Zone</div>
|
||
<div class="DZ-ACCORD-chev">›</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="SAVE-BAR" style="padding:8px 12px">
|
||
<div class="BTN BTN-ghost BTN-sm">Discard</div>
|
||
<div class="BTN BTN-primary BTN-sm">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Mobile: 2-column field grid collapses to 1-column. All fields stack vertically. Sticky save bar remains full-bleed. Danger Zone always at very bottom, collapsed by default.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S4 NEW PERSON -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">4</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-persons">New</span>
|
||
<div class="sec-title">New Person <code style="font-size:14px">/persons/new</code></div>
|
||
<div class="sec-tagline">Centered max-w-2xl form. All 6 fields (fixes the 3-field inconsistency). Card-style save bar (not sticky). "Create person" green primary button.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screens cols2" style="margin-bottom:24px">
|
||
<!-- 4A Desktop new person -->
|
||
<div class="screen-block">
|
||
<div class="screen-label">4-A · Desktop new person <span class="sz">1440px</span> <span class="state-tag new">new</span></div>
|
||
<div class="URL-LINE">/persons/new</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to overview</div>
|
||
<div class="PAGE-TITLE" style="margin-bottom:16px">New person</div>
|
||
<!-- Centered max-w-2xl container -->
|
||
<div style="max-width:560px">
|
||
<div class="FORM-CARD">
|
||
<div class="FORM-CARD-title">Person details</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Nickname / Alias <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">Birth year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Notes <span style="font-size:7.5px;color:#AAA;font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></div>
|
||
<div class="FTA" style="height:60px"></div>
|
||
</div>
|
||
</div>
|
||
<!-- Card-style save bar (not sticky — short form) -->
|
||
<div style="display:flex;align-items:center;justify-content:space-between;background:#fff;border:1.5px solid #E8E4DF;border-radius:8px;padding:10px 16px;box-shadow:0 1px 4px rgba(0,0,0,.04)">
|
||
<div class="BTN BTN-ghost">Cancel</div>
|
||
<div class="BTN BTN-green">Create person</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Save bar uses card-style (not sticky full-bleed) — form is short enough to always be visible. "Cancel" navigates back to /persons. "Create person" green primary. All empty fields shown — no pre-fill.</div>
|
||
</div>
|
||
|
||
<!-- 4B Mobile new person -->
|
||
<div class="screen-block">
|
||
<div class="screen-label">4-B · Mobile new person <span class="sz">375px</span> <span class="state-tag new">new</span></div>
|
||
<div class="URL-LINE">/persons/new</div>
|
||
<div class="wf" style="max-width:260px">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV-m">
|
||
<div class="logo" style="font-size:8px">FAMILIENARCHIV</div>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN" style="padding:12px;gap:8px">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back</div>
|
||
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">New person</div>
|
||
<div class="FORM-CARD" style="padding:10px 12px">
|
||
<div class="FORM-CARD-title" style="margin-bottom:8px">Person details</div>
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Nickname / Alias</div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Birth year</div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year</div>
|
||
<div class="FI"></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Notes</div>
|
||
<div class="FTA" style="height:52px"></div>
|
||
</div>
|
||
</div>
|
||
<div style="display:flex;align-items:center;justify-content:space-between;background:#fff;border:1.5px solid #E8E4DF;border-radius:6px;padding:8px 12px">
|
||
<div class="BTN BTN-ghost BTN-sm">Cancel</div>
|
||
<div class="BTN BTN-green BTN-sm">Create person</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Mobile: all fields in single column. Save bar card-style (not sticky). Same 6 fields as desktop.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S5 EDGE CASES -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">5</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-edge">Edge Cases</span>
|
||
<div class="sec-title">Edge Cases & Error States</div>
|
||
<div class="sec-tagline">Person with no documents. Unsaved changes guard. Save API error.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 5A Person with no documents -->
|
||
<div class="screens" style="margin-bottom:24px">
|
||
<div class="screen-block" style="flex:1">
|
||
<div class="screen-label">5-A · Person with no documents — Maria Weber <span class="sz">desktop</span> <span class="state-tag empty">no documents</span></div>
|
||
<div class="URL-LINE">/persons/d4e5f6g7</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nlang"><span>DE</span><span class="on">EN</span><span>ES</span></div><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN-wide">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to overview</div>
|
||
<div class="DETAIL-LAYOUT">
|
||
<div>
|
||
<div class="PERSON-CARD">
|
||
<div class="PERSON-CARD-topbar"></div>
|
||
<div class="PERSON-CARD-body">
|
||
<div class="PC-avatar PC-avatar-lg">MW</div>
|
||
<div class="PC-name">Maria Weber</div>
|
||
<div style="font-size:8.5px;color:#D1D5DB;font-style:italic;text-align:center;margin-top:4px;margin-bottom:4px">No alias · No dates</div>
|
||
<div class="BTN BTN-outline BTN-sm" style="width:100%;justify-content:center;margin-top:10px">✏ Edit person</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="ACTIVITY">
|
||
<!-- No correspondents — section omitted entirely -->
|
||
<!-- Sent: empty state -->
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head">
|
||
<div class="ACT-title">Sent Documents</div>
|
||
<div class="ACT-badge" style="background:#F3F4F6;color:#AAA">0</div>
|
||
</div>
|
||
<div class="EMPTY-BOX" style="padding:20px;border-color:#E8E4DF">
|
||
<div class="EMPTY-ICON" style="font-size:20px">📄</div>
|
||
<div class="EMPTY-MSG">No sent documents yet</div>
|
||
</div>
|
||
</div>
|
||
<!-- Received: empty state -->
|
||
<div class="ACT-section">
|
||
<div class="ACT-section-head">
|
||
<div class="ACT-title">Received Documents</div>
|
||
<div class="ACT-badge" style="background:#F3F4F6;color:#AAA">0</div>
|
||
</div>
|
||
<div class="EMPTY-BOX" style="padding:20px;border-color:#E8E4DF">
|
||
<div class="EMPTY-ICON" style="font-size:20px">📄</div>
|
||
<div class="EMPTY-MSG">No received documents yet</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">When both sent and received document counts are 0, empty-state dashed boxes are shown. Correspondent section is entirely absent (not rendered). Count badge shows 0 in grey, not navy.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 5B Unsaved changes guard + 5C Save error -->
|
||
<div class="screens cols2" style="margin-bottom:16px">
|
||
<div class="screen-block">
|
||
<div class="screen-label">5-B · Unsaved changes guard <span class="sz">edit page</span> <span class="state-tag warn">dirty form</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:320px">
|
||
<div class="MAIN-wide" style="flex:1;overflow:hidden;gap:10px">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<!-- Unsaved changes banner -->
|
||
<div class="UNSAVED-BANNER">
|
||
<div class="UNSAVED-MSG">⚠ You have unsaved changes. Save or discard before leaving.</div>
|
||
<div style="display:flex;gap:6px">
|
||
<div class="BTN BTN-primary BTN-sm">Save</div>
|
||
<div class="BTN BTN-ghost BTN-sm">Discard</div>
|
||
</div>
|
||
</div>
|
||
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit person: Otto Fischer</div>
|
||
<div class="FORM-CARD" style="padding:10px 12px">
|
||
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI filled focus">Ott<span style="border-right:2px solid #002850"> </span></div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI filled">Fischer</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:8px;color:#AAA;font-style:italic;margin-top:4px">Form is dirty — first name partially edited</div>
|
||
</div>
|
||
</div>
|
||
<div class="SAVE-BAR">
|
||
<div class="BTN BTN-ghost">Discard changes</div>
|
||
<div class="BTN BTN-primary">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">Banner triggers when user clicks the back link or uses browser navigation while form isDirty (track with Svelte $derived). [Save] in banner = same action as save bar. [Discard] resets form and navigates away. SvelteKit beforeNavigate() hook handles browser back/forward.</div>
|
||
</div>
|
||
|
||
<div class="screen-block">
|
||
<div class="screen-label">5-C · Save error — API failure <span class="sz">edit page</span> <span class="state-tag err">error</span></div>
|
||
<div class="URL-LINE">/persons/a1b2c3d4/edit</div>
|
||
<div class="wf">
|
||
<div class="wf-bar"><div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="urlbar"></div></div>
|
||
<div class="NAV">
|
||
<div class="logo">FAMILIENARCHIV</div>
|
||
<div class="nl">Documents</div><div class="nl on">Persons</div><div class="nl">Conversations</div><div class="nl">Admin</div>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div style="display:flex;flex-direction:column;height:320px">
|
||
<div class="MAIN-wide" style="flex:1;overflow:hidden;gap:10px">
|
||
<div class="BACK-LINK"><span class="BACK-ARROW">←</span> Back to Otto Fischer</div>
|
||
<!-- Error banner -->
|
||
<div class="ERR-BANNER">
|
||
<div class="ERR-BANNER-msg">✕ Save failed — First name is required.</div>
|
||
</div>
|
||
<div class="PAGE-TITLE" style="font-size:11px;margin-bottom:8px">Edit person: Otto Fischer</div>
|
||
<div class="FORM-CARD" style="padding:10px 12px">
|
||
<div class="FORM-CARD-title" style="margin-bottom:8px">Personal Details</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">First name <span class="req">*</span></div>
|
||
<div class="FI err"></div>
|
||
<div class="ferr">First name is required</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Last name <span class="req">*</span></div>
|
||
<div class="FI filled">Fischer</div>
|
||
</div>
|
||
</div>
|
||
<div class="FG-row">
|
||
<div class="FG">
|
||
<div class="FL">Birth year</div>
|
||
<div class="FI filled">1882</div>
|
||
</div>
|
||
<div class="FG">
|
||
<div class="FL">Death year</div>
|
||
<div class="FI filled">1944</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="SAVE-BAR">
|
||
<div class="BTN BTN-ghost">Discard changes</div>
|
||
<div class="BTN BTN-primary">Save changes</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="screen-cap">API error shown in red banner below the back link. Specific field also highlighted with inline error. Error message uses backend ErrorCode translation via getErrorMessage(). Page stays on edit route — user can correct and retry.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S6 IMPLEMENTATION NOTES -->
|
||
<div class="section">
|
||
<div class="sec-intro">
|
||
<div class="sec-num">6</div>
|
||
<div class="sec-meta">
|
||
<span class="sec-badge badge-arch">Implementation</span>
|
||
<div class="sec-title">Implementation Notes</div>
|
||
<div class="sec-tagline">Numbered rules covering every required code change. Follow these in order to implement the full Concept A redesign.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="SPEC">
|
||
<div class="SPEC-title">Implementation rules — Concept A: Enriched Directory</div>
|
||
<div class="SPEC-grid">
|
||
<div class="SPEC-col">
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 1 — Route change</div>
|
||
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">/persons/[id]/edit</span> as a new SvelteKit route (<span class="SPEC-rule-code">+page.svelte</span> + <span class="SPEC-rule-code">+page.server.ts</span>). Move the <span class="SPEC-rule-code">update</span> form action from <span class="SPEC-rule-code">/persons/[id]/+page.server.ts</span> to the edit route's server file. <span class="SPEC-rule-code">PersonCard.svelte</span> edit-mode <span class="SPEC-rule-code">$state</span> can be removed — the card is now view-only. The [Edit person] button navigates to <span class="SPEC-rule-code">/persons/{id}/edit</span>.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 2 — New person form fields</div>
|
||
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">birthYear</span>, <span class="SPEC-rule-code">deathYear</span>, and <span class="SPEC-rule-code">notes</span> fields to <span class="SPEC-rule-code">/persons/new/+page.svelte</span> and the corresponding <span class="SPEC-rule-code">create</span> server action. These fields are already on the PersonDTO and the backend <span class="SPEC-rule-code">PersonService</span>; only the frontend form was missing them. Use <span class="SPEC-rule-code">parseInt(formData.get('birthYear'))</span> — handle empty string as <span class="SPEC-rule-code">undefined</span>.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 3 — Card enrichment on list page</div>
|
||
<div class="SPEC-rule-text">The list <span class="SPEC-rule-code">+page.server.ts</span> already returns <span class="SPEC-rule-code">persons[]</span>. No backend change needed — <span class="SPEC-rule-code">alias</span>, <span class="SPEC-rule-code">birthYear</span>, <span class="SPEC-rule-code">deathYear</span> are already on the PersonDTO. Update the card template in <span class="SPEC-rule-code">+page.svelte</span> to render these fields. Render alias only <span class="SPEC-rule-code">{#if person.alias}</span>. Life dates: <span class="SPEC-rule-code">✦ {birthYear}</span> and <span class="SPEC-rule-code">† {deathYear}</span> joined with <span class="SPEC-rule-code"> · </span>; omit when null.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 4 — Stats bar</div>
|
||
<div class="SPEC-rule-text">Compute <span class="SPEC-rule-code">persons.length</span> (person count) and <span class="SPEC-rule-code">totalDocs = persons.reduce((acc, p) => acc + (p.documentCount ?? 0), 0)</span> (total documents). This requires backend to return <span class="SPEC-rule-code">documentCount: number</span> on PersonDTO — add this field to the Java <span class="SPEC-rule-code">Person</span> entity response (computed via <span class="SPEC-rule-code">@Formula</span> or a JPQL query in <span class="SPEC-rule-code">PersonService.findAll()</span>). Mark it <span class="SPEC-rule-code">@Schema(requiredMode = REQUIRED)</span> and run <span class="SPEC-rule-code">npm run generate:api</span>.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 5 — 2-column detail layout</div>
|
||
<div class="SPEC-rule-text">Replace the current vertical stack in <span class="SPEC-rule-code">/persons/[id]/+page.svelte</span> with a CSS grid: <span class="SPEC-rule-code">class="grid md:grid-cols-[35fr_65fr] gap-5 items-start"</span>. Left child = PersonCard. Right child = Activity wrapper containing the three ACT sections. On mobile/tablet (<span class="SPEC-rule-code"><md:</span>) the grid collapses to single column (PersonCard above, Activity below).</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 6 — Merge panel relocation</div>
|
||
<div class="SPEC-rule-text"><span class="SPEC-rule-code">PersonMergePanel.svelte</span> must be moved from <span class="SPEC-rule-code">/persons/[id]/+page.svelte</span> to <span class="SPEC-rule-code">/persons/[id]/edit/+page.svelte</span>. Wrap it in a collapsible accordion: <span class="SPEC-rule-code">let dangerOpen = $state(false)</span>; the accordion header toggles <span class="SPEC-rule-code">dangerOpen</span>; the body uses a CSS <span class="SPEC-rule-code">transition</span> on max-height or a simple <span class="SPEC-rule-code">{#if dangerOpen}</span> block.</div>
|
||
</div>
|
||
</div>
|
||
<div class="SPEC-col">
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 7 — "Full Name" duplication fix</div>
|
||
<div class="SPEC-rule-text">Remove the <span class="SPEC-rule-code"><div class="FL">Full Name</div></span> label and associated value row from <span class="SPEC-rule-code">PersonCard.svelte</span> view mode. The <span class="SPEC-rule-code"><h1></span> (PC-name class) already displays the full name. This was flagged in the audit as a direct duplication.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 8 — Sticky save bar</div>
|
||
<div class="SPEC-rule-text">The edit route uses the full-bleed sticky pattern from <span class="SPEC-rule-code">CLAUDE.md</span>: <span class="SPEC-rule-code">class="sticky bottom-0 z-10 -mx-4 px-6 py-4 bg-white border-t border-brand-sand shadow-[0_-2px_8px_rgba(0,0,0,0.06)] flex items-center justify-between"</span>. The new person form uses the card-style save bar (not sticky): <span class="SPEC-rule-code">class="mt-4 flex items-center justify-between rounded-sm border border-brand-sand bg-white px-6 py-4 shadow-sm"</span>.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 9 — Co-correspondents tooltip</div>
|
||
<div class="SPEC-rule-text">Add <span class="SPEC-rule-code">title="Click to view conversation"</span> to each correspondent chip element. Optionally add a small 💬 chat icon inside the chip (Unicode or a 12px SVG). The chip's <span class="SPEC-rule-code">href</span> should navigate to <span class="SPEC-rule-code">/conversations?person1={currentId}&person2={corrId}</span>. This clarifies the navigation target which was previously ambiguous.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 10 — Document status labels</div>
|
||
<div class="SPEC-rule-text">Map raw status enums to human-readable i18n labels using the existing Paraglide system: <span class="SPEC-rule-code">PLACEHOLDER → m.status_scan_pending()</span>, <span class="SPEC-rule-code">UPLOADED → m.status_uploaded()</span>, <span class="SPEC-rule-code">TRANSCRIBED → m.status_transcribed()</span>, <span class="SPEC-rule-code">REVIEWED → m.status_reviewed()</span>, <span class="SPEC-rule-code">ARCHIVED → m.status_archived()</span>. Add keys to <span class="SPEC-rule-code">messages/de.json</span>, <span class="SPEC-rule-code">en.json</span>, <span class="SPEC-rule-code">es.json</span>. Add <span class="SPEC-rule-code">DOCUMENT_STATUS_INVALID</span> to <span class="SPEC-rule-code">ErrorCode.java</span> and <span class="SPEC-rule-code">errors.ts</span> for unknown values.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 11 — Unsaved changes guard</div>
|
||
<div class="SPEC-rule-text">In <span class="SPEC-rule-code">/persons/[id]/edit/+page.svelte</span>, track a <span class="SPEC-rule-code">isDirty = $derived(...)</span> boolean by comparing current field values to the loaded person. Use SvelteKit's <span class="SPEC-rule-code">beforeNavigate(({ cancel }) => { if (isDirty) cancel() })</span> to block browser navigation. Show the inline warning banner (yellow, above the form) when isDirty and user attempts to leave. The banner [Save] button submits the form; [Discard] resets fields and calls <span class="SPEC-rule-code">invalidate()</span>.</div>
|
||
</div>
|
||
<div class="SPEC-rule">
|
||
<div class="SPEC-rule-num">Rule 12 — Mobile card layout</div>
|
||
<div class="SPEC-rule-text">On mobile (<span class="SPEC-rule-code"><640px</span>) the person grid cards switch from centered column layout to horizontal row layout: initials circle on the left (36×36px), text block in the middle (name + alias + dates + doc count), chevron on the right. Use <span class="SPEC-rule-code">sm:flex-col sm:items-center</span> vs base <span class="SPEC-rule-code">flex-row items-center</span> in Tailwind. This improves scannability on narrow screens.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Status label reference -->
|
||
<div class="DECISION" style="margin-top:24px">
|
||
<div class="DECISION-title">📋 Document status label map (Rule 10)</div>
|
||
<ul>
|
||
<li><code>PLACEHOLDER</code> → "Scan pending" — <span class="CH CH-warn">Scan pending</span> (amber chip)</li>
|
||
<li><code>UPLOADED</code> → "Uploaded" — <span class="CH CH-navy">Uploaded</span> (navy chip)</li>
|
||
<li><code>TRANSCRIBED</code> → "Transcribed" — <span class="CH CH-blue">Transcribed</span> (blue chip)</li>
|
||
<li><code>REVIEWED</code> → "Reviewed" — <span class="CH CH-mint">Reviewed</span> (mint chip)</li>
|
||
<li><code>ARCHIVED</code> → "Archived" — <span class="CH CH-green">Archived</span> (green chip)</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Files to touch summary -->
|
||
<div style="background:#fff;border:1px solid #E8E4DF;border-radius:8px;overflow:hidden;margin-top:24px">
|
||
<div style="padding:12px 16px;background:#F7F5F2;border-bottom:1px solid #E8E4DF;font-size:10px;font-weight:800;color:#555;text-transform:uppercase;letter-spacing:1px">Files to create / modify</div>
|
||
<table class="SUM-table">
|
||
<thead><tr><th>File</th><th>Action</th><th>Related rule(s)</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><code>frontend/src/routes/persons/+page.svelte</code></td><td>Add alias, dates, doc count to card template; add stats bar; switch to 4-col grid; mobile row layout</td><td>3, 4, 12</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/new/+page.svelte</code></td><td>Add birth year, death year, notes fields</td><td>2</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/new/+page.server.ts</code></td><td>Handle new fields in create action</td><td>2</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/[id]/+page.svelte</code></td><td>2-col grid layout; view-only PersonCard; remove edit toggle state; remove merge panel</td><td>1, 5, 6, 7</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/[id]/+page.server.ts</code></td><td>Remove update action (moved to edit route)</td><td>1</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/[id]/edit/+page.svelte</code></td><td>CREATE: edit form, sticky save bar, danger zone accordion, unsaved guard</td><td>1, 6, 8, 11</td></tr>
|
||
<tr><td><code>frontend/src/routes/persons/[id]/edit/+page.server.ts</code></td><td>CREATE: load person, update action</td><td>1</td></tr>
|
||
<tr><td><code>frontend/src/lib/components/PersonCard.svelte</code></td><td>Remove edit mode toggle; remove "Full Name" label row; make view-only</td><td>1, 7</td></tr>
|
||
<tr><td><code>frontend/src/lib/components/PersonMergePanel.svelte</code></td><td>Move to edit route; add tooltip to chips</td><td>6, 9</td></tr>
|
||
<tr><td><code>backend/src/main/java/…/model/Person.java</code></td><td>Add <code>documentCount</code> computed field or handle in service</td><td>4</td></tr>
|
||
<tr><td><code>frontend/src/lib/errors.ts</code></td><td>Add DOCUMENT_STATUS_INVALID error code</td><td>10</td></tr>
|
||
<tr><td><code>frontend/src/lib/messages/de.json</code> + <code>en.json</code> + <code>es.json</code></td><td>Add status label keys</td><td>10</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- end .doc -->
|
||
</body>
|
||
</html>
|