diff --git a/frontend/src/lib/timeline/eventClustering.spec.ts b/frontend/src/lib/timeline/eventClustering.spec.ts index f469f1c9..4b42fea9 100644 --- a/frontend/src/lib/timeline/eventClustering.spec.ts +++ b/frontend/src/lib/timeline/eventClustering.spec.ts @@ -59,6 +59,22 @@ describe('eventClustering — buildEventLookup', () => { expect(lookup.has(EV_A)).toBe(false); expect(lookup.size).toBe(0); }); + + it('skips an event with an empty or whitespace title — no bare ✉ card (#8)', () => { + const timeline: TimelineDTO = { + years: [ + { + year: 1916, + entries: [ + makeEvent({ eventId: EV_A, title: '' }), + makeEvent({ eventId: EV_B, title: ' ' }) + ] + } + ], + undated: [] + }; + expect(buildEventLookup(timeline).size).toBe(0); + }); }); describe('eventClustering — splitYearLetters', () => { diff --git a/frontend/src/lib/timeline/eventClustering.ts b/frontend/src/lib/timeline/eventClustering.ts index 22e3ee78..e80a43fd 100644 --- a/frontend/src/lib/timeline/eventClustering.ts +++ b/frontend/src/lib/timeline/eventClustering.ts @@ -33,13 +33,17 @@ export interface SplitLetters { * Only year-band events are collected: an undated event renders as a plain pill in the undated * bucket (out of clustering scope), so including it would scatter its dated letters into orphaned * cross-year cards detached from that pill (#7). + * + * An event with an empty/whitespace title is skipped too — clustering under it would render a + * label-less `✉` mystery card; its letters stay loose instead (#8). */ export function buildEventLookup(timeline: TimelineDTO): Map { const lookup = new Map(); const collect = (entries: TimelineEntryDTO[]) => { for (const entry of entries) { - if (entry.kind === 'EVENT' && entry.eventId && entry.type !== 'HISTORICAL') { - lookup.set(entry.eventId, entry.title ?? ''); + const title = entry.title?.trim(); + if (entry.kind === 'EVENT' && entry.eventId && entry.type !== 'HISTORICAL' && title) { + lookup.set(entry.eventId, title); } } };