From 7902f4e6acf78b1f1f808a01c9485c2c83613388 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 13 Jun 2026 20:30:59 +0200 Subject: [PATCH] refactor(timeline): extract entryKey helper from YearBand Move the per-entry {#each} key logic into a shared entryKey.ts so the undated bucket in TimelineView can reuse it. No behavior change. Co-Authored-By: Claude Opus 4.8 --- frontend/src/lib/timeline/YearBand.svelte | 11 +---------- frontend/src/lib/timeline/entryKey.ts | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 frontend/src/lib/timeline/entryKey.ts diff --git a/frontend/src/lib/timeline/YearBand.svelte b/frontend/src/lib/timeline/YearBand.svelte index 005e6e7e..a612a750 100644 --- a/frontend/src/lib/timeline/YearBand.svelte +++ b/frontend/src/lib/timeline/YearBand.svelte @@ -4,6 +4,7 @@ import WorldBand from './WorldBand.svelte'; import LetterCard from './LetterCard.svelte'; import YearLetterStrip from './YearLetterStrip.svelte'; import { isDense } from './timelineDensity'; +import { entryKey } from './entryKey'; import type { components } from '$lib/generated/api'; type TimelineYearDTO = components['schemas']['TimelineYearDTO']; @@ -42,16 +43,6 @@ const rows = $derived.by(() => { } return out; }); - -function entryKey(entry: TimelineEntryDTO): string { - return ( - entry.kind + - ':' + - (entry.eventId ?? - entry.documentId ?? - `${entry.derivedType}:${(entry.linkedPersonIds ?? []).join('-')}`) - ); -}
diff --git a/frontend/src/lib/timeline/entryKey.ts b/frontend/src/lib/timeline/entryKey.ts new file mode 100644 index 00000000..4ebd74de --- /dev/null +++ b/frontend/src/lib/timeline/entryKey.ts @@ -0,0 +1,23 @@ +import type { components } from '$lib/generated/api'; + +type TimelineEntryDTO = components['schemas']['TimelineEntryDTO']; + +/** + * Stable `{#each}` key for a timeline entry. Prefers the entry's own identity + * (`eventId` for curated events, `documentId` for letters); derived life-events + * carry neither, so they key on `derivedType` + their linked person ids — which + * keeps two derived births in the same year distinct. The `kind` prefix keeps an + * event and a letter that happen to share an id from colliding. + * + * Used by both `YearBand` (per-band rows) and `TimelineView` (the undated + * bucket), where entries can be events without a `documentId`. + */ +export function entryKey(entry: TimelineEntryDTO): string { + return ( + entry.kind + + ':' + + (entry.eventId ?? + entry.documentId ?? + `${entry.derivedType}:${(entry.linkedPersonIds ?? []).join('-')}`) + ); +}