diff --git a/frontend/src/lib/timeline/LetterCard.svelte b/frontend/src/lib/timeline/LetterCard.svelte index c56b048c..1e3b334f 100644 --- a/frontend/src/lib/timeline/LetterCard.svelte +++ b/frontend/src/lib/timeline/LetterCard.svelte @@ -32,10 +32,12 @@ let { const isEventVariant = $derived(variant === 'event'); const dateLabel = $derived(timelineDateLabel(entry.eventDate, entry.precision, entry.eventDateEnd)); -// Inside an event card the year frames the time, and these archive titles already -// embed the date — so the compact in-card letter drops the redundant date chip when a -// title is present, halving the row height and killing the duplicate date (#850). -const showDate = $derived(!compact || !entry.title); +// Inside an event card the band frames the time, so a compact in-card letter drops the +// redundant date chip — but ONLY when the (free-form OCR) title actually embeds the formatted +// date, e.g. "H-0023 – 6. Juli 1916". A title without the date keeps its chip, so a letter like +// "Brief an Mutter" never loses its month/day (the band frames only the year) — #850, finding #4. +const titleEmbedsDate = $derived(!!dateLabel && !!entry.title && entry.title.includes(dateLabel)); +const showDate = $derived(!compact || !titleEmbedsDate); const sender = $derived(entry.senderName === '' ? m.timeline_unknown_person() : entry.senderName); const receiver = $derived( entry.receiverName === '' ? m.timeline_unknown_person() : entry.receiverName diff --git a/frontend/src/lib/timeline/LetterCard.svelte.spec.ts b/frontend/src/lib/timeline/LetterCard.svelte.spec.ts index f7957637..349a2e72 100644 --- a/frontend/src/lib/timeline/LetterCard.svelte.spec.ts +++ b/frontend/src/lib/timeline/LetterCard.svelte.spec.ts @@ -152,14 +152,26 @@ describe('LetterCard — event-cluster variants (#850, REQ-002)', () => { expect(document.querySelector('[data-testid="tag-chip"]')).not.toBeNull(); }); - it('drops the redundant date line in the compact variant when a title is present (#850)', () => { - // Inside an event card the year already frames the time, and these archive titles - // embed the date — so the compact in-card letter omits the date chip. - render(LetterCard, { entry: makeEntry({ title: 'H-0023 – 6. Juli 1916' }), compact: true }); + it('drops the compact date chip only when the title actually embeds the formatted date (#850)', () => { + // An archive title like "H-0023 – 6. Juli 1916" already carries the date, so inside an + // event card (where the band frames the time) the redundant chip is dropped. + const entry = makeEntry({ eventDate: '1916-07-06', precision: 'DAY' }); + const dateLabel = timelineDateLabel(entry.eventDate, entry.precision, entry.eventDateEnd); + render(LetterCard, { entry: { ...entry, title: `H-0023 – ${dateLabel}` }, compact: true }); expect(document.querySelector('[data-testid="letter-date"]')).toBeNull(); expect(document.body.textContent).toContain('Karl Raddatz'); // sender still shown }); + it('keeps the compact date chip when the title does NOT embed the date (#850, finding #4)', () => { + // Titles are free-form OCR text — a titled letter whose title carries no date must keep + // its month/day, since inside an event card the band frames only the year. + render(LetterCard, { + entry: makeEntry({ eventDate: '1916-07-06', precision: 'DAY', title: 'Brief an Mutter' }), + compact: true + }); + expect(document.querySelector('[data-testid="letter-date"]')).not.toBeNull(); + }); + it('keeps the date in the compact variant when the letter has no title (#850)', () => { render(LetterCard, { entry: makeEntry({ title: undefined }), compact: true }); expect(document.querySelector('[data-testid="letter-date"]')).not.toBeNull();