Exploration spec (sort-integration-spec.html) covers 4 placement variants with comparison matrix. Final spec (sort-inline-final-spec.html) locks in Variant A (inline sort in search bar row) with full desktop/mobile states, dropdown interaction anatomy, loading/empty states, and backend wiring checklist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1292 lines
65 KiB
HTML
1292 lines
65 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Sort Integration — 4 Exploration Variants · Familienarchiv #180</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:1400px;margin:0 auto;padding:48px 32px}
|
||
|
||
/* ── Masthead ─── */
|
||
.mast{background:#0D2240;border-radius:10px;padding:32px 40px;margin-bottom:48px}
|
||
.mast-top{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;margin-bottom:16px}
|
||
.mast h1{font-size:22px;font-weight:900;color:#fff;letter-spacing:-.4px;margin-bottom:6px}
|
||
.mast p{font-size:12px;color:rgba(255,255,255,.5);max-width:640px;line-height:1.7}
|
||
.mast-badge{font-size:9px;font-weight:800;padding:3px 9px;border-radius:20px;text-transform:uppercase;letter-spacing:.8px;white-space:nowrap;flex-shrink:0;margin-top:4px}
|
||
.mb-exploration{background:#FCD34D;color:#713F12}
|
||
.decisions{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:20px;border-top:1px solid rgba(255,255,255,.1);padding-top:16px}
|
||
.dec{background:rgba(255,255,255,.06);border-radius:6px;padding:10px 12px}
|
||
.dec-label{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:rgba(255,255,255,.35);margin-bottom:5px}
|
||
.dec-value{font-size:9.5px;font-weight:700;color:#fff;line-height:1.5}
|
||
|
||
/* ── Section headings ─── */
|
||
.sec{margin-bottom:64px}
|
||
.sec+.sec{border-top:2px dashed #C8C4BE;padding-top:56px}
|
||
.sec-h{font-size:11px;font-weight:800;text-transform:uppercase;letter-spacing:1.2px;color:#888;margin-bottom:20px;display:flex;align-items:center;gap:10px}
|
||
.sec-h::after{content:'';flex:1;height:1px;background:#D8D4CE}
|
||
.sec-num{background:#0D2240;color:#fff;font-size:9px;font-weight:900;padding:2px 7px;border-radius:10px}
|
||
.sec-variant{background:#002850;color:#A6DAD8;font-size:9px;font-weight:900;padding:2px 9px;border-radius:10px;letter-spacing:.3px}
|
||
|
||
/* ── Variant cards ─── */
|
||
.variant-meta{background:#fff;border:1.5px solid #E0DDD6;border-radius:8px;padding:16px 20px;margin-bottom:20px;display:flex;gap:32px}
|
||
.vm-col h3{font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:#888;margin-bottom:6px}
|
||
.vm-col ul{list-style:none;display:flex;flex-direction:column;gap:4px}
|
||
.vm-col ul li{font-size:10.5px;color:#555;padding-left:14px;position:relative;line-height:1.5}
|
||
.vm-col.pros li::before{content:'✓';position:absolute;left:0;color:#16A34A;font-weight:900}
|
||
.vm-col.cons li::before{content:'✗';position:absolute;left:0;color:#DC2626;font-weight:900}
|
||
.vm-col.when li::before{content:'→';position:absolute;left:0;color:#002850}
|
||
|
||
/* ── Mockup chrome ─── */
|
||
.wf{background:#fff;border:2px solid #B8B4AE;border-radius:10px;overflow:hidden;box-shadow:0 4px 18px rgba(0,0,0,.08);max-width:820px}
|
||
.wf-bar{height:24px;background:#E8E4DF;border-bottom:1px solid #C8C4BE;display:flex;align-items:center;padding:0 9px;gap:4px}
|
||
.dot{width:7px;height:7px;border-radius:50%;background:#C8C4BE}
|
||
.dot.r{background:#F87171}.dot.y{background:#FCD34D}.dot.g{background:#4ADE80}
|
||
.urlbar{flex:1;height:11px;background:#D8D4CE;border-radius:3px;margin-left:6px;display:flex;align-items:center;padding:0 5px}
|
||
.urlbar span{font-size:7.5px;color:#888;font-family:monospace}
|
||
.N{height:40px;background:#0D2240;display:flex;align-items:center;padding:0 16px;gap:12px;flex-shrink:0}
|
||
.logo{font-size:9px;font-weight:900;color:#fff;letter-spacing:1px}
|
||
.nl{font-size:7.5px;color:rgba(255,255,255,.4);font-weight:700;text-transform:uppercase;letter-spacing:.5px}
|
||
.nl.on{color:#fff;border-bottom:2px solid #A6DAD8;padding-bottom:2px}
|
||
.nr{margin-left:auto;display:flex;gap:7px;align-items:center}
|
||
.nico{width:20px;height:20px;background:rgba(255,255,255,.1);border-radius:4px}
|
||
.MAIN{padding:14px 18px;display:flex;flex-direction:column;gap:10px;background:#ECEAE4}
|
||
|
||
/* ── Search card ─── */
|
||
.SCARD{background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;padding:11px 14px;box-shadow:0 1px 3px rgba(0,0,0,.06)}
|
||
.SROW1{display:flex;align-items:center;gap:6px}
|
||
.SINPUT{flex:1;height:24px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 8px;font-size:8.5px;color:#9CA3AF;font-style:italic;gap:5px;position:relative}
|
||
.SINPUT.active{color:#1A1A1A;font-style:normal}
|
||
.SINPUT-ICON{width:8px;height:8px;opacity:.35;flex-shrink:0}
|
||
.SINPUT-SPINNER{width:8px;height:8px;border:1.5px solid #E0DDD6;border-top-color:#002850;border-radius:50%;flex-shrink:0;animation:spin .6s linear infinite}
|
||
@keyframes spin{to{transform:rotate(360deg)}}
|
||
.SBTN{height:24px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 9px;font-size:8px;font-weight:700;color:#555;gap:4px;cursor:pointer;white-space:nowrap;background:#F7F5F2}
|
||
.SBTN.sort-active{border-color:#002850;color:#002850;background:#fff}
|
||
.SBTN.filter{background:#F7F5F2}
|
||
.SBTN.reset{border-color:transparent;background:transparent;color:#9CA3AF;padding:0 6px}
|
||
.SBTN.reset:hover{color:#DC2626}
|
||
.SCHEV{font-size:7px;opacity:.5}
|
||
.SCHEV.up{transform:rotate(180deg);display:inline-block}
|
||
|
||
/* ── Sort dropdown ─── */
|
||
.SDROP{background:#fff;border:1.5px solid #002850;border-top:none;border-radius:0 0 4px 4px;box-shadow:0 5px 12px rgba(0,0,0,.12);margin-top:-2px;position:relative;z-index:10}
|
||
.SDROP-ROW{display:flex;align-items:center;padding:5px 9px;border-bottom:1px solid #F0EDE8;cursor:pointer;gap:6px}
|
||
.SDROP-ROW:last-child{border-bottom:none}
|
||
.SDROP-ROW.active{background:#F0F5FF}
|
||
.SDROP-LABEL{flex:1;font-size:8px;color:#1A1A1A;font-weight:700}
|
||
.SDROP-ROW.active .SDROP-LABEL{color:#002850}
|
||
.SDROP-DIR{display:flex;gap:3px}
|
||
.SDROP-D{font-size:7.5px;color:#C8C4BE;font-weight:700;padding:1px 4px;border-radius:2px}
|
||
.SDROP-D.active{background:#002850;color:#fff}
|
||
.SDROP-CHECKMARK{width:8px;height:8px;color:#002850;font-size:8px;font-weight:900}
|
||
|
||
/* ── Sort pills strip ─── */
|
||
.SPILLS{background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;padding:7px 12px;display:flex;align-items:center;gap:6px;overflow-x:auto;box-shadow:0 1px 2px rgba(0,0,0,.04)}
|
||
.SPILLS-LABEL{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#AAA;white-space:nowrap;flex-shrink:0;margin-right:2px}
|
||
.SPILL{height:17px;border:1.5px solid #D1D5DB;border-radius:20px;display:flex;align-items:center;padding:0 8px;font-size:7.5px;font-weight:700;color:#555;white-space:nowrap;cursor:pointer;gap:3px;flex-shrink:0}
|
||
.SPILL.active{background:#002850;color:#fff;border-color:#002850}
|
||
.SPILL-DIR{font-size:7px;opacity:.7}
|
||
.SPILLS-SEP{width:1px;height:14px;background:#E0DDD6;flex-shrink:0;margin-left:2px}
|
||
.SPILLS-DIRBTN{height:17px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 6px;font-size:7.5px;font-weight:700;color:#555;cursor:pointer;gap:2px;flex-shrink:0;white-space:nowrap}
|
||
.SPILLS-DIRBTN.active{border-color:#002850;color:#002850}
|
||
|
||
/* ── Result header ─── */
|
||
.RESHEAD{display:flex;align-items:center;gap:8px;padding:0 2px;margin-bottom:4px}
|
||
.RESHEAD-COUNT{font-size:8px;font-weight:700;color:#555;flex:1}
|
||
.RESHEAD-COUNT strong{color:#002850}
|
||
.RESHEAD-SORT{height:22px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 8px;font-size:7.5px;font-weight:700;color:#555;gap:5px;cursor:pointer;white-space:nowrap;background:#fff}
|
||
.RESHEAD-SORT.active{border-color:#002850;color:#002850}
|
||
.RESHEAD-SORTLABEL{font-size:7px;font-weight:400;color:#AAA;margin-right:2px}
|
||
|
||
/* ── Advanced filter with sort ─── */
|
||
.ADVSORT{border-bottom:1px solid #E0DDD6;padding-bottom:10px;margin-bottom:10px}
|
||
.ADVSORT-LABEL{font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:7px}
|
||
.ADVSORT-PILLS{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:6px}
|
||
.ADVSORT-PILL{height:17px;border:1.5px solid #D1D5DB;border-radius:20px;display:flex;align-items:center;padding:0 8px;font-size:7.5px;font-weight:700;color:#555;cursor:pointer;white-space:nowrap}
|
||
.ADVSORT-PILL.active{background:#002850;color:#fff;border-color:#002850}
|
||
.ADVSORT-DIRS{display:flex;gap:5px}
|
||
.ADVSORT-DIR{height:17px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 8px;font-size:7.5px;font-weight:700;color:#555;cursor:pointer;gap:3px;white-space:nowrap}
|
||
.ADVSORT-DIR.active{border-color:#002850;background:#002850;color:#fff}
|
||
|
||
/* ── Document list rows ─── */
|
||
.DOCLIST{display:flex;flex-direction:column;gap:0}
|
||
.DOCROW{background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;padding:8px 12px;margin-bottom:5px;display:flex;align-items:flex-start;gap:8px;cursor:pointer}
|
||
.DOCROW:hover{border-color:#A6DAD8}
|
||
.DOCROW-THUMB{width:22px;height:28px;background:#F0EDE8;border:1px solid #E0DDD6;border-radius:2px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:7px;color:#AAA}
|
||
.DOCROW-BODY{flex:1;min-width:0}
|
||
.DOCROW-TITLE{font-size:8.5px;font-weight:700;color:#0D2240;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:2px}
|
||
.DOCROW-META{font-size:7.5px;color:#888;display:flex;align-items:center;gap:5px}
|
||
.DOCROW-META-SEP{color:#D1CCC8}
|
||
.DOCROW-TAG{display:inline-block;background:#F0EDE8;border-radius:20px;padding:1px 5px;font-size:7px;font-weight:700;color:#555}
|
||
.PH{height:6px;background:#E8E4DF;border-radius:2px}
|
||
.w80{width:80%}.w70{width:70%}.w60{width:60%}.w50{width:50%}.w40{width:40%}.w30{width:30%}
|
||
|
||
/* ── Grid ─── */
|
||
.sg{display:grid;gap:20px;align-items:start}
|
||
.sg-2{grid-template-columns:1fr 1fr}
|
||
.sg-3{grid-template-columns:1fr 1fr 1fr}
|
||
.sb{display:flex;flex-direction:column}
|
||
.sl{font-size:9px;font-weight:800;color:#888;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:6px;display:flex;align-items:center;gap:6px}
|
||
.sc{font-size:10px;color:#888;margin-top:8px;font-style:italic;line-height:1.5}
|
||
|
||
/* ── Mobile chrome ─── */
|
||
.WF-M{background:#fff;border:2px solid #B8B4AE;border-radius:16px;overflow:hidden;box-shadow:0 4px 18px rgba(0,0,0,.08);width:200px}
|
||
.WF-M-STATUS{height:16px;background:#0D2240;display:flex;align-items:center;justify-content:space-between;padding:0 10px}
|
||
.WF-M-TIME{font-size:6px;color:#fff;font-weight:700}
|
||
.WF-M-ICONS{display:flex;gap:3px}
|
||
.WF-M-ICON{width:5px;height:5px;background:rgba(255,255,255,.5);border-radius:1px}
|
||
.N-M{height:34px;background:#0D2240;display:flex;align-items:center;padding:0 10px;justify-content:space-between}
|
||
.MAIN-SM{padding:8px 10px;display:flex;flex-direction:column;gap:7px;background:#ECEAE4}
|
||
.SCARD-SM{background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;padding:8px 10px}
|
||
|
||
/* ── Annotation callouts ─── */
|
||
.ann-block{background:#FFF7ED;border:1px solid #FDBA74;border-radius:5px;padding:10px 14px;font-size:10.5px;color:#7C2D12;line-height:1.6;margin-top:12px}
|
||
.ann-block strong{font-weight:800}
|
||
.ann-block ul{padding-left:18px;display:flex;flex-direction:column;gap:3px;margin-top:6px}
|
||
|
||
/* ── Comparison matrix ─── */
|
||
.matrix{width:100%;border-collapse:collapse;border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.06)}
|
||
.matrix th{background:#0D2240;color:#fff;font-size:10px;font-weight:800;padding:10px 14px;text-align:left;letter-spacing:.3px}
|
||
.matrix th:first-child{width:160px}
|
||
.matrix td{padding:9px 14px;font-size:11px;border-bottom:1px solid #E8E4DF;vertical-align:top;line-height:1.5}
|
||
.matrix tr:nth-child(even) td{background:#F7F5F2}
|
||
.matrix tr:last-child td{border-bottom:none}
|
||
.matrix td:first-child{font-weight:800;color:#0D2240;font-size:10.5px}
|
||
.matrix .good{color:#16A34A;font-weight:700}
|
||
.matrix .bad{color:#DC2626;font-weight:700}
|
||
.matrix .ok{color:#D97706;font-weight:700}
|
||
.matrix .best{background:#E0F2FE;font-weight:700;color:#0369A1}
|
||
|
||
/* ── Spec disclaimer ─── */
|
||
.spec-disclaimer{background:#FFF8E1;border:1.5px solid #FFC107;border-radius:6px;padding:11px 16px;font-size:11px;color:#6D4C00;margin-bottom:32px;line-height:1.6}
|
||
.spec-disclaimer strong{font-weight:800}
|
||
|
||
/* ── impl-ref ─── */
|
||
.impl-ref{background:#0d1117;border-radius:8px;margin-top:20px;overflow:hidden;border:1px solid #30363d}
|
||
.impl-ref-hdr{background:#161b22;padding:9px 16px;font-size:9.5px;font-weight:800;color:#f0883e;border-bottom:1px solid #30363d;display:flex;align-items:center;gap:8px;letter-spacing:.4px;text-transform:uppercase}
|
||
.impl-ref-hdr::before{content:'⚙';font-size:12px}
|
||
.impl-ref-hdr span{color:rgba(240,136,62,.55);font-weight:400;margin-left:auto;font-size:9px;text-transform:none;letter-spacing:0}
|
||
.impl-ref table{width:100%;border-collapse:collapse;font-size:10px}
|
||
.impl-ref th{text-align:left;font-size:8px;font-weight:800;text-transform:uppercase;letter-spacing:.8px;color:#8b949e;padding:8px 14px;border-bottom:1px solid #21262d}
|
||
.impl-ref td{padding:6px 14px;border-bottom:1px solid #161b22;vertical-align:top;line-height:1.6;color:#c9d1d9}
|
||
.impl-ref tr:last-child td{border-bottom:none}
|
||
.impl-ref td:first-child{color:#79c0ff;font-weight:700;white-space:nowrap;width:200px}
|
||
.impl-ref td code{font-family:'SFMono-Regular',Consolas,monospace;font-size:9.5px;background:#161b22;color:#a5d6ff;padding:1px 5px;border-radius:3px;white-space:nowrap}
|
||
.impl-ref .ir-px{color:#7ee787;font-family:monospace;font-size:9.5px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="doc">
|
||
|
||
<!-- ══════════════════════════════════════
|
||
MASTHEAD
|
||
══════════════════════════════════════ -->
|
||
<div class="mast">
|
||
<div class="mast-top">
|
||
<div>
|
||
<h1>Sort Integration — 4 Exploration Variants</h1>
|
||
<p>Four distinct approaches for adding sort controls to the document search. Issue #180 (Problem 1). Each variant has a different placement philosophy — choose based on the user model you want to reinforce. Not a final spec; pick one and lock it down.</p>
|
||
</div>
|
||
<span class="mast-badge mb-exploration">Exploration · Pick One</span>
|
||
</div>
|
||
<div class="decisions">
|
||
<div class="dec">
|
||
<div class="dec-label">Issue</div>
|
||
<div class="dec-value">#180 — Sort & Search UX</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Sort options (6)</div>
|
||
<div class="dec-value">Datum · Titel · Absender · Empfänger · Tag · Hochgeladen</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">Direction</div>
|
||
<div class="dec-value">Aufsteigend ↑ / Absteigend ↓ per option</div>
|
||
</div>
|
||
<div class="dec">
|
||
<div class="dec-label">New URL params</div>
|
||
<div class="dec-value"><code style="font-size:8.5px;color:#A6DAD8">?sort=date&dir=desc</code></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── spec disclaimer ── -->
|
||
<div class="spec-disclaimer">
|
||
<strong>📐 Mockup scale notice —</strong> all font-size, height, and padding values
|
||
in the mockup CSS are scaled to ~55% of actual implementation values.
|
||
<strong>Do not copy sizes from mockup CSS.</strong> Use the ⚙ Implementation
|
||
Reference tables after each section.
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════
|
||
VARIANT A — INLINE SORT IN SEARCH ROW
|
||
══════════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h">
|
||
<span class="sec-num">A</span>
|
||
<span class="sec-variant">Inline sort in search bar row</span>
|
||
Sort dropdown sits directly in row 1 — always visible, no extra space
|
||
</div>
|
||
|
||
<div class="variant-meta">
|
||
<div class="vm-col pros">
|
||
<h3>Pros</h3>
|
||
<ul>
|
||
<li>Always visible — zero discovery friction</li>
|
||
<li>Sort and search feel like one cohesive control surface</li>
|
||
<li>Familiar pattern (GitHub Issues, Notion tables)</li>
|
||
<li>Active state is immediately legible without opening anything</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col cons">
|
||
<h3>Cons</h3>
|
||
<ul>
|
||
<li>Row 1 gets crowded at 320px — needs a wrapping strategy</li>
|
||
<li>Sort button competes visually with Filter button</li>
|
||
<li>Dropdown overlaps results on short viewports</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col when">
|
||
<h3>Best when</h3>
|
||
<ul>
|
||
<li>Sort is a primary, frequently changed action</li>
|
||
<li>Users already understand the search bar as a control hub</li>
|
||
<li>You want to minimize total UI surface area</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg sg-2" style="gap:24px;align-items:start">
|
||
|
||
<!-- Desktop mockup with dropdown open -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop — dropdown open</div>
|
||
<div class="wf">
|
||
<div class="wf-bar">
|
||
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
|
||
<div class="urlbar"><span>localhost:3000/?q=brief&sort=date&dir=desc</span></div>
|
||
</div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl on">Dokumente</span>
|
||
<span class="nl">Personen</span>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="SCARD">
|
||
<div class="SROW1">
|
||
<!-- Search input with spinner (search in progress) -->
|
||
<div class="SINPUT active">
|
||
<div class="SINPUT-SPINNER"></div>
|
||
<span style="font-size:8px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<!-- Sort button — ACTIVE, dropdown open -->
|
||
<div style="position:relative">
|
||
<div class="SBTN sort-active" style="gap:5px">
|
||
<span style="font-size:7px;color:#888;font-weight:400">Sortieren:</span>
|
||
Datum ↓
|
||
<span class="SCHEV up">▾</span>
|
||
</div>
|
||
<!-- Dropdown -->
|
||
<div class="SDROP" style="position:absolute;top:24px;left:0;width:160px">
|
||
<div class="SDROP-ROW active">
|
||
<span class="SDROP-LABEL">Datum</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D active">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Titel</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Absender</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Empfänger</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Tag</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Hochgeladen</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D">↓</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Filter button -->
|
||
<div class="SBTN filter">
|
||
<span>⊞</span> Filter
|
||
<span class="SCHEV">▾</span>
|
||
</div>
|
||
<!-- Reset -->
|
||
<div class="SBTN reset">✕</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Result count -->
|
||
<div class="RESHEAD" style="margin-top:2px">
|
||
<div class="RESHEAD-COUNT"><strong>12 Dokumente</strong> gefunden</div>
|
||
</div>
|
||
|
||
<!-- Doc list -->
|
||
<div class="DOCLIST">
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Brief an Tante Klara, Weihnachten 1954</div>
|
||
<div class="DOCROW-META">
|
||
<span>15. Dezember 1954</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span>Ernst Raddatz → Klara Meier</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span class="DOCROW-TAG">Briefe</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Briefwechsel Sommer 1961</div>
|
||
<div class="DOCROW-META">
|
||
<span>3. Juli 1961</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span>Hildegard Raddatz → Stadtamt</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span class="DOCROW-TAG">Verwaltung</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Sort button sits between search input and Filter button. Dropdown shows all 6 options with per-option ↑/↓ direction toggle. Active option highlighted in navy.</div>
|
||
</div>
|
||
|
||
<!-- Mobile mockup -->
|
||
<div class="sb">
|
||
<div class="sl">Mobile 320px — collapsed (no open dropdown)</div>
|
||
<div class="WF-M">
|
||
<div class="WF-M-STATUS">
|
||
<span class="WF-M-TIME">9:41</span>
|
||
<div class="WF-M-ICONS"><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div></div>
|
||
</div>
|
||
<div class="N-M">
|
||
<span class="logo" style="font-size:7px">FAMILIENARCHIV</span>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN-SM">
|
||
<div class="SCARD-SM">
|
||
<!-- Mobile: row 1 has search + reset only -->
|
||
<div style="display:flex;gap:4px;margin-bottom:5px">
|
||
<div class="SINPUT active" style="height:22px">
|
||
<div class="SINPUT-ICON">⌕</div>
|
||
<span style="font-size:7.5px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<div class="SBTN reset" style="height:22px">✕</div>
|
||
</div>
|
||
<!-- Mobile: row 2 has sort + filter as full-width buttons -->
|
||
<div style="display:flex;gap:4px">
|
||
<div class="SBTN sort-active" style="height:20px;flex:1;justify-content:center;font-size:7.5px">
|
||
Datum ↓ <span class="SCHEV">▾</span>
|
||
</div>
|
||
<div class="SBTN filter" style="height:20px;flex:1;justify-content:center;font-size:7.5px">
|
||
⊞ Filter
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:7px;font-weight:700;color:#555">12 Dokumente gefunden</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="PH w80" style="margin-bottom:4px"></div>
|
||
<div class="PH w50"></div>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="PH w70" style="margin-bottom:4px"></div>
|
||
<div class="PH w40"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">On mobile, sort wraps to a second row inside the search card. Both sort and filter become equal-width buttons — same touch target, consistent layout.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Variant A: Inline Sort
|
||
<span>Real values · mockup above is ~55% scale · do not copy mockup CSS</span>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Sort trigger button</td>
|
||
<td><code>h-10 flex items-center gap-2 border border-line px-3 text-sm font-bold text-ink-2 bg-muted hover:bg-surface transition whitespace-nowrap rounded-sm</code></td>
|
||
<td><span class="ir-px">h 40px, px 12px</span></td>
|
||
<td>Active state: <code>border-brand-navy text-brand-navy bg-surface</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort prefix label</td>
|
||
<td><code>text-xs font-normal text-ink-3 mr-1</code></td>
|
||
<td><span class="ir-px">12px / 400</span></td>
|
||
<td>"Sortieren:" prefix — hide on mobile with <code>hidden sm:inline</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort dropdown container</td>
|
||
<td><code>absolute top-full left-0 z-50 min-w-[180px] bg-surface border border-brand-navy border-t-0 shadow-lg rounded-b-sm</code></td>
|
||
<td><span class="ir-px">min-w 180px</span></td>
|
||
<td>Opens below button; close on outside click via <code>onpointerdown</code> listener</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dropdown option row</td>
|
||
<td><code>flex items-center px-3 py-2.5 gap-3 border-b border-line cursor-pointer hover:bg-muted last:border-b-0</code></td>
|
||
<td><span class="ir-px">h ~40px, py 10px</span></td>
|
||
<td>Touch target ≥ 44px — most commonly undersized element</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dropdown option label</td>
|
||
<td><code>flex-1 text-sm font-semibold text-ink</code></td>
|
||
<td><span class="ir-px">14px / 600</span></td>
|
||
<td>Active row: <code>text-brand-navy</code> + row background <code>bg-blue-50</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction toggle (↑/↓)</td>
|
||
<td><code>flex gap-1</code> — each button: <code>text-xs font-bold px-1.5 py-0.5 rounded-sm border border-transparent text-ink-3</code></td>
|
||
<td><span class="ir-px">24px touch area min</span></td>
|
||
<td>Active direction: <code>bg-brand-navy text-white border-brand-navy</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Mobile: sort + filter row</td>
|
||
<td><code>flex gap-2 mt-2</code> — each button adds <code>flex-1 justify-center</code></td>
|
||
<td><span class="ir-px">h 40px, flex-1</span></td>
|
||
<td>Wraps to second line inside <code>.SCARD</code> below sm. Both buttons equal width.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>New URL params</td>
|
||
<td><code>sort</code> + <code>dir</code></td>
|
||
<td>—</td>
|
||
<td>Values: <code>sort=date|title|sender|receiver|tag|uploaded</code>, <code>dir=asc|desc</code>. Add to <code>triggerSearch()</code> in <code>+page.svelte</code> and to <code>/api/documents/search</code> query params.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════
|
||
VARIANT B — SORT PILL STRIP (BELOW SEARCH CARD)
|
||
══════════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h">
|
||
<span class="sec-num">B</span>
|
||
<span class="sec-variant">Sort pill strip below search card</span>
|
||
A horizontally scrollable row of pills between search and results
|
||
</div>
|
||
|
||
<div class="variant-meta">
|
||
<div class="vm-col pros">
|
||
<h3>Pros</h3>
|
||
<ul>
|
||
<li>All 6 options visible at a glance — no dropdown needed</li>
|
||
<li>Active sort is unmistakable (navy pill, always in view)</li>
|
||
<li>Natural horizontal scroll on mobile — familiar to users</li>
|
||
<li>Search bar stays clean and single-purpose</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col cons">
|
||
<h3>Cons</h3>
|
||
<ul>
|
||
<li>Adds a full row of vertical space even when sort isn't used</li>
|
||
<li>6 options may overflow without scroll cue on narrow screens</li>
|
||
<li>Seniors may not discover horizontal scroll on mobile</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col when">
|
||
<h3>Best when</h3>
|
||
<ul>
|
||
<li>Sort is a secondary action but users switch it often</li>
|
||
<li>You want sort visible without modal/dropdown overhead</li>
|
||
<li>The team prefers a "tab strip" mental model over a select</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg sg-2" style="gap:24px;align-items:start">
|
||
|
||
<!-- Desktop -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop — "Absender" active, ascending</div>
|
||
<div class="wf">
|
||
<div class="wf-bar">
|
||
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
|
||
<div class="urlbar"><span>localhost:3000/?q=brief&sort=sender&dir=asc</span></div>
|
||
</div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl on">Dokumente</span>
|
||
<span class="nl">Personen</span>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<!-- Search card (clean, no sort inside) -->
|
||
<div class="SCARD">
|
||
<div class="SROW1">
|
||
<div class="SINPUT">
|
||
<div class="SINPUT-ICON">⌕</div>
|
||
<span style="font-size:8px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<div class="SBTN filter">⊞ Filter <span class="SCHEV">▾</span></div>
|
||
<div class="SBTN reset">✕</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sort pill strip (separate card) -->
|
||
<div class="SPILLS">
|
||
<span class="SPILLS-LABEL">Sortieren:</span>
|
||
<div class="SPILL">Datum <span class="SPILL-DIR">↓</span></div>
|
||
<div class="SPILL">Titel</div>
|
||
<div class="SPILL active">Absender ↑</div>
|
||
<div class="SPILL">Empfänger</div>
|
||
<div class="SPILL">Tag</div>
|
||
<div class="SPILL">Hochgeladen</div>
|
||
<!-- Direction toggle far right -->
|
||
<div class="SPILLS-SEP"></div>
|
||
<div class="SPILLS-DIRBTN active">↑ A–Z</div>
|
||
<div class="SPILLS-DIRBTN">↓ Z–A</div>
|
||
</div>
|
||
|
||
<!-- Result count -->
|
||
<div class="RESHEAD">
|
||
<div class="RESHEAD-COUNT"><strong>12 Dokumente</strong>, sortiert nach Absender ↑</div>
|
||
</div>
|
||
|
||
<!-- Doc list sorted by sender -->
|
||
<div class="DOCLIST">
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Brief an Tante Klara, Weihnachten 1954</div>
|
||
<div class="DOCROW-META">
|
||
<span>Ernst Raddatz</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span>15. Dez 1954</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span class="DOCROW-TAG">Briefe</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Urlaubspostkarte 1962</div>
|
||
<div class="DOCROW-META">
|
||
<span>Hildegard Raddatz</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span>8. Aug 1962</span>
|
||
<span class="DOCROW-META-SEP">·</span>
|
||
<span class="DOCROW-TAG">Karten</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Pill strip lives between search card and results as its own card. Active pill is navy-filled. Direction buttons (↑/↓) are separate toggle at the right end. Result count confirms active sort.</div>
|
||
</div>
|
||
|
||
<!-- Mobile -->
|
||
<div class="sb">
|
||
<div class="sl">Mobile 320px — horizontal scroll</div>
|
||
<div class="WF-M">
|
||
<div class="WF-M-STATUS">
|
||
<span class="WF-M-TIME">9:41</span>
|
||
<div class="WF-M-ICONS"><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div></div>
|
||
</div>
|
||
<div class="N-M">
|
||
<span class="logo" style="font-size:7px">FAMILIENARCHIV</span>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN-SM">
|
||
<div class="SCARD-SM">
|
||
<div style="display:flex;gap:4px">
|
||
<div class="SINPUT" style="height:22px">
|
||
<span style="font-size:7.5px;color:#9CA3AF;font-style:italic">brief</span>
|
||
</div>
|
||
<div class="SBTN filter" style="height:22px;font-size:7px">⊞</div>
|
||
<div class="SBTN reset" style="height:22px">✕</div>
|
||
</div>
|
||
</div>
|
||
<!-- Pill strip — shows partial pills to signal scroll -->
|
||
<div class="SPILLS" style="padding:5px 8px;gap:5px">
|
||
<div class="SPILL" style="font-size:7px;height:15px;padding:0 7px">Datum ↓</div>
|
||
<div class="SPILL active" style="font-size:7px;height:15px;padding:0 7px">Absender ↑</div>
|
||
<div class="SPILL" style="font-size:7px;height:15px;padding:0 7px">Empfänger</div>
|
||
<div class="SPILL" style="font-size:7px;height:15px;padding:0 7px;opacity:.4">Tag…</div>
|
||
</div>
|
||
<div style="font-size:7px;font-weight:700;color:#555">12 Dokumente, Absender ↑</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY"><div class="PH w70" style="margin-bottom:4px"></div><div class="PH w50"></div></div>
|
||
</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY"><div class="PH w80" style="margin-bottom:4px"></div><div class="PH w40"></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">On mobile the pill row clips at screen edge — the half-visible last pill cues horizontal scroll. Direction toggle moves inside the active pill label (↑/↓ suffix). Min touch target: 44px height enforced in implementation.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ann-block" style="margin-top:16px">
|
||
<strong>Senior accessibility note:</strong> Horizontal scroll is invisible on desktop and may be missed by seniors on tablet. Consider adding a faint right-fade gradient mask (<code>-webkit-mask-image: linear-gradient(to right, #000 80%, transparent)</code>) to the pill container to signal overflow.
|
||
</div>
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Variant B: Sort Pill Strip
|
||
<span>Real values · mockup above is ~55% scale</span>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Pill strip container</td>
|
||
<td><code>flex items-center gap-2 overflow-x-auto bg-surface border border-line rounded-sm px-4 py-3 shadow-sm scroll-smooth</code></td>
|
||
<td><span class="ir-px">h ~48px, py 12px</span></td>
|
||
<td>Add <code>scrollbar-hide</code> (Tailwind plugin) or <code>::-webkit-scrollbar { display: none }</code>. Right-fade mask on mobile.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>"Sortieren:" label</td>
|
||
<td><code>text-xs font-bold uppercase tracking-widest text-ink-3 shrink-0 mr-1</code></td>
|
||
<td><span class="ir-px">12px / 700</span></td>
|
||
<td>Hide on mobile: <code>hidden sm:block</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Inactive pill</td>
|
||
<td><code>h-8 shrink-0 flex items-center gap-1 px-3 rounded-full border border-line text-sm font-semibold text-ink-2 cursor-pointer hover:border-brand-navy hover:text-brand-navy transition whitespace-nowrap</code></td>
|
||
<td><span class="ir-px">h 32px, px 12px</span></td>
|
||
<td>Touch target: wrap in <code>min-h-[44px] flex items-center</code> on mobile. Most commonly undersized element.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Active pill</td>
|
||
<td>Inactive classes + <code>bg-brand-navy text-white border-brand-navy</code></td>
|
||
<td><span class="ir-px">h 32px</span></td>
|
||
<td>Shows direction suffix: "Absender ↑". Screen reader: <code>aria-pressed="true"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction toggles (↑/↓)</td>
|
||
<td><code>shrink-0 h-8 flex items-center gap-1 px-3 border border-line text-sm font-bold text-ink-2 rounded-sm cursor-pointer hover:border-brand-navy transition</code></td>
|
||
<td><span class="ir-px">h 32px, px 12px</span></td>
|
||
<td>Active: <code>border-brand-navy text-brand-navy</code>. <code>aria-label="Aufsteigend"</code> / <code>"Absteigend"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Separator</td>
|
||
<td><code>w-px h-5 bg-line shrink-0 mx-1</code></td>
|
||
<td><span class="ir-px">1px × 20px</span></td>
|
||
<td>Divides pills from direction buttons. <code>role="separator" aria-hidden="true"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Result count confirmation</td>
|
||
<td><code>text-sm font-medium text-ink-2 mb-2</code></td>
|
||
<td><span class="ir-px">14px</span></td>
|
||
<td>Text: "12 Dokumente, sortiert nach Absender ↑". Live region: <code>aria-live="polite"</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════
|
||
VARIANT C — RESULT-HEADER SORT (ABOVE DOCUMENT LIST)
|
||
══════════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h">
|
||
<span class="sec-num">C</span>
|
||
<span class="sec-variant">Sort in the result-list header</span>
|
||
Sort lives above the document list, co-located with result count — zero search bar pollution
|
||
</div>
|
||
|
||
<div class="variant-meta">
|
||
<div class="vm-col pros">
|
||
<h3>Pros</h3>
|
||
<ul>
|
||
<li>Search bar stays completely clean — single responsibility</li>
|
||
<li>Sort sits next to what it affects — contextually obvious</li>
|
||
<li>Result count + sort in one bar = efficient use of space</li>
|
||
<li>Pattern familiar from e-commerce (Amazon, Zalando)</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col cons">
|
||
<h3>Cons</h3>
|
||
<ul>
|
||
<li>Sort is below the fold on mobile — users may not scroll to find it</li>
|
||
<li>Only visible in search mode (disappears on dashboard)</li>
|
||
<li>Seniors may not understand why sort isn't near the search input</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col when">
|
||
<h3>Best when</h3>
|
||
<ul>
|
||
<li>Sort is considered a result-manipulation tool, not a search param</li>
|
||
<li>The result list is long enough to justify a persistent header</li>
|
||
<li>You want a clean aesthetic in the search bar at all costs</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg sg-2" style="gap:24px;align-items:start">
|
||
|
||
<!-- Desktop -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop — sort dropdown open</div>
|
||
<div class="wf">
|
||
<div class="wf-bar">
|
||
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
|
||
<div class="urlbar"><span>localhost:3000/?q=brief&sort=date&dir=desc</span></div>
|
||
</div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl on">Dokumente</span>
|
||
<span class="nl">Personen</span>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<!-- Clean search card — no sort here -->
|
||
<div class="SCARD">
|
||
<div class="SROW1">
|
||
<div class="SINPUT active">
|
||
<div class="SINPUT-SPINNER"></div>
|
||
<span style="font-size:8px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<div class="SBTN filter">⊞ Filter <span class="SCHEV">▾</span></div>
|
||
<div class="SBTN reset">✕</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Result header with sort -->
|
||
<div class="RESHEAD" style="padding:8px 12px;background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;margin-top:0">
|
||
<div class="RESHEAD-COUNT"><strong>12 Dokumente</strong> gefunden</div>
|
||
<div style="position:relative">
|
||
<!-- Sort trigger -->
|
||
<div class="RESHEAD-SORT active">
|
||
<span class="RESHEAD-SORTLABEL">Sortieren:</span>
|
||
Datum ↓
|
||
<span class="SCHEV up">▾</span>
|
||
</div>
|
||
<!-- Dropdown -->
|
||
<div class="SDROP" style="position:absolute;top:22px;right:0;width:160px">
|
||
<div class="SDROP-ROW active">
|
||
<span class="SDROP-LABEL">Datum</span>
|
||
<div class="SDROP-DIR">
|
||
<span class="SDROP-D">↑</span>
|
||
<span class="SDROP-D active">↓</span>
|
||
</div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Titel</span>
|
||
<div class="SDROP-DIR"><span class="SDROP-D">↑</span><span class="SDROP-D">↓</span></div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Absender</span>
|
||
<div class="SDROP-DIR"><span class="SDROP-D">↑</span><span class="SDROP-D">↓</span></div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Empfänger</span>
|
||
<div class="SDROP-DIR"><span class="SDROP-D">↑</span><span class="SDROP-D">↓</span></div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Tag</span>
|
||
<div class="SDROP-DIR"><span class="SDROP-D">↑</span><span class="SDROP-D">↓</span></div>
|
||
</div>
|
||
<div class="SDROP-ROW">
|
||
<span class="SDROP-LABEL">Hochgeladen</span>
|
||
<div class="SDROP-DIR"><span class="SDROP-D">↑</span><span class="SDROP-D">↓</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Doc list -->
|
||
<div class="DOCLIST" style="margin-top:-5px">
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Brief an Tante Klara, Weihnachten 1954</div>
|
||
<div class="DOCROW-META"><span>15. Dez 1954</span><span class="DOCROW-META-SEP">·</span><span>Ernst Raddatz</span><span class="DOCROW-META-SEP">·</span><span class="DOCROW-TAG">Briefe</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Briefwechsel Sommer 1961</div>
|
||
<div class="DOCROW-META"><span>3. Jul 1961</span><span class="DOCROW-META-SEP">·</span><span>Hildegard Raddatz</span><span class="DOCROW-META-SEP">·</span><span class="DOCROW-TAG">Verwaltung</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Result header is its own card above the document list. Left: result count. Right: sort dropdown trigger. Sort dropdown opens upward on mobile if needed. This variant only renders during search — not on dashboard.</div>
|
||
</div>
|
||
|
||
<!-- Mobile -->
|
||
<div class="sb">
|
||
<div class="sl">Mobile 320px — result header sticky</div>
|
||
<div class="WF-M">
|
||
<div class="WF-M-STATUS">
|
||
<span class="WF-M-TIME">9:41</span>
|
||
<div class="WF-M-ICONS"><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div><div class="WF-M-ICON"></div></div>
|
||
</div>
|
||
<div class="N-M">
|
||
<span class="logo" style="font-size:7px">FAMILIENARCHIV</span>
|
||
<div class="nico"></div>
|
||
</div>
|
||
<div class="MAIN-SM">
|
||
<div class="SCARD-SM">
|
||
<div style="display:flex;gap:4px">
|
||
<div class="SINPUT" style="height:22px"><span style="font-size:7.5px;color:#1a1a1a">brief</span></div>
|
||
<div class="SBTN filter" style="height:22px;font-size:7px">⊞</div>
|
||
<div class="SBTN reset" style="height:22px">✕</div>
|
||
</div>
|
||
</div>
|
||
<!-- Result header — sticky on mobile -->
|
||
<div style="background:#fff;border:1.5px solid #E0DDD6;border-radius:3px;padding:5px 9px;display:flex;align-items:center;gap:6px;position:sticky;top:0">
|
||
<span style="font-size:7px;font-weight:700;color:#555;flex:1"><strong style="color:#002850">12</strong> Dok.</span>
|
||
<div class="RESHEAD-SORT active" style="height:18px;font-size:7px;padding:0 7px">
|
||
<span style="font-size:6.5px;color:#AAA">Sort:</span>
|
||
Datum ↓ <span class="SCHEV up" style="font-size:6px">▾</span>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY"><div class="PH w80" style="margin-bottom:4px"></div><div class="PH w50"></div></div>
|
||
</div>
|
||
<div class="DOCROW" style="padding:6px 9px">
|
||
<div class="DOCROW-THUMB" style="width:18px;height:22px">PDF</div>
|
||
<div class="DOCROW-BODY"><div class="PH w60" style="margin-bottom:4px"></div><div class="PH w40"></div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Result header is <code>position: sticky; top: 0</code> on mobile so it stays in view while scrolling the document list. Sort dropdown opens upward (<code>bottom: 100%</code>) to avoid viewport overflow.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Variant C: Result-Header Sort
|
||
<span>Real values · mockup above is ~55% scale</span>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Result header bar</td>
|
||
<td><code>flex items-center gap-3 px-4 py-3 bg-surface border border-line rounded-sm shadow-sm sticky top-0 z-20</code></td>
|
||
<td><span class="ir-px">h ~48px, py 12px</span></td>
|
||
<td>Sticky on mobile. Only rendered when <code>!isDashboard</code> — wrap in <code>{#if !data.isDashboard}</code> in <code>+page.svelte</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Result count text</td>
|
||
<td><code>flex-1 text-sm font-medium text-ink-2</code></td>
|
||
<td><span class="ir-px">14px / 500</span></td>
|
||
<td><code><strong class="text-brand-navy">12</strong> Dokumente gefunden</code>. <code>aria-live="polite"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort trigger (result header)</td>
|
||
<td><code>h-9 flex items-center gap-2 border border-line px-3 text-sm font-bold text-ink-2 bg-surface rounded-sm hover:border-brand-navy transition whitespace-nowrap</code></td>
|
||
<td><span class="ir-px">h 36px, px 12px</span></td>
|
||
<td>Active: <code>border-brand-navy text-brand-navy</code>. Touch target min 44px: add <code>min-h-[44px]</code> on mobile.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort dropdown (result header)</td>
|
||
<td><code>absolute bottom-full right-0 mb-1 z-50 min-w-[180px] bg-surface border border-brand-navy shadow-lg rounded-sm</code></td>
|
||
<td><span class="ir-px">min-w 180px</span></td>
|
||
<td>Opens upward (<code>bottom-full</code>) on mobile to stay in viewport. Same option rows as Variant A.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dropdown option row</td>
|
||
<td><code>flex items-center px-3 py-2.5 gap-3 border-b border-line last:border-b-0 cursor-pointer hover:bg-muted</code></td>
|
||
<td><span class="ir-px">h ~40px</span></td>
|
||
<td>Touch target ≥ 44px — most commonly undersized</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction toggle</td>
|
||
<td>Same as Variant A direction toggle</td>
|
||
<td>—</td>
|
||
<td>Reuse same component</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Svelte placement</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
<td>Add <code>ResultHeader.svelte</code> component. Render between <code>SearchFilterBar</code> and <code>DocumentList</code> in <code>+page.svelte</code>, only when <code>!data.isDashboard</code>.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════
|
||
VARIANT D — SORT INSIDE ADVANCED FILTER PANEL
|
||
══════════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h">
|
||
<span class="sec-num">D</span>
|
||
<span class="sec-variant">Sort inside the advanced filter panel</span>
|
||
Sort lives at the top of the collapsible "Filter" section — hidden by default
|
||
</div>
|
||
|
||
<div class="variant-meta">
|
||
<div class="vm-col pros">
|
||
<h3>Pros</h3>
|
||
<ul>
|
||
<li>Zero additional chrome when filters are closed</li>
|
||
<li>Logical grouping: "filtering and sorting" as one concept</li>
|
||
<li>Reveals naturally when filter badge shows active sort</li>
|
||
<li>Works well if sort is rarely changed once set</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col cons">
|
||
<h3>Cons</h3>
|
||
<ul>
|
||
<li>Discoverability is low — users must click "Filter" to find sort</li>
|
||
<li>Seniors may not think to look inside "Filter" for sort</li>
|
||
<li>Active sort is invisible when filter panel is collapsed</li>
|
||
</ul>
|
||
</div>
|
||
<div class="vm-col when">
|
||
<h3>Best when</h3>
|
||
<ul>
|
||
<li>Sort is rarely changed (users set it once and leave it)</li>
|
||
<li>You want to keep the primary UI completely minimal</li>
|
||
<li>The Filter button shows an active-state badge when sort is non-default</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sg sg-2" style="gap:24px;align-items:start">
|
||
|
||
<!-- Desktop: filter open showing sort at top -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop — advanced filter open, sort section visible</div>
|
||
<div class="wf">
|
||
<div class="wf-bar">
|
||
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
|
||
<div class="urlbar"><span>localhost:3000/?q=brief&sort=sender&dir=asc</span></div>
|
||
</div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl on">Dokumente</span>
|
||
<span class="nl">Personen</span>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="SCARD">
|
||
<!-- Row 1: search bar — Filter button has a badge -->
|
||
<div class="SROW1">
|
||
<div class="SINPUT active">
|
||
<div class="SINPUT-ICON">⌕</div>
|
||
<span style="font-size:8px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<!-- Filter button WITH active badge (sort is set) -->
|
||
<div class="SBTN sort-active" style="position:relative">
|
||
⊞ Filter
|
||
<span style="position:absolute;top:-5px;right:-5px;width:9px;height:9px;background:#002850;border-radius:50%;border:1.5px solid #fff;display:flex;align-items:center;justify-content:center;font-size:5px;color:#fff;font-weight:900">1</span>
|
||
<span class="SCHEV up">▾</span>
|
||
</div>
|
||
<div class="SBTN reset">✕</div>
|
||
</div>
|
||
|
||
<!-- Advanced filter panel — OPEN -->
|
||
<div style="margin-top:10px;border-top:1px solid #E0DDD6;padding-top:10px;display:flex;flex-direction:column;gap:10px">
|
||
|
||
<!-- Sort section at TOP of advanced panel -->
|
||
<div class="ADVSORT">
|
||
<div class="ADVSORT-LABEL">Sortieren nach</div>
|
||
<div class="ADVSORT-PILLS">
|
||
<div class="ADVSORT-PILL">Datum</div>
|
||
<div class="ADVSORT-PILL">Titel</div>
|
||
<div class="ADVSORT-PILL active">Absender</div>
|
||
<div class="ADVSORT-PILL">Empfänger</div>
|
||
<div class="ADVSORT-PILL">Tag</div>
|
||
<div class="ADVSORT-PILL">Hochgeladen</div>
|
||
</div>
|
||
<div class="ADVSORT-DIRS">
|
||
<div class="ADVSORT-DIR active">↑ Aufsteigend</div>
|
||
<div class="ADVSORT-DIR">↓ Absteigend</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Existing filter fields below sort -->
|
||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;font-size:7.5px">
|
||
<div>
|
||
<div style="font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:4px">Absender</div>
|
||
<div style="height:20px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 7px;color:#C8C4BE;font-style:italic;font-size:7.5px">Person wählen…</div>
|
||
</div>
|
||
<div>
|
||
<div style="font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:4px">Empfänger</div>
|
||
<div style="height:20px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 7px;color:#C8C4BE;font-style:italic;font-size:7.5px">Person wählen…</div>
|
||
</div>
|
||
<div>
|
||
<div style="font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:4px">Von</div>
|
||
<div style="height:20px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 7px;color:#C8C4BE;font-style:italic;font-size:7.5px">Datum…</div>
|
||
</div>
|
||
<div>
|
||
<div style="font-size:7px;font-weight:800;text-transform:uppercase;letter-spacing:.5px;color:#888;margin-bottom:4px">Bis</div>
|
||
<div style="height:20px;border:1.5px solid #D1D5DB;border-radius:2px;display:flex;align-items:center;padding:0 7px;color:#C8C4BE;font-style:italic;font-size:7.5px">Datum…</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Result count + doc list -->
|
||
<div class="RESHEAD"><div class="RESHEAD-COUNT"><strong>12 Dokumente</strong>, sortiert nach Absender ↑</div></div>
|
||
<div class="DOCLIST">
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Brief an Tante Klara, Weihnachten 1954</div>
|
||
<div class="DOCROW-META"><span>Ernst Raddatz</span><span class="DOCROW-META-SEP">·</span><span>15. Dez 1954</span><span class="DOCROW-META-SEP">·</span><span class="DOCROW-TAG">Briefe</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Sort sits at the top of the advanced filter panel — above Absender, Empfänger, dates. When sort is non-default, the Filter button shows a navy badge with the count of active modifiers (sort + any active filters).</div>
|
||
</div>
|
||
|
||
<!-- Desktop: filter CLOSED, showing badge -->
|
||
<div class="sb">
|
||
<div class="sl">Desktop — filter closed, active badge visible</div>
|
||
<div class="wf">
|
||
<div class="wf-bar">
|
||
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
|
||
<div class="urlbar"><span>localhost:3000/?q=brief&sort=sender&dir=asc</span></div>
|
||
</div>
|
||
<div class="N">
|
||
<span class="logo">FAMILIENARCHIV</span>
|
||
<span class="nl on">Dokumente</span>
|
||
<span class="nl">Personen</span>
|
||
<div class="nr"><div class="nico"></div></div>
|
||
</div>
|
||
<div class="MAIN">
|
||
<div class="SCARD">
|
||
<div class="SROW1">
|
||
<div class="SINPUT active">
|
||
<div class="SINPUT-ICON">⌕</div>
|
||
<span style="font-size:8px;color:#1a1a1a">brief</span>
|
||
</div>
|
||
<div class="SBTN sort-active" style="position:relative">
|
||
⊞ Filter (1)
|
||
<span class="SCHEV">▾</span>
|
||
</div>
|
||
<div class="SBTN reset">✕</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="RESHEAD"><div class="RESHEAD-COUNT"><strong>12 Dokumente</strong>, sortiert nach Absender ↑</div></div>
|
||
<div class="DOCLIST">
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Brief an Tante Klara, Weihnachten 1954</div>
|
||
<div class="DOCROW-META"><span>Ernst Raddatz</span><span class="DOCROW-META-SEP">·</span><span>15. Dez 1954</span><span class="DOCROW-META-SEP">·</span><span class="DOCROW-TAG">Briefe</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="DOCROW">
|
||
<div class="DOCROW-THUMB">PDF</div>
|
||
<div class="DOCROW-BODY">
|
||
<div class="DOCROW-TITLE">Briefwechsel Sommer 1961</div>
|
||
<div class="DOCROW-META"><span>Hildegard Raddatz</span><span class="DOCROW-META-SEP">·</span><span>3. Jul 1961</span><span class="DOCROW-META-SEP">·</span><span class="DOCROW-TAG">Verwaltung</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sc">Filter button shows "(1)" suffix when sort is non-default. The result count line confirms active sort. This is the only surface that signals sort is active when the panel is collapsed — the discoverability weakness of this variant.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ann-block">
|
||
<strong>Discoverability mitigation:</strong> If choosing Variant D, the Filter button label should read "Filter (1)" (or show a dot badge) whenever sort is non-default. Additionally, the result-count line should always name the active sort: "12 Dokumente, Absender ↑". These two surfaces together are the only visual hints that a sort is active when the panel is closed.
|
||
</div>
|
||
|
||
<div class="impl-ref">
|
||
<div class="impl-ref-hdr">Implementation Reference — Variant D: Sort in Advanced Filter Panel
|
||
<span>Real values · mockup above is ~55% scale</span>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Element</th><th>Tailwind classes</th><th>Real size</th><th>Notes</th></tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Sort section in panel</td>
|
||
<td><code>border-b border-line pb-5 mb-5</code></td>
|
||
<td>—</td>
|
||
<td>First child inside the <code>transition:slide</code> panel in <code>SearchFilterBar.svelte</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort section label</td>
|
||
<td><code>text-xs font-bold uppercase tracking-widest text-ink-2 mb-3 block</code></td>
|
||
<td><span class="ir-px">12px / 700</span></td>
|
||
<td>"SORTIEREN NACH"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Sort option pills row</td>
|
||
<td><code>flex flex-wrap gap-2 mb-3</code></td>
|
||
<td>—</td>
|
||
<td>Wraps on mobile. 6 pills total.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Inactive sort pill</td>
|
||
<td><code>h-9 flex items-center px-4 rounded-full border border-line text-sm font-semibold text-ink-2 cursor-pointer hover:border-brand-navy transition whitespace-nowrap</code></td>
|
||
<td><span class="ir-px">h 36px, px 16px</span></td>
|
||
<td>Touch target: <code>min-h-[44px]</code> on mobile. Most commonly undersized.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Active sort pill</td>
|
||
<td>Same + <code>bg-brand-navy text-white border-brand-navy</code></td>
|
||
<td>—</td>
|
||
<td><code>aria-pressed="true"</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction row</td>
|
||
<td><code>flex gap-2</code></td>
|
||
<td>—</td>
|
||
<td>Two buttons: "↑ Aufsteigend" / "↓ Absteigend"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Direction button</td>
|
||
<td><code>h-9 flex items-center gap-1.5 px-4 border border-line text-sm font-bold text-ink-2 rounded-sm cursor-pointer hover:border-brand-navy transition whitespace-nowrap</code></td>
|
||
<td><span class="ir-px">h 36px</span></td>
|
||
<td>Active: <code>bg-brand-navy text-white border-brand-navy</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Filter button badge count</td>
|
||
<td>Inline "(N)" text suffix or: <code>absolute -top-1.5 -right-1.5 w-4 h-4 rounded-full bg-brand-navy text-white text-[10px] font-bold flex items-center justify-center border-2 border-surface</code></td>
|
||
<td><span class="ir-px">16px badge</span></td>
|
||
<td>Count = number of active modifiers: active sort (if non-default) + active filter fields. Computed in <code>+page.svelte</code>.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════
|
||
COMPARISON MATRIX
|
||
══════════════════════════════════════ -->
|
||
<div class="sec">
|
||
<div class="sec-h">
|
||
<span class="sec-num">↔</span>
|
||
Variant comparison — pick one
|
||
</div>
|
||
|
||
<table class="matrix">
|
||
<thead>
|
||
<tr>
|
||
<th>Criterion</th>
|
||
<th>A — Inline</th>
|
||
<th>B — Pill strip</th>
|
||
<th>C — Result header</th>
|
||
<th>D — In filter panel</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Discoverability</td>
|
||
<td class="best">Excellent — always in view</td>
|
||
<td class="good">Good — visible strip</td>
|
||
<td class="ok">Medium — below search</td>
|
||
<td class="bad">Low — hidden by default</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Senior usability</td>
|
||
<td class="good">Good — labeled button</td>
|
||
<td class="ok">Medium — scroll may confuse</td>
|
||
<td class="ok">Medium — must scroll to find</td>
|
||
<td class="bad">Low — requires two taps to find</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Mobile footprint</td>
|
||
<td class="good">Good — wraps to row 2</td>
|
||
<td class="ok">Medium — extra full row</td>
|
||
<td class="best">Excellent — no extra row in search card</td>
|
||
<td class="best">Excellent — zero chrome when closed</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Search bar clarity</td>
|
||
<td class="ok">Medium — adds sort button to row 1</td>
|
||
<td class="good">Good — search bar unchanged</td>
|
||
<td class="best">Excellent — search bar 100% clean</td>
|
||
<td class="best">Excellent — search bar 100% clean</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Active state visibility</td>
|
||
<td class="best">Excellent — button label changes</td>
|
||
<td class="best">Excellent — active pill always visible</td>
|
||
<td class="good">Good — result header shows it</td>
|
||
<td class="bad">Low — only via badge + result count</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Implementation complexity</td>
|
||
<td class="ok">Medium — dropdown with dir toggle</td>
|
||
<td class="good">Low — pills + 2 buttons, no dropdown</td>
|
||
<td class="ok">Medium — new ResultHeader component</td>
|
||
<td class="good">Low — extends existing filter panel</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Keyboard / screen reader</td>
|
||
<td class="ok">Medium — dropdown needs focus trap</td>
|
||
<td class="best">Excellent — no dropdown, simple buttons</td>
|
||
<td class="ok">Medium — same dropdown focus trap</td>
|
||
<td class="best">Excellent — inside existing panel flow</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Recommended for this project</td>
|
||
<td class="best" style="font-weight:900;color:#002850">★ Primary recommendation</td>
|
||
<td class="good">Strong alternative if row 1 feels crowded</td>
|
||
<td style="color:#888">Suitable only if sort is secondary</td>
|
||
<td style="color:#888">Not recommended — discoverability gap</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<div class="ann-block" style="margin-top:20px">
|
||
<strong>Recommendation — Variant A (Inline) with Variant B (Pill strip) as fallback:</strong>
|
||
<ul>
|
||
<li>Variant A puts sort at 0-click distance, which matters most for seniors and first-time users</li>
|
||
<li>If the team finds row 1 too dense (especially at 375px), switch to Variant B — it keeps all 6 options visible without a dropdown and has the cleanest keyboard flow</li>
|
||
<li>Variant C is acceptable if the product decision is that sort is a result-manipulation tool (not a search param). Make the result header sticky so it stays accessible while scrolling</li>
|
||
<li>Variant D is not recommended: the discoverability deficit is too severe for the senior audience. The badge workaround is a patch, not a solution</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /doc -->
|
||
</body>
|
||
</html>
|