fix(timeline): label the cross-year ✉ glyph for screen readers

The cross-year card header emitted a bare aria-hidden ✉ with no sr-only
label, unlike the same-year header and LetterCard — a screen-reader user
heard only the title with no cue that this is a letter group. It now uses
the shared GlyphLabel (✉ + sr-only "Brief"). Fixes review finding #6
(glyph half).

Refs #850
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-15 22:18:31 +02:00
parent a9027ceaf7
commit 30384fa53b
2 changed files with 12 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import * as m from '$lib/paraglide/messages.js';
import LetterCard from './LetterCard.svelte';
import GlyphLabel from './GlyphLabel.svelte';
import { entryKey } from './entryKey';
import { getAccentConfig } from './eventCardConfig';
import { timelineDateLabel } from './dateLabel';
@@ -107,7 +108,7 @@ const hiddenCount = $derived(letters.length - CLUSTER_PREVIEW);
class="flex items-center gap-2 border-b border-line px-3 py-2"
>
<span class="font-serif text-sm font-bold whitespace-pre-line text-ink">
<span aria-hidden="true"></span>
<GlyphLabel glyph="✉" label={m.timeline_letter_glyph_label()} />
{title}
</span>
<span data-testid="event-count" class="font-sans text-xs text-ink-3">· {count}</span>

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { tick } from 'svelte';
import * as m from '$lib/paraglide/messages.js';
import EventCluster from './EventCluster.svelte';
import { makeEntry } from './test-factories';
import type { components } from '$lib/generated/api';
@@ -98,6 +99,15 @@ describe('EventCluster — contained event card (#850)', () => {
expect(document.querySelector('[data-testid="event-edit"]')).toBeNull();
});
it('pairs the cross-year ✉ glyph with an sr-only label so it is not a silent glyph (finding #6)', () => {
render(EventCluster, { letters: letters(2), title: 'Briefe von der Front' });
const header = document.querySelector('[data-testid="event-header"]') as HTMLElement;
const hidden = header.querySelector('[aria-hidden="true"]');
expect(hidden?.textContent).toContain('✉');
const srOnly = header.querySelector('.sr-only');
expect(srOnly?.textContent).toBe(m.timeline_letter_glyph_label());
});
it('renders an HTML-bearing event title verbatim as text, never as markup (REQ-010)', () => {
render(EventCluster, {
letters: letters(1),