diff --git a/frontend/messages/de.json b/frontend/messages/de.json index a78baf18..ea422b13 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -16,7 +16,7 @@ "error_internal_error": "Ein unerwarteter Fehler ist aufgetreten.", "nav_documents": "Dokumente", "nav_persons": "Personen", - "nav_conversations": "Korrespondenz", + "nav_conversations": "Briefwechsel", "nav_admin": "Admin", "nav_logout": "Abmelden", "btn_save": "Speichern", @@ -130,7 +130,7 @@ "person_co_correspondents_heading": "Häufige Korrespondenten", "person_correspondents_hint": "klicken für Konversation", "person_show_more": "+ {count} weitere anzeigen", - "conv_heading": "Korrespondenz", + "conv_heading": "Briefwechsel", "conv_subtitle": "Briefwechsel einer Person durchsuchen — mit oder ohne Korrespondent.", "conv_label_person_a": "Person A (Absender)", "conv_label_person_b": "Korrespondent", @@ -139,13 +139,14 @@ "conv_sort_label": "Sortierung:", "conv_sort_newest": "Neueste zuerst", "conv_sort_oldest": "Älteste zuerst", - "conv_empty_heading": "Korrespondenz durchsuchen", + "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", "conv_summary": "{count} Dokumente · {yearFrom}–{yearTo}", - "conv_new_doc_link": "Neues Dokument in dieser Korrespondenz", + "conv_new_doc_link": "Neues Dokument in diesem Briefwechsel", "conv_label_correspondent_optional": "Korrespondent", "conv_hint_single_person": "Alle Briefe von {name} — wähle einen Korrespondenten oben um einzugrenzen", "conv_hint_single_person_filtered": "Alle Briefe von {name} · {from}–{to} · {sortLabel}", @@ -159,6 +160,7 @@ "conv_suggestions_all_label": "Alle Korrespondenten von {name}", "conv_letters_count": "{count} Briefe", "conv_empty_search_placeholder": "Person suchen…", + "conv_hero_divider": "oder", "conv_empty_recent_label": "Zuletzt geöffnet", "conv_asym_sent": "{count} von {name} →", "conv_asym_received": "{count} von {name} ←", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 5e447abb..c58d2061 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -16,7 +16,7 @@ "error_internal_error": "An unexpected error occurred.", "nav_documents": "Documents", "nav_persons": "Persons", - "nav_conversations": "Correspondence", + "nav_conversations": "Letters", "nav_admin": "Admin", "nav_logout": "Sign out", "btn_save": "Save", @@ -130,7 +130,7 @@ "person_co_correspondents_heading": "Frequent correspondents", "person_correspondents_hint": "click to view conversation", "person_show_more": "+ {count} more", - "conv_heading": "Correspondence", + "conv_heading": "Letters", "conv_subtitle": "Browse a person's letters — with or without a correspondent.", "conv_label_person_a": "Person A (Sender)", "conv_label_person_b": "Correspondent", @@ -139,13 +139,14 @@ "conv_sort_label": "Sort:", "conv_sort_newest": "Newest first", "conv_sort_oldest": "Oldest first", - "conv_empty_heading": "Browse correspondence", + "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", "conv_summary": "{count} documents · {yearFrom}–{yearTo}", - "conv_new_doc_link": "New document in this correspondence", + "conv_new_doc_link": "New document in this exchange", "conv_label_correspondent_optional": "Correspondent", "conv_hint_single_person": "All letters from {name} — choose a correspondent above to narrow down", "conv_hint_single_person_filtered": "All letters from {name} · {from}–{to} · {sortLabel}", @@ -159,6 +160,7 @@ "conv_suggestions_all_label": "All correspondents of {name}", "conv_letters_count": "{count} letters", "conv_empty_search_placeholder": "Search person…", + "conv_hero_divider": "or", "conv_empty_recent_label": "Recently opened", "conv_asym_sent": "{count} from {name} →", "conv_asym_received": "{count} from {name} ←", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 95641956..10c0b414 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -16,7 +16,7 @@ "error_internal_error": "Se ha producido un error inesperado.", "nav_documents": "Documentos", "nav_persons": "Personas", - "nav_conversations": "Correspondencia", + "nav_conversations": "Cartas", "nav_admin": "Admin", "nav_logout": "Cerrar sesión", "btn_save": "Guardar", @@ -130,7 +130,7 @@ "person_co_correspondents_heading": "Corresponsales frecuentes", "person_correspondents_hint": "clic para ver conversación", "person_show_more": "+ {count} más", - "conv_heading": "Correspondencia", + "conv_heading": "Cartas", "conv_subtitle": "Explore las cartas de una persona — con o sin corresponsal.", "conv_label_person_a": "Persona A (Remitente)", "conv_label_person_b": "Corresponsal", @@ -139,13 +139,14 @@ "conv_sort_label": "Ordenar:", "conv_sort_newest": "Más reciente primero", "conv_sort_oldest": "Más antiguo primero", - "conv_empty_heading": "Explorar correspondencia", + "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", "conv_summary": "{count} documentos · {yearFrom}–{yearTo}", - "conv_new_doc_link": "Nuevo documento en esta correspondencia", + "conv_new_doc_link": "Nuevo documento en este intercambio", "conv_label_correspondent_optional": "Corresponsal", "conv_hint_single_person": "Todas las cartas de {name} — elige un corresponsal arriba para filtrar", "conv_hint_single_person_filtered": "Todas las cartas de {name} · {from}–{to} · {sortLabel}", @@ -159,6 +160,7 @@ "conv_suggestions_all_label": "Todos los corresponsales de {name}", "conv_letters_count": "{count} cartas", "conv_empty_search_placeholder": "Buscar persona…", + "conv_hero_divider": "o", "conv_empty_recent_label": "Recientemente abiertos", "conv_asym_sent": "{count} de {name} →", "conv_asym_received": "{count} de {name} ←", 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/lib/components/SortDropdown.svelte b/frontend/src/lib/components/SortDropdown.svelte index f6b2f7ec..753c82ac 100644 --- a/frontend/src/lib/components/SortDropdown.svelte +++ b/frontend/src/lib/components/SortDropdown.svelte @@ -47,6 +47,20 @@ function toggleDir() { class="-ml-px flex items-center justify-center border border-line bg-muted px-3 py-2.5 text-sm font-bold text-ink-2 transition hover:text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" aria-label={dir === 'asc' ? m.sort_dir_asc() : m.sort_dir_desc()} > - {dir === 'asc' ? '↑' : '↓'} + {#if dir === 'asc'} + + {:else} + + {/if} diff --git a/frontend/src/lib/components/SortDropdown.svelte.spec.ts b/frontend/src/lib/components/SortDropdown.svelte.spec.ts index 2c4282a8..98b12ac0 100644 --- a/frontend/src/lib/components/SortDropdown.svelte.spec.ts +++ b/frontend/src/lib/components/SortDropdown.svelte.spec.ts @@ -22,15 +22,19 @@ describe('SortDropdown', () => { await expect.element(btn).toBeInTheDocument(); }); - it('direction button shows ↑ when dir is asc', async () => { + it('direction button shows up arrow when dir is asc', async () => { render(SortDropdown, { sort: 'DATE', dir: 'asc' }); - const btn = page.getByRole('button'); - await expect.element(btn).toHaveTextContent('↑'); + await expect.element(page.getByRole('button')).toBeInTheDocument(); + const img = document.querySelector('button img') as HTMLImageElement; + expect(img).not.toBeNull(); + expect(img.src).toContain('Long-Arrow-Up'); }); - it('direction button shows ↓ when dir is desc', async () => { + it('direction button shows down arrow when dir is desc', async () => { render(SortDropdown, { sort: 'DATE', dir: 'desc' }); - const btn = page.getByRole('button'); - await expect.element(btn).toHaveTextContent('↓'); + await expect.element(page.getByRole('button')).toBeInTheDocument(); + const img = document.querySelector('button img') as HTMLImageElement; + expect(img).not.toBeNull(); + expect(img.src).toContain('Long-Arrow-Down'); }); }); diff --git a/frontend/src/routes/AppNav.svelte b/frontend/src/routes/AppNav.svelte index 4fe77704..026b7f72 100644 --- a/frontend/src/routes/AppNav.svelte +++ b/frontend/src/routes/AppNav.svelte @@ -60,9 +60,9 @@ function handleOverlayKeydown(event: KeyboardEvent) { @@ -161,9 +161,9 @@ function handleOverlayKeydown(event: KeyboardEvent) { diff --git a/frontend/src/routes/SearchFilterBar.svelte b/frontend/src/routes/SearchFilterBar.svelte index 589476df..20328af0 100644 --- a/frontend/src/routes/SearchFilterBar.svelte +++ b/frontend/src/routes/SearchFilterBar.svelte @@ -1,6 +1,7 @@ + +{#if showHero} + +
+ +
+{:else} + +
+
+ (showAdvanced = !showAdvanced)} + /> + + {#if showAdvanced} + + {/if} + + {#if isSinglePerson} + + {/if} +
+ +
+ {#if data.documents.length === 0} +
+

{m.conv_no_results_heading()}

+

{m.conv_no_results_text()}

+
+ {:else} + + {/if} +
+
+{/if} diff --git a/frontend/src/routes/korrespondenz/ConversationFilterBar.svelte b/frontend/src/routes/briefwechsel/ConversationFilterBar.svelte similarity index 100% rename from frontend/src/routes/korrespondenz/ConversationFilterBar.svelte rename to frontend/src/routes/briefwechsel/ConversationFilterBar.svelte diff --git a/frontend/src/routes/korrespondenz/ConversationTimeline.svelte b/frontend/src/routes/briefwechsel/ConversationTimeline.svelte similarity index 86% rename from frontend/src/routes/korrespondenz/ConversationTimeline.svelte rename to frontend/src/routes/briefwechsel/ConversationTimeline.svelte index 3502803d..4a2842e7 100644 --- a/frontend/src/routes/korrespondenz/ConversationTimeline.svelte +++ b/frontend/src/routes/briefwechsel/ConversationTimeline.svelte @@ -84,8 +84,24 @@ const newDocUrl = $derived( aria-label="Briefverteilung in diesem Zeitraum: {outCount} von {senderName ?? ''}, {inCount} von {receiverName ?? ''}" >
- {outCount} von {shortSenderName} → - {inCount} von {shortReceiverName} ← + {outCount} von {shortSenderName} + + {inCount} von {shortReceiverName} +
@@ -115,14 +131,14 @@ const newDocUrl = $derived( class:border-l-primary={isOut} class:border-l-accent={!isOut} > - + class="h-4 w-4 shrink-0 opacity-60" + />
diff --git a/frontend/src/routes/korrespondenz/CorrespondentSuggestionsDropdown.svelte b/frontend/src/routes/briefwechsel/CorrespondentSuggestionsDropdown.svelte similarity index 100% rename from frontend/src/routes/korrespondenz/CorrespondentSuggestionsDropdown.svelte rename to frontend/src/routes/briefwechsel/CorrespondentSuggestionsDropdown.svelte diff --git a/frontend/src/routes/briefwechsel/CorrespondenzFilterControls.svelte b/frontend/src/routes/briefwechsel/CorrespondenzFilterControls.svelte new file mode 100644 index 00000000..70d2ef45 --- /dev/null +++ b/frontend/src/routes/briefwechsel/CorrespondenzFilterControls.svelte @@ -0,0 +1,48 @@ + + +
+ +
+ + onapplyFilters()} + class="block w-full rounded-md border border-line bg-surface px-3 py-2.5 text-sm text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" + /> +
+ + +
+ + onapplyFilters()} + class="block w-full rounded-md border border-line bg-surface px-3 py-2.5 text-sm text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring" + /> +
+
diff --git a/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte new file mode 100644 index 00000000..e059370d --- /dev/null +++ b/frontend/src/routes/briefwechsel/CorrespondenzHero.svelte @@ -0,0 +1,92 @@ + + +
+ +

+ {m.conv_empty_heading()} +

+ + +
+ {m.conv_hero_crosslink()} + + + +
+ +
+ + + {#if recentPersons.length > 0} +
+
+ {m.conv_hero_divider()} +
+
+ +
+ + {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'); + }); +}); diff --git a/frontend/src/routes/briefwechsel/CorrespondenzPersonBar.svelte b/frontend/src/routes/briefwechsel/CorrespondenzPersonBar.svelte new file mode 100644 index 00000000..62d67337 --- /dev/null +++ b/frontend/src/routes/briefwechsel/CorrespondenzPersonBar.svelte @@ -0,0 +1,187 @@ + + + +
+ +
+ { if (id) onapplyFilters(); }} + /> +
+ + + + + +
+ { + showSuggestions = false; + onapplyFilters(); + }} + onfocused={handleCorrespondentFocused} + /> + {#if showSuggestions && senderId && !receiverId} + (showSuggestions = false)} + /> + {/if} +
+
+ + +
+ + + + + + + + + {m.conv_letters_count({ count: documentCount })} + +
diff --git a/frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte b/frontend/src/routes/briefwechsel/SinglePersonHintBar.svelte similarity index 91% rename from frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte rename to frontend/src/routes/briefwechsel/SinglePersonHintBar.svelte index 034e0284..ab867c4f 100644 --- a/frontend/src/routes/korrespondenz/SinglePersonHintBar.svelte +++ b/frontend/src/routes/briefwechsel/SinglePersonHintBar.svelte @@ -19,7 +19,7 @@ let toYear = $derived(toDate ? toDate.substring(0, 4) : '');
{ - it('shows the search heading when no person is selected', async () => { +describe('Briefwechsel page – hero state', () => { + it('shows the hero when no person is selected', async () => { render(Page, { data: baseData }); - await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument(); + await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument(); }); - it('shows the empty-search button', async () => { + it('shows the discovery headline', async () => { render(Page, { data: baseData }); - await expect.element(page.getByTestId('conv-empty-search')).toBeInTheDocument(); + await expect.element(page.getByText(/Wessen Briefe möchten Sie lesen/i)).toBeInTheDocument(); + }); + + it('does not show the person bar in hero state', async () => { + render(Page, { data: baseData }); + await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument(); + await expect.element(page.getByTestId('conv-person-bar')).not.toBeInTheDocument(); + }); + + it('does not show filter controls in hero state', async () => { + render(Page, { data: baseData }); + await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument(); + await expect.element(page.getByTestId('conv-filter-controls')).not.toBeInTheDocument(); }); it('does not show the new document link when no person is selected', async () => { @@ -77,9 +89,30 @@ describe('Korrespondenz page – empty state', () => { }); }); +// ─── Results state (senderId set) ──────────────────────────────────────────── + +describe('Briefwechsel page – results state', () => { + it('does not show the hero when senderId is set', async () => { + render(Page, { data: withSender }); + await expect.element(page.getByTestId('conv-person-bar')).toBeInTheDocument(); + await expect.element(page.getByTestId('conv-hero')).not.toBeInTheDocument(); + }); + + it('shows the person bar when senderId is set', async () => { + render(Page, { data: withSender }); + await expect.element(page.getByTestId('conv-person-bar')).toBeInTheDocument(); + }); + + it('hides filter controls by default (collapsible)', async () => { + render(Page, { data: withSender }); + await expect.element(page.getByTestId('conv-person-bar')).toBeInTheDocument(); + await expect.element(page.getByTestId('conv-filter-controls')).not.toBeInTheDocument(); + }); +}); + // ─── Recent persons chips ───────────────────────────────────────────────────── -describe('Korrespondenz page – recent persons', () => { +describe('Briefwechsel page – recent persons', () => { it('shows recent person chips from localStorage', async () => { localStorage.setItem( 'korrespondenz_recent_persons', @@ -93,15 +126,14 @@ describe('Korrespondenz page – recent persons', () => { it('does not crash when localStorage contains corrupt JSON', async () => { localStorage.setItem('korrespondenz_recent_persons', '}{not valid json'); render(Page, { data: baseData }); - // Empty state heading is still shown — no chip list crash - await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument(); + await expect.element(page.getByText(/Wessen Briefe möchten Sie lesen/i)).toBeInTheDocument(); localStorage.removeItem('korrespondenz_recent_persons'); }); }); // ─── Single-person hint bar ─────────────────────────────────────────────────── -describe('Korrespondenz page – single-person hint bar', () => { +describe('Briefwechsel page – single-person hint bar', () => { it('shows hint bar when only senderId is set', async () => { render(Page, { data: withSender }); await expect.element(page.getByText(/Alle Briefe von Hans Müller/i)).toBeInTheDocument(); @@ -118,25 +150,9 @@ describe('Korrespondenz page – single-person hint bar', () => { }); }); -// ─── Filter controls disabled state ────────────────────────────────────────── - -describe('Korrespondenz page – filter strip Row 2 disabled state', () => { - it('renders filter controls with aria-disabled when no senderId', async () => { - render(Page, { data: baseData }); - const strip = document.querySelector('[aria-disabled="true"]'); - expect(strip).not.toBeNull(); - }); - - it('filter controls are not aria-disabled when senderId is set', async () => { - render(Page, { data: withSender }); - const strip = document.querySelector('[aria-disabled="false"]'); - expect(strip).not.toBeNull(); - }); -}); - // ─── Strip letter count ─────────────────────────────────────────────────────── -describe('Korrespondenz page – strip letter count', () => { +describe('Briefwechsel page – strip letter count', () => { it('shows 0 Briefe when senderId is set but no documents', async () => { render(Page, { data: withSender }); await expect.element(page.getByTestId('conv-strip-count')).toHaveTextContent('0 Briefe'); @@ -150,7 +166,7 @@ describe('Korrespondenz page – strip letter count', () => { // ─── No results ─────────────────────────────────────────────────────────────── -describe('Korrespondenz page – no results', () => { +describe('Briefwechsel page – no results', () => { it('shows "no documents found" when a person is selected but there are no documents', async () => { render(Page, { data: withSender }); await expect.element(page.getByText(/Keine Dokumente gefunden/i)).toBeInTheDocument(); @@ -159,12 +175,11 @@ describe('Korrespondenz page – no results', () => { // ─── Swap button ────────────────────────────────────────────────────────────── -describe('Korrespondenz page – swap button', () => { +describe('Briefwechsel page – swap button', () => { it('swap button is invisible when only one person is set', async () => { render(Page, { data: withSender }); const btn = document.querySelector('[data-testid="conv-swap-btn"]'); expect(btn).not.toBeNull(); - // opacity-0 is applied via class when swapVisible is false expect(btn!.className).toMatch(/opacity-0/); }); @@ -187,7 +202,7 @@ describe('Korrespondenz page – swap button', () => { // ─── Year dividers ──────────────────────────────────────────────────────────── -describe('Korrespondenz page – year dividers', () => { +describe('Briefwechsel page – year dividers', () => { it('renders a year divider for the first document', async () => { render(Page, { data: withDocs }); await expect.element(page.getByTestId('year-divider').first()).toHaveTextContent('1923'); @@ -222,7 +237,7 @@ describe('Korrespondenz page – year dividers', () => { // ─── New document link ──────────────────────────────────────────────────────── -describe('Korrespondenz page – new document link', () => { +describe('Briefwechsel page – new document link', () => { it('shows the link with correct href for a write user (bilateral)', async () => { render(Page, { data: { ...withDocs, canWrite: true } }); const link = page.getByTestId('conv-new-doc-link'); diff --git a/frontend/src/routes/korrespondenz/+page.svelte b/frontend/src/routes/korrespondenz/+page.svelte deleted file mode 100644 index c6cddf6d..00000000 --- a/frontend/src/routes/korrespondenz/+page.svelte +++ /dev/null @@ -1,140 +0,0 @@ - - - -
- - - - - - - - {#if isSinglePerson} - - {/if} -
- - -
- {#if !senderId} - - {:else if data.documents.length === 0} -
-

{m.conv_no_results_heading()}

-

{m.conv_no_results_text()}

-
- {:else} - - {/if} -
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte b/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte deleted file mode 100644 index b6a3ad64..00000000 --- a/frontend/src/routes/korrespondenz/CorrespondenzEmptyState.svelte +++ /dev/null @@ -1,120 +0,0 @@ - - -
- -
- -
- - -

{m.conv_empty_heading()}

- - -

- {m.conv_empty_text()} -

- - - - - - {#if recentPersons.length > 0} - -
-
- oder -
-
- -
- - {m.conv_empty_recent_label()} - -
- {#each recentPersons as person (person.id)} - - - {/each} -
-
- {/if} -
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte b/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte deleted file mode 100644 index d26bd3bb..00000000 --- a/frontend/src/routes/korrespondenz/CorrespondenzFilterControls.svelte +++ /dev/null @@ -1,115 +0,0 @@ - - -
- - - - - onapplyFilters()} - placeholder={m.conv_strip_from_placeholder()} - class="h-8 w-[100px] rounded border bg-surface px-2 text-xs text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring {fromDate ? 'border-primary' : 'border-line'}" - /> - - - - - onapplyFilters()} - placeholder={m.conv_strip_to_placeholder()} - class="h-8 w-[100px] rounded border bg-surface px-2 text-xs text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring {toDate ? 'border-primary' : 'border-line'}" - /> - - - - {m.conv_letters_count({ count: documentCount ?? 0 })} - - - - -
diff --git a/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte b/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte deleted file mode 100644 index 7a1da482..00000000 --- a/frontend/src/routes/korrespondenz/CorrespondenzPersonBar.svelte +++ /dev/null @@ -1,129 +0,0 @@ - - -
- -
- onapplyFilters()} - /> -
- - - - - -
- { - showSuggestions = false; - onapplyFilters(); - }} - onfocused={handleCorrespondentFocused} - /> - {#if showSuggestions && senderId && !receiverId} - (showSuggestions = false)} - /> - {/if} -
-
diff --git a/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte b/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte index b6f0b01d..1db48079 100644 --- a/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte +++ b/frontend/src/routes/persons/[id]/CoCorrespondentsList.svelte @@ -30,7 +30,7 @@ function initials(name: string): string {
{#each coCorrespondents as c (c.id)}