From 621248f941629f427f86d1b16070df90e0c36786 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 15 Jun 2026 22:43:55 +0200 Subject: [PATCH] refactor(timeline): extract shared EventHeader for pill + event-card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EventCluster's same-year header re-implemented EventPill's glyph circle, serif title, provenance subtitle, and the curator edit anchor near- verbatim — the third copy of that markup. They now share a single EventHeader component (glyph via GlyphLabel, title, `{date} · provenance` subtitle, optional sr-only letter count, and the canEditEvent-gated edit pencil); EventPill keeps only its pill border, EventCluster only its card chrome. Second half of review finding #5 (Architect-1). No behavior change — EventPill/EventCluster/YearBand/TimelineView specs stay green. Refs #850 Co-Authored-By: Claude Opus 4.8 --- frontend/src/lib/timeline/EventCluster.svelte | 62 +++-------------- frontend/src/lib/timeline/EventHeader.svelte | 69 +++++++++++++++++++ .../lib/timeline/EventHeader.svelte.spec.ts | 66 ++++++++++++++++++ frontend/src/lib/timeline/EventPill.svelte | 53 +++----------- 4 files changed, 152 insertions(+), 98 deletions(-) create mode 100644 frontend/src/lib/timeline/EventHeader.svelte create mode 100644 frontend/src/lib/timeline/EventHeader.svelte.spec.ts diff --git a/frontend/src/lib/timeline/EventCluster.svelte b/frontend/src/lib/timeline/EventCluster.svelte index 024ba168..29f13497 100644 --- a/frontend/src/lib/timeline/EventCluster.svelte +++ b/frontend/src/lib/timeline/EventCluster.svelte @@ -2,9 +2,8 @@ import * as m from '$lib/paraglide/messages.js'; import LetterCard from './LetterCard.svelte'; import GlyphLabel from './GlyphLabel.svelte'; +import EventHeader from './EventHeader.svelte'; import { entryKey } from './entryKey'; -import { getAccentConfig, canEditEvent } from './eventCardConfig'; -import { timelineDateLabel } from './dateLabel'; import { CLUSTER_PREVIEW } from './eventClustering'; import type { components } from '$lib/generated/api'; @@ -15,9 +14,9 @@ type TimelineEntryDTO = components['schemas']['TimelineEntryDTO']; * header (so its title reads once — never also as a floating pill, #850 REQ-002), and its letters * sit inside as compact `.lcard.ev` cards. * - * - Same-year event (`event` given): the header carries the accent glyph + sr-only label, the - * title, a `{date} · {kuratiert|abgeleitet}` subtitle, the letter count, and — for a curator on - * a curated event — an edit link to `/zeitstrahl/events/{eventId}/edit` (REQ-002). + * - Same-year event (`event` given): the shared EventHeader carries the accent glyph + sr-only + * label, the title, a `{date} · {kuratiert|abgeleitet}` subtitle, the letter count, and — for a + * curator on a curated event — an edit link to `/zeitstrahl/events/{eventId}/edit` (REQ-002). * - Cross-year (`title` given, no `event`): a plain `✉ {title}` text header, no edit link, no pill * chrome — it holds that other year's linked letters (REQ-004). * @@ -40,19 +39,6 @@ let { const count = $derived(letters.length); -// Event-as-header: a same-year curated event renders as this card's header, mirroring EventPill — -// glyph + title + date · provenance + an edit pencil for a curator. The title is never repeated -// as a separate floating pill (REQ-002). -const accent = $derived(event ? getAccentConfig(event) : null); -const eventDateLabel = $derived( - event ? timelineDateLabel(event.eventDate, event.precision, event.eventDateEnd) : null -); -const provenance = $derived( - event?.derived ? m.timeline_provenance_derived() : m.timeline_provenance_curated() -); -const eventSubtitle = $derived(eventDateLabel ? `${eventDateLabel} · ${provenance}` : provenance); -const canEdit = $derived(!!event && canEditEvent(event, canWrite)); - // First-5 preview + show-more (REQ-003): a large cluster stays readable instead of dumping every // card into the timeline. let expanded = $state(false); @@ -64,45 +50,15 @@ const hiddenCount = $derived(letters.length - CLUSTER_PREVIEW); class="my-3 overflow-hidden rounded-md border border-l-2 border-line border-l-brand-mint bg-surface shadow-sm" data-testid="event-card" > - {#if event && accent} - + {#if event} +
- - - {accent.label} - - - {event.title} - - {eventSubtitle} - - - {m.timeline_cluster_letter_count({ count })} - - - - {#if canEdit} - - - {m.btn_edit()} - - {/if} +
{:else}