feat(timeline): center the year badge and add spine markers (REQ-003/004/005)
The year badge now centers on the axis at ≥1024px and hugs the left spine below that (sticky top:4rem preserved), with a navy node marker so it visibly interrupts the spine. Each letter row gains a connector dot (white fill, mint ring) on the spine: centered between card and axis on desktop, on the left spine clear of the indented card on phone. Spine geometry is commented to track TimelineView's spine so the markers can't silently desync. Refs #833 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user