Adds the Mappe design handoff as in-repo ground truth and closes out the design-token foundation: --radius-sm/md/full + --shadow-sm/md tokens (distinct dark values in both dark blocks) and the canonical 10-color $lib/shared/avatarPalette.ts (AA-darkened sage/amber/sand swatches), guarded by avatarPalette.spec.ts. Closes #854.
12 KiB
EPIC: Familienarchiv Visual Redesign ("Mappe")
Implement in order. Stories 1–4 are foundation and shared primitives — every screen depends on them. Do not start a screen story until 1–4 are merged, or the header, avatar, and tokens get re-implemented per screen and drift. Read
DESIGN_RULES.mdfirst; open the matchingprototypes/*.dc.htmlfor pixel ground truth while building each story.
Epic goal
Reskin the entire Familienarchiv app to the unified "Mappe" archival direction and ship three new sections (Geschichten, Zeitstrahl, Aktivitäten). All copy German-first via Paraglide; light + dark mode; De Gruyter icon convention preserved.
Epic-level acceptance criteria
- All eight screens match their prototype in light and dark mode.
- Header, page-header, avatar, segmented control, and card exist as single shared components — zero duplication of the header markup or the avatar-color function.
- No raw hex in components; everything references the semantic tokens.
- Every visible string is a Paraglide message key, German authored first;
en/esstubs added. - Icons rendered as
<img>, invert correctly in dark mode. - No gradients, blur, emoji, or transform-based motion introduced.
Reframe (2026-06-16): this is alignment, not greenfield. An audit of the live codebase found the substrate already in place — the full token system (
DESIGN_RULES §1–2), dark mode, the app header, and the three "new" sections (Geschichten, Zeitstrahl, Aktivitäten) all already exist. So Stories 1–4 below are close-out + extraction, not from-scratch builds, and Stories 5–11 are "align the existing screen to its prototype," not new pages. The detailed, trackable breakdown lives in the Gitea milestone "Mappe Visual Redesign" (issues split into shared components then pages); Phase B at the bottom of this file lists the screens that previously had no prototype and now do.
Story 1 — Foundation: tokens, fonts, theme
Goal: establish the visual substrate the whole app reads from.
- Port
prototypes/colors_and_type.cssinto the app's token layer (Tailwind 4@theme/layout.css). Keep every variable name inDESIGN_RULES.md §1. - Wire Montserrat + Tinos (or licensed Gotham/Times) and the
--font-sans/--font-serifvars. - Implement light/dark via
:root[data-theme='dark']+ the pre-paint boot script that readslocalStorage['theme']. Add the globalimg[src*='degruyter-icons']{filter:invert(1)}dark rule.
Done when: a throwaway page using var(--c-*) tokens renders correct in both themes; no
flash of wrong theme on reload.
Story 2 — Shared: app header + nav (ArchiveHeader)
Spec: DESIGN_RULES.md §4. Prototype: ArchiveHeader.dc.html.
- One sticky header component: mint stripe, wordmark, nav with active-key prop, theme toggle, user chip. Nav routes to all sections.
- Theme toggle drives the Story 1 mechanism.
Done when: header renders identically on every route; active item shows the mint underline; toggle flips theme and persists.
Story 3 — Shared: avatar + deterministic color
Spec: DESIGN_RULES.md §5.
avatarFor(name)util (hash → palette index + initials) + an<Avatar name size>component supporting 26/28/40/48px and the overlapping-stack ring variant.
Done when: the same name yields the same color everywhere; stacks overlap with the surface-colored ring.
Story 4 — Shared: page-header, segmented control, card, metadata, empty state
Spec: DESIGN_RULES.md §3, §6, §7.
PageHeader(eyebrow + 4px mint left rule + serif h1 + italic lede + right slot).SegmentedControl(active = navy).Card(mint top/left border variants).MetaLine(·separated, optional leading icon).EmptyState(dashed, serif + ellipsis).
Done when: each primitive matches the prototype and is consumed by the screen stories below — not re-styled inline.
Story 5 — Dokumente (dashboard / search results)
Route: /. Prototype: Dokumente.dc.html.
PageHeader (eyebrow "Archiv", title "Dokumente", lede, right count "147 Dokumente · 38
Personen"). Then: a search bar card (input Titel, Personen, Tags durchsuchen… +
"Datum ↓" sort + "Filter" buttons); a resume strip (mint left border, "Weiter bei:" +
italic underlined doc link); a 1fr 320px grid — left: "Zuletzt hinzugefügt" list
(title · avatar stack · right-aligned date width:128px · status dot+label width:118px),
right column: upload dropzone (dashed, Upload icon, PDF, JPG, PNG, TIFF bis 50 MB) +
"Benötigt Metadaten" card; below full-width Mission Control — 3 tiles (Segmentierung /
Transkription / Zur Überprüfung), each with a caption, a pill "skill" hint, a weekly count,
and a list of linked items. Right column collapses below lg; main goes full-width.
Done when: matches prototype both themes; status dots use the §7 colors; grid collapses.
Story 6 — Personen (directory)
Route: /persons. Prototype: Personen.dc.html.
PageHeader (eyebrow "Verzeichnis") + right count "38 Personen". Search input
(z.B. Oma Frieda, Onkel Karl…) + segmented control (Alle / Personen / Institutionen /
Gruppen). 3-column card grid; each card: 48px avatar, serif name, relation sub, optional
type badge (Institution/Gruppe/Unbekannt — §1 colors), divider, meta line
✉ N Briefe · N Dokumente. Cards carry the 3px mint top border.
Done when: badge colors correct; avatar colors deterministic; grid responsive.
Story 7 — Briefwechsel — DROPPED
The two-person letter-exchange feature was removed from the product. Its prototype, route, and nav entry no longer exist. Skip.
Story 8 — Geschichten (story collections list) — NEW
Route: /geschichten. Prototype: Geschichten.dc.html.
PageHeader (eyebrow "Sammlungen") + primary button "Neue Geschichte". Segmented control
(Alle / Veröffentlicht / In Arbeit / Entwurf) + Filter button. 2-column card grid; each
card (link, mint top border): tag chips (dot + UPPERCASE label), serif 24px title, serif dek,
meta line 📅 range · N Dokumente · N Personen, footer with overlapping avatar stack + status
dot/label. Cards link to the story detail.
Done when: tag dots and status colors correct; cards link to Story 9.
Story 9 — Geschichte (single story detail) — NEW
Route: /geschichten/:id. Prototype: Geschichte.dc.html. Two variants
(variant prop): "Lesereise" (a guided reading — intro + narration blocks + letter
cards + annotation notes) and "Sammlung" (a collection — intro + "Erwähnte Dokumente"
list). Centered max-width:880px article card (mint top border, padding:48px 56px):
type badge, 38px serif title, byline row (author avatar + name + "zusammengestellt am …" +
Bearbeiten / Löschen actions), intro paragraph, then ordered blocks:
- narration — 3px mint left rule, serif italic 18px.
- letter — clickable row: 40px tile w/ Mail icon, serif title, meta
date · von X an Y, trailing Arrow-Right icon. - note — mint-tinted (
--c-accent-bg) left-rule box, "Anmerkung" caption + serif italic.
Done when: both variants render from the prop; block types styled per spec; Löschen uses
--c-danger.
Story 10 — Zeitstrahl (timeline) — NEW
Route: /zeitstrahl. Prototype: Zeitstrahl.dc.html.
PageHeader (eyebrow "Chronik") + right count. Segmented control (Alle / Briefe / Personen /
Ereignisse) + a small legend. Centered vertical spine (max-width:760px, 2px mint center
line). Item types stacked on the spine: year pill (navy), summary card (count + a
12-bar monthly-density mini chart in mint + range labels), letter cards alternating
left/right with a spine dot (2px solid --c-primary) and optional tag pill, person
node (28px navy circle glyph + name + derived meta), curated node (★, mint left rule),
historical band (full-width, Globe icon, serif italic, top/bottom hairline).
Done when: spine centered; letters alternate; bars scale to value %; all five item types render.
Story 11 — Aktivitäten (activity feed) — NEW
Route: /aktivitaeten. Prototype: Aktivitaeten.dc.html.
PageHeader (eyebrow "Verlauf") + "Aktualisieren" button. Segmented control (Alle / Transkription / Uploads / Personen). Feed grouped by day (Heute / Gestern / Diese Woche), each group a UPPERCASE caption + rows. Each row: 40px avatar with a small action-icon badge bottom-right (Check/Upload/Chat/Edit/…), then a sentence — bold actor name + Montserrat verb + italic underlined target link — and a time sub.
Done when: grouping + icon badges match; target links styled with mint underline.
Story 12 (optional) — Regeln (internal style reference)
Prototype: Regeln.dc.html. Internal page documenting the seven blocks (Typografie,
Farbe, Seitenkopf, Steuerung, Avatare, Metadaten/Leerzustände). Build only if the team wants
a living in-app reference; otherwise DESIGN_RULES.md is the canonical record. Gate behind
admin/dev.
Suggested order & dependencies
1 Tokens ─┬─ 2 Header ──┐
├─ 3 Avatar ──┼─→ 5 Dokumente, 6 Personen,
└─ 4 Primitives┘ 8 Geschichten → 9 Geschichte,
10 Zeitstrahl, 11 Aktivitäten (parallelizable)
12 Regeln (optional, last)
→ then Phase B (added screens), all depend on 1–4
Phase B — Added screens (previously un-prototyped pages)
These are the pages the original handoff never covered. Each now has a hifi .dc.html
prototype in prototypes/. All depend on the shared primitives from Stories 1–4 and are
parallelizable among themselves. Each maps to one Gitea page-issue in the milestone.
Admin + OCR pages are explicitly out of scope here (phase-2 milestone).
| # | Screen | Prototype | Route(s) | Done when |
|---|---|---|---|---|
| B1 | Dokumente-Liste | Dokumente-Liste.dc.html |
/documents |
PageHeader; search card; AND/OR segmented; grouped mint-top cards; avatar-stack rows; 7px status dot+label; pagination |
| B2 | Dokument-Detail | Dokument-Detail.dc.html |
/documents/[id] |
compact top bar w/ mint accent bar; PDF pane + transcription panel w/ Lesen/Bearbeiten segmented + turquoise mode; details card |
| B3 | Dokument-Bearbeiten | Dokument-Bearbeiten.dc.html |
/documents/[id]/edit, /new, /bulk-edit |
split pane; progress strip; Wer&Wann + Beschreibung cards; dropzone (new); action bar (Löschen danger / Abbrechen / Zur Überprüfung / Speichern) |
| B4 | PersonDetail | PersonDetail.dc.html |
/persons/[id] |
PageHeader; 2-col mint-top cards; deterministic avatar; correspondents + relationships + letter lists |
| B5 | PersonForm | PersonForm.dc.html |
/persons/new, /[id]/edit |
PageHeader; Stammdaten card w/ type segmented; caps labels; Namensverlauf; edit-only merge danger zone; save bar |
| B6 | PersonReview | PersonReview.dc.html |
/persons/review |
PageHeader + count; row card w/ muted avatar; idle/rename/merge states; danger merge+delete; confirm dialog; empty state |
| B7 | Geschichte-Editor | Geschichte-Editor.dc.html |
/geschichten/new, /[id]/edit |
type-pick segmented; prose editor toolbar; journey editor w/ color-only drag; sidebar status+persons; save bar |
| B8 | Ereignis-Editor | Ereignis-Editor.dc.html |
/zeitstrahl/events/new, /[id]/edit |
PageHeader; Wann&Was card w/ type segmented + date precision + danger error; persons/docs sidebar; save bar |
| B9 | Stammbaum | Stammbaum.dc.html |
/stammbaum |
PageHeader + count; node cards w/ §5 avatar in resting/selected/dimmed; line connectors; side panel; zoom controls; empty state |
| B10 | Themen | Themen.dc.html |
/themen |
PageHeader + count; segmented filter; mint-top cards w/ §1 tag-dot (not stripe); child rows; empty state |
| B11 | Anreicherung | Anreicherung.dc.html |
/enrich, /[id], /done |
list (status rows) / step (progress bar + split pane + action bar) / done (success card) |
| B12 | Profil | Profil.dc.html |
/profile, /users/[id] |
PageHeader; 2-col data/password cards; token banners; notifications; public profile card w/ avatar |
| B13 | Anmeldung | Anmeldung.dc.html |
/login, /register, /forgot-password, /reset-password |
self-contained branded shell (no app header); Tinos sentence-case titles; 17px inputs; token banners |
| B14 | Hilfe-Transkription | Hilfe-Transkription.dc.html |
/hilfe/transkription |
PageHeader; article column; rule cards w/ De Gruyter icons (no emoji); fixes border-brand-sand/bg-white bugs |