diff --git a/frontend/messages/de.json b/frontend/messages/de.json index fdc37e57..4c933f16 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -141,6 +141,7 @@ "conv_sort_oldest": "Älteste zuerst", "conv_empty_heading": "Wessen Briefe möchten Sie lesen?", "conv_empty_text": "Wähle eine Person aus dem Archiv um deren Briefe zu sehen — mit oder ohne Korrespondent.", + "conv_hero_crosslink": "Suchen Sie ein bestimmtes Dokument? → Zur Dokumentensuche", "conv_no_results_heading": "Keine Dokumente gefunden.", "conv_no_results_text": "Versuchen Sie, den Zeitraum anzupassen.", "conv_swap_btn": "Personen tauschen", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index e323e3ca..70335627 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -141,6 +141,7 @@ "conv_sort_oldest": "Oldest first", "conv_empty_heading": "Whose letters would you like to read?", "conv_empty_text": "Choose a person from the archive to see their letters — with or without a correspondent.", + "conv_hero_crosslink": "Looking for a specific document? → Go to document search", "conv_no_results_heading": "No documents found.", "conv_no_results_text": "Try adjusting the time period.", "conv_swap_btn": "Swap persons", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 0bdeabb5..c33c6ee2 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -141,6 +141,7 @@ "conv_sort_oldest": "Más antiguo primero", "conv_empty_heading": "¿De quién desea leer las cartas?", "conv_empty_text": "Elige una persona del archivo para ver sus cartas — con o sin corresponsal.", + "conv_hero_crosslink": "¿Busca un documento en particular? → Ir a la búsqueda", "conv_no_results_heading": "No se encontraron documentos.", "conv_no_results_text": "Intente ajustar el período de tiempo.", "conv_swap_btn": "Intercambiar personas", diff --git a/frontend/src/lib/components/PersonTypeahead.svelte b/frontend/src/lib/components/PersonTypeahead.svelte index 8e9cf930..316d54d7 100644 --- a/frontend/src/lib/components/PersonTypeahead.svelte +++ b/frontend/src/lib/components/PersonTypeahead.svelte @@ -13,6 +13,7 @@ interface Props { suggestedName?: string; placeholder?: string; compact?: boolean; + large?: boolean; restrictToCorrespondentsOf?: string; onchange?: (value: string) => void; onfocused?: () => void; @@ -26,6 +27,7 @@ let { suggestedName = '', placeholder, compact = false, + large = false, restrictToCorrespondentsOf, onchange, onfocused @@ -140,9 +142,11 @@ function selectPerson(person: Person) { oninput={handleInput} onfocus={handleFocus} placeholder={placeholder ?? m.comp_typeahead_placeholder()} - class={compact - ? 'mt-1 block h-9 w-full rounded border border-line bg-surface px-2 text-sm text-ink placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring' - : 'mt-1 block w-full rounded-md border border-line bg-surface p-2 text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring'} + class={large + ? 'mt-2 block h-14 w-full rounded-md border border-line bg-surface px-4 text-base text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring' + : compact + ? 'mt-1 block h-9 w-full rounded border border-line bg-surface px-2 text-sm text-ink placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring' + : 'mt-1 block w-full rounded-md border border-line bg-surface p-2 text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring'} /> {#if showDropdown && (results.length > 0 || loading)} diff --git a/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte new file mode 100644 index 00000000..924d37a2 --- /dev/null +++ b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte @@ -0,0 +1,90 @@ + + +
+ + + {m.conv_hero_crosslink()} + + + +

+ {m.conv_empty_heading()} +

+ + +
+ +
+ + + {#if recentPersons.length > 0} +
+
+ oder +
+
+ +
+ + {m.conv_empty_recent_label()} + +
+ {#each recentPersons as person (person.id)} + + {/each} +
+
+ {/if} +
diff --git a/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte.spec.ts b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte.spec.ts new file mode 100644 index 00000000..b3108334 --- /dev/null +++ b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte.spec.ts @@ -0,0 +1,50 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import CorrespondenzHero from './CorrespondenzHero.svelte'; + +vi.mock('$app/navigation', () => ({ goto: vi.fn() })); + +afterEach(cleanup); + +const noop = () => {}; + +describe('CorrespondenzHero — headline and cross-link', () => { + it('renders the discovery headline', async () => { + render(CorrespondenzHero, { onSelectPerson: noop }); + await expect.element(page.getByText(/Wessen Briefe möchten Sie lesen/i)).toBeInTheDocument(); + }); + + it('renders a cross-link to the document search page', async () => { + render(CorrespondenzHero, { onSelectPerson: noop }); + const link = page.getByRole('link', { name: /Zur Dokumentensuche/i }); + await expect.element(link).toBeInTheDocument(); + await expect.element(link).toHaveAttribute('href', '/'); + }); + + it('renders a person typeahead input', async () => { + render(CorrespondenzHero, { onSelectPerson: noop }); + await expect.element(page.getByTestId('conv-hero').getByRole('textbox')).toBeInTheDocument(); + }); +}); + +describe('CorrespondenzHero — recent persons', () => { + it('shows recent person chips when provided', async () => { + render(CorrespondenzHero, { + onSelectPerson: noop, + recentPersons: [{ id: 'r1', name: 'Clara Braun' }] + }); + await expect.element(page.getByText('Clara Braun')).toBeInTheDocument(); + }); + + it('calls onSelectPerson when a recent person chip is clicked', async () => { + const spy = vi.fn(); + render(CorrespondenzHero, { + onSelectPerson: spy, + recentPersons: [{ id: 'r1', name: 'Clara Braun' }] + }); + await expect.element(page.getByText('Clara Braun')).toBeInTheDocument(); + document.querySelector('[data-testid="recent-person-r1"]')!.click(); + expect(spy).toHaveBeenCalledWith('r1'); + }); +});