feat(timeline): frame the undated bucket with a dashed border + count (REQ-012)

The "Ohne Datum" section now renders inside a dashed-bordered surface box
whose heading reads "Ohne Datum · {count}", matching the spec's .undated
treatment. The kind/type dispatch (events as pills/bands, letters as cards)
is unchanged; the section stays absent when there are no undated entries.

Refs #833
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-14 10:55:37 +02:00
parent 6382efa65a
commit e0b096f12c
2 changed files with 21 additions and 2 deletions

View File

@@ -59,8 +59,13 @@ const isEmpty = $derived(timeline.years.length === 0 && timeline.undated.length
</ol> </ol>
{#if timeline.undated.length > 0} {#if timeline.undated.length > 0}
<section data-testid="undated-section" class="mx-auto mt-8 max-w-3xl"> <section
<h2 class="mb-3 font-serif text-sm font-bold text-ink-2">{m.timeline_undated_section()}</h2> data-testid="undated-section"
class="mx-auto mt-8 max-w-3xl rounded-sm border border-dashed border-line bg-surface p-4"
>
<h2 class="mb-3 font-serif text-sm font-bold text-ink-2">
{m.timeline_undated_section()} · {timeline.undated.length}
</h2>
<ul class="space-y-2"> <ul class="space-y-2">
<!-- The undated bucket is filtered from ALL entries, so it can hold <!-- The undated bucket is filtered from ALL entries, so it can hold
events as well as letters. Dispatch on kind/type exactly like events as well as letters. Dispatch on kind/type exactly like

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, afterEach } from 'vitest'; import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte'; import { cleanup, render } from 'vitest-browser-svelte';
import * as m from '$lib/paraglide/messages.js';
import TimelineView from './TimelineView.svelte'; import TimelineView from './TimelineView.svelte';
import { makeEntry, makeYear, makeTimelineDTO } from './test-factories'; import { makeEntry, makeYear, makeTimelineDTO } from './test-factories';
@@ -73,6 +74,19 @@ describe('TimelineView', () => {
expect(document.querySelector('[data-testid="undated-section"]')).toBeNull(); expect(document.querySelector('[data-testid="undated-section"]')).toBeNull();
}); });
it('frames the undated section with a dashed border and shows the count (REQ-012)', () => {
const undated = Array.from({ length: 11 }, (_, i) =>
makeEntry({ precision: 'UNKNOWN', eventDate: undefined, documentId: `u-${i}` })
);
render(TimelineView, { timeline: makeTimelineDTO({ undated }) });
const section = document.querySelector('[data-testid="undated-section"]') as HTMLElement;
expect(section).not.toBeNull();
expect(section.classList.contains('border-dashed')).toBe(true);
const h2 = section.querySelector('h2');
expect(h2?.textContent).toContain(m.timeline_undated_section());
expect(h2?.textContent).toContain('11');
});
it('renders all years and undated entries with personId undefined, no filtering (REQ-025)', () => { it('renders all years and undated entries with personId undefined, no filtering (REQ-025)', () => {
render(TimelineView, { render(TimelineView, {
timeline: makeTimelineDTO({ timeline: makeTimelineDTO({