fix(korrespondenz): address 10 visual and functional regressions

- Strip full-bleed: remove max-w container, put strips at page level
- Remove page heading/subtitle above strip (not in spec)
- Swap button always visible (drop opacity-0, keep pointer-events-none)
- Korrespondent placeholder "Alle Korrespondenten" + label "— optional"
- Add placeholder prop to PersonTypeahead; add onfocused callback prop
- "Person suchen" button now focuses #senderId-search instead of no-op navigate
- Wire CorrespondentSuggestionsDropdown on correspondent field focus
- Hint bar: bold name via <strong>, year-only dates (no ISO strings)
- Asymmetry bar: use first name only to prevent label overflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-30 13:57:00 +02:00
parent 49f6b0a8c7
commit 0387e9f428
5 changed files with 83 additions and 64 deletions

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import PersonTypeahead from '$lib/components/PersonTypeahead.svelte';
import CorrespondentSuggestionsDropdown from './CorrespondentSuggestionsDropdown.svelte';
interface Props {
senderId?: string;
@@ -20,6 +21,18 @@ let {
}: Props = $props();
let swapVisible = $derived(!!(senderId && receiverId));
let showSuggestions = $state(false);
function handleCorrespondentFocused() {
if (senderId) showSuggestions = true;
}
function handleSuggestionSelect(id: string) {
receiverId = id;
showSuggestions = false;
onapplyFilters();
}
</script>
<div class="flex items-end gap-[9px] border-b border-[#EAE7E0] bg-white px-4 py-[9px] sm:px-[18px]">
@@ -42,7 +55,6 @@ let swapVisible = $derived(!!(senderId && receiverId));
aria-label="Personen tauschen"
onclick={onswapPersons}
class="mb-1 flex h-7 w-7 shrink-0 items-center justify-center rounded border border-[#D1D5DB] bg-white text-[#888] transition-colors hover:border-[#002850] hover:text-[#002850]"
class:opacity-0={!swapVisible}
class:pointer-events-none={!swapVisible}
tabindex={swapVisible ? 0 : -1}
>
@@ -65,23 +77,31 @@ let swapVisible = $derived(!!(senderId && receiverId));
<!-- Korrespondent field -->
<div
class="min-w-0 flex-1"
class="relative min-w-0 flex-1"
class:[&_input]:border-dashed={!receiverId}
class:[&_input]:border-solid={!!receiverId}
class:[&_input]:bg-[#F9F8F6]={!receiverId}
>
<PersonTypeahead
name="receiverId"
label={receiverId ? 'Korrespondent' : 'Korrespondent'}
label={receiverId ? 'Korrespondent' : 'Korrespondent — optional'}
bind:value={receiverId}
initialName={initialReceiverName}
placeholder="Alle Korrespondenten"
restrictToCorrespondentsOf={senderId || undefined}
onchange={() => onapplyFilters()}
onchange={() => {
showSuggestions = false;
onapplyFilters();
}}
onfocused={handleCorrespondentFocused}
/>
{#if !receiverId}
<span class="pointer-events-none absolute -mt-[1px] text-[11px] text-[#AAA] italic">
— optional
</span>
{#if showSuggestions && senderId && !receiverId}
<CorrespondentSuggestionsDropdown
senderId={senderId}
senderName=""
onselect={handleSuggestionSelect}
onclose={() => (showSuggestions = false)}
/>
{/if}
</div>
</div>