[Mappe·Shared] PageHeader — eyebrow + 4px mint rule + Tinos 46px title + lede (§3) #856

Open
opened 2026-06-16 10:53:34 +02:00 by marcel · 0 comments
Owner

Shared component · Story 4. Part of #853. Highest-leverage primitive — absent on every page.

Context

Not one page renders the signature page-opening block. Pages use a bare font-serif text-2xl/3xl h1 with no eyebrow and no mint rule.

Scope

  • Create $lib/shared/primitives/PageHeader.svelte. Props: eyebrow, title, lede?, and right?: Snippet for a count or a primary action button (single optional snippet — not a config object).
  • Markup per _AUTHORING_KIT.md §3 / Personen.dc.html lines 26–33:
    • container border-left:4px solid var(--c-accent); padding-left:18px
    • eyebrow Montserrat 12px/700, .14em, UPPERCASE, text-ink-3, mb 8px — not a heading element
    • h1 Tinos clamp(28px, 8vw, 46px)/700, lh 1.06, text-ink — clamped so the title does not overflow at 320px
    • lede Tinos italic 16px, text-ink-2, mt 10px, max-w 520px
    • right slot via justify-between; align-items:flex-end; flex-wrap:wrap
  • All three text props (eyebrow, title, lede) render via Svelte default {...} escaping. The component never uses {@html}.
  • The component is string-agnostic: it takes no Paraglide literals. Consuming pages source strings from Paraglide and pass them as props.
  • Props must cover both list-page context (PERSONENVERZEICHNIS) and edit/detail eyebrow context (PERSON BEARBEITEN) — keep generic.

Out of Scope

Page migrations for the remaining ~20 pages are tracked in the blocked issues. This issue ships the primitive + one reference consumer (/persons).

Acceptance

  • Matches prototype in light + dark — verified by: (a) vitest-browser-svelte for single-<h1>/heading-structure assertions (getByRole('heading') confirms one <h1>, eyebrow is not a heading); (b) Playwright/visual check at 320/768/1440 px in both themes on the /persons consumer
  • <h1> font-size computed value = clamp(28px, 8vw, 46px); no raw hex / non-token color in the diff; 320px viewport: no horizontal overflow
  • Consumed by /persons (the reference consumer) — its inline header removed and replaced with <PageHeader>; strings wired through Paraglide
  • Exactly one <h1> per page; eyebrow is not a heading element
  • eyebrow/title/lede render via {...} escaping only — no {@html} anywhere in the component

Depends on: none. Blocks: all page issues. Refs: DESIGN_RULES §3.

**Shared component · Story 4.** Part of #853. **Highest-leverage primitive — absent on every page.** ## Context Not one page renders the signature page-opening block. Pages use a bare `font-serif text-2xl/3xl` h1 with no eyebrow and no mint rule. ## Scope - Create `$lib/shared/primitives/PageHeader.svelte`. Props: `eyebrow`, `title`, `lede?`, and `right?: Snippet` for a count or a primary action button (single optional snippet — not a config object). - Markup per `_AUTHORING_KIT.md §3` / `Personen.dc.html` lines 26–33: - container `border-left:4px solid var(--c-accent); padding-left:18px` - eyebrow Montserrat 12px/700, `.14em`, UPPERCASE, `text-ink-3`, mb 8px — **not a heading element** - h1 Tinos `clamp(28px, 8vw, 46px)`/700, lh 1.06, `text-ink` — clamped so the title does not overflow at 320px - lede Tinos italic 16px, `text-ink-2`, mt 10px, max-w 520px - right slot via `justify-between; align-items:flex-end; flex-wrap:wrap` - All three text props (`eyebrow`, `title`, `lede`) render via Svelte default `{...}` escaping. The component **never** uses `{@html}`. - The component is string-agnostic: it takes no Paraglide literals. Consuming pages source strings from Paraglide and pass them as props. - Props must cover both list-page context (`PERSONENVERZEICHNIS`) and edit/detail eyebrow context (`PERSON BEARBEITEN`) — keep generic. ## Out of Scope Page migrations for the remaining ~20 pages are tracked in the blocked issues. This issue ships the primitive + one reference consumer (`/persons`). ## Acceptance - [ ] Matches prototype in light + dark — verified by: (a) vitest-browser-svelte for single-`<h1>`/heading-structure assertions (`getByRole('heading')` confirms one `<h1>`, eyebrow is not a heading); (b) Playwright/visual check at 320/768/1440 px in both themes on the `/persons` consumer - [ ] `<h1>` font-size computed value = `clamp(28px, 8vw, 46px)`; no raw hex / non-token color in the diff; 320px viewport: no horizontal overflow - [ ] Consumed by `/persons` (the reference consumer) — its inline header removed and replaced with `<PageHeader>`; strings wired through Paraglide - [ ] Exactly one `<h1>` per page; eyebrow is **not** a heading element - [ ] `eyebrow`/`title`/`lede` render via `{...}` escaping only — no `{@html}` anywhere in the component **Depends on:** none. **Blocks:** all page issues. **Refs:** `DESIGN_RULES §3`.
marcel added this to the Mappe Visual Redesign milestone 2026-06-16 10:53:34 +02:00
marcel added the P1-highfeatureredesign-mappeui labels 2026-06-16 11:06:17 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#856