Records the visual-brainstorm outcome for #827's grouped view: a cluster becomes one contained card (event/tag as header, first 5 letters + show-more), the leftover bin collapses to a count-only drawer, derived/world fixtures stay plain, and REQ-001/003/014/020 are amended. Mockups under .superpowers/brainstorm/ (gitignored). Refs #827 #847
6.1 KiB
Zeitstrahl grouped-view layout redesign
Date: 2026-06-15
Feature: #827 (regroup /zeitstrahl by Ereignis/Thema) — layout follow-up on PR #847
Status: Approved (brainstorm), pending implementation plan
The REQ contract for #827 lives in the Gitea issue body (and the amendment comment of 2026-06-15). This document records the layout/visual design agreed in the visual brainstorm and the REQ deltas it implies. Mockups:
.superpowers/brainstorm/*/content/.
Problem
The first grouped-view implementation (PR #847) fixed the flood and the duplicate event title, but two issues remained on review of the live view:
- Weak belonging. A clustered event's letters dropped below its centered pill as a full-width block with only a thin left rail. The connection between an event and its letters read weakly — the eye couldn't tell the letters belonged to the pill above.
- Layout inconsistency. In Datum mode letters alternate left/right of the centered spine (events/density centered). In grouped mode the letters became full-width, breaking that rhythm with no clear reason.
Decision: a cluster is one contained card
A clustered event (Ereignis) or root tag (Thema) renders as one bordered card whose header is the event/tag itself and whose body holds that cluster's letters. Belonging becomes structural (a single container), not positional guesswork. This replaces the full-width block.
Ereignis mode, per year band
- Derived life-events (Geburt/Tod/Heirat,
abgeleitet) never cluster — they carry no document links, so they are always plain axis fixtures, unchanged from Datum mode. A world-band (historisch) is normally letterless and stays a plain band; on the rare occasion a historical event has linked letters it follows rule 2 (becomes a card). - A curated event (PERSONAL or HISTORICAL) with letters in this band → one mint-bordered card:
- Header = the event's glyph + title + date +
kuratiert+ edit-✎ + count (the pill's content, laid out as a header bar). This replaces the separate floating pill for that event in this band — killing the duplicate title. - Body = the cluster's letters, first 5 shown, then a "+ N weitere Briefe anzeigen"
toggle that expands/collapses the rest. Letters use the compact
LetterCardvariant.
- Header = the event's glyph + title + date +
- A curated event with no letters in this band → stays a plain centered pill (no empty card).
- A curated event whose letters fall in a different year than its pill → those letters form a labeled card in their year (header = event name as text, no ✎/pill since the pill lives elsewhere); the pill stays in its own band. No adjacent duplication.
- Leftover letters (linked to no surviving curated event) → a collapsed neutral, dashed "✉ N Briefe ohne Ereignis · anzeigen ›" drawer. Clicking expands to the same first-5 + show-more list. No preview letters until opened.
Thema mode
Identical shape. Each card's header is the tinted root-tag chip (● Krieg · 24,
BucketHeaderChip, fixed-ink label per the contrast fix) instead of an event pill; there is no
axis pill for a tag, so every tag cluster is a standalone card. The per-letter TagChip stays
suppressed inside its own card (REQ-017). The leftover drawer reads "Ohne Thema".
Layout / spine
- Cluster cards are centered on the spine (like events already are), not full-width-flush — consistent with how grouped units (events) relate to the axis. Individual chronological letters keep alternating left/right only in Datum mode.
- Each card carries a colour left rail: mint for an Ereignis cluster, the tag colour for a Thema cluster, neutral dashed for the leftover drawer.
Components affected
LetterBucket.svelte— becomes the contained card: header slot (pill-content / tag chip / drawer label / cross-year text label) + body with the first-5 cap and the show-more toggle. Drop theYearLetterStrip(sparkline) branch from grouped mode.YearBand.svelte— in Ereignis mode, a same-year curated event renders as the card header (merge pill into the card) instead of pill-then-nested-bucket; derived/world/letterless events stay plain; cross-year clusters and the leftover drawer render after the axis entries.LetterCard.svelte— compact variant already exists (PR #847); reused inside cards.BucketHeaderChip.svelte— reused as the Thema card header (contrast fix already shipped).timelineGrouping.ts— the first-visible cap (CLUSTER_PREVIEW = 5) replacesBUCKET_DENSE_THRESHOLD; helpers unchanged otherwise.- Possibly a small
ClusterCard/header sub-component ifLetterBucketgrows too large.
REQ deltas (to fold into issue #827)
- REQ-001 (amended): derived life-events, world-bands, and letterless curated event pills render identically across modes; a curated event that has letters renders as its cluster card's header in grouped mode (no longer byte-identical to its Datum pill). Every event keeps its spine position (year).
- REQ-003 / REQ-014 (amended): event-clustered letters live inside a contained card; the header is the event (same-year) or a text label (cross-year). First 5 shown + show-more.
- REQ-020 (amended): grouped clusters are contained colour-railed cards with a first-5
preview + show-more toggle; the leftover bin is a collapsed count-only drawer. The
month-density
YearLetterStripis no longer used in grouped mode (still used in Datum dense years).
Out of scope
- Datum mode (untouched — keeps the alternating-axis zigzag and the >12 sparkline strip).
- Backend / DTO (
linkedEventIdand root-tag fields already shipped; no change). - New i18n beyond a show-more / drawer label string set.
Testing approach
TDD per component, mirroring PR #847: LetterBucket (card header variants, first-5 cap,
show-more expand/collapse, drawer collapsed-by-default, colour rail), YearBand (same-year merge
= no duplicate title; cross-year keeps a label; derived/world pills unchanged), and the route
spec for the assembled view. Run targeted --project=client / --project=server specs only.