diff --git a/frontend/src/lib/timeline/YearBand.svelte b/frontend/src/lib/timeline/YearBand.svelte index a612a750..64a19fdd 100644 --- a/frontend/src/lib/timeline/YearBand.svelte +++ b/frontend/src/lib/timeline/YearBand.svelte @@ -46,10 +46,13 @@ const rows = $derived.by(() => {
-

- {year.year} +

+ + {year.year}

@@ -62,6 +65,7 @@ const rows = $derived.by(() => { {/if} {:else if row.t === 'letter'}
+
{:else} @@ -73,19 +77,69 @@ const rows = $derived.by(() => { diff --git a/frontend/src/lib/timeline/YearBand.svelte.spec.ts b/frontend/src/lib/timeline/YearBand.svelte.spec.ts index 5d43a6e5..ce1abff0 100644 --- a/frontend/src/lib/timeline/YearBand.svelte.spec.ts +++ b/frontend/src/lib/timeline/YearBand.svelte.spec.ts @@ -1,9 +1,13 @@ import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; import YearBand from './YearBand.svelte'; import { makeEntry, makeYear } from './test-factories'; -afterEach(() => cleanup()); +afterEach(async () => { + cleanup(); + await page.viewport(1280, 720); +}); function manyLetters(year: number, count: number) { return Array.from({ length: count }, (_, i) => @@ -81,4 +85,59 @@ describe('YearBand', () => { expect(document.body.textContent).toContain('Heirat'); expect(document.querySelector('[data-testid="world-range"]')).not.toBeNull(); }); + + it('centers the year badge on the axis at desktop (REQ-003)', async () => { + await page.viewport(1440, 900); + render(YearBand, { year: makeYear(1914, [makeEntry()]) }); + const section = document.querySelector('section') as HTMLElement; + const badge = document.querySelector('[data-testid="year-label"]') as HTMLElement; + const s = section.getBoundingClientRect(); + const b = badge.getBoundingClientRect(); + const sectionCenter = s.left + s.width / 2; + const badgeCenter = b.left + b.width / 2; + expect(Math.abs(badgeCenter - sectionCenter)).toBeLessThan(8); + }); + + it('left-aligns the year badge at phone width (REQ-003)', async () => { + await page.viewport(375, 800); + render(YearBand, { year: makeYear(1914, [makeEntry()]) }); + const section = document.querySelector('section') as HTMLElement; + const badge = document.querySelector('[data-testid="year-label"]') as HTMLElement; + const s = section.getBoundingClientRect(); + const b = badge.getBoundingClientRect(); + // hugs the left spine — clearly not centered + expect(b.left - s.left).toBeLessThan(s.width / 3); + }); + + it('keeps the sticky year heading at top:4rem (REQ-003)', () => { + render(YearBand, { year: makeYear(1914, [makeEntry()]) }); + const h2 = document.querySelector('h2') as HTMLElement; + const cs = getComputedStyle(h2); + expect(cs.position).toBe('sticky'); + expect(cs.top).toBe('64px'); + }); + + it('renders a year-badge node marker that clears the badge text on phone (REQ-004)', async () => { + await page.viewport(375, 800); + render(YearBand, { year: makeYear(1914, [makeEntry()]) }); + const node = document.querySelector('[data-testid="year-node"]') as HTMLElement; + const label = document.querySelector('[data-testid="year-label"]') as HTMLElement; + expect(node).not.toBeNull(); + const n = node.getBoundingClientRect(); + const l = label.getBoundingClientRect(); + expect(n.right).toBeLessThanOrEqual(l.left + 0.5); + }); + + it('renders one connector dot per letter row, each clearing its card on phone (REQ-005)', async () => { + await page.viewport(375, 800); + render(YearBand, { year: makeYear(1909, manyLetters(1909, 3)) }); + const dots = document.querySelectorAll('[data-testid="letter-dot"]'); + expect(dots).toHaveLength(3); + const row = document.querySelector('.letter-row') as HTMLElement; + const dot = row.querySelector('[data-testid="letter-dot"]') as HTMLElement; + const card = row.querySelector('a') as HTMLElement; + expect(dot.getBoundingClientRect().right).toBeLessThanOrEqual( + card.getBoundingClientRect().left + 0.5 + ); + }); });