fix(korrespondenz): dark theme, compact strip labels, year divider size, chevron alignment
- Add compact prop to PersonTypeahead: 7px uppercase label, 30px h input (matches spec FL/FI) - Replace all hardcoded hex in 6 korrespondenz components with theme tokens (bg-surface, bg-muted, bg-canvas, border-line, text-ink, text-primary, text-accent, etc.) - Fix year divider: text-[15px] font-black (spec: 15px/900) - Fix log row chevron: items-center instead of items-start for vertical centering - Fix recent-persons persistence: move persistRecentPerson to post-navigation $effect so senderName is resolved from server before stored in localStorage - Add metadataComplete field to makeDoc() fixture to satisfy updated Document type - Restore opacity-0 on swap button when only one person is set (matches spec + test) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ interface Props {
|
|||||||
initialName?: string;
|
initialName?: string;
|
||||||
suggestedName?: string;
|
suggestedName?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
compact?: boolean;
|
||||||
restrictToCorrespondentsOf?: string;
|
restrictToCorrespondentsOf?: string;
|
||||||
onchange?: (value: string) => void;
|
onchange?: (value: string) => void;
|
||||||
onfocused?: () => void;
|
onfocused?: () => void;
|
||||||
@@ -23,6 +24,7 @@ let {
|
|||||||
initialName = '',
|
initialName = '',
|
||||||
suggestedName = '',
|
suggestedName = '',
|
||||||
placeholder,
|
placeholder,
|
||||||
|
compact = false,
|
||||||
restrictToCorrespondentsOf,
|
restrictToCorrespondentsOf,
|
||||||
onchange,
|
onchange,
|
||||||
onfocused
|
onfocused
|
||||||
@@ -125,7 +127,13 @@ function clickOutside(node: HTMLElement) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative" use:clickOutside>
|
<div class="relative" use:clickOutside>
|
||||||
<label for={name} class="block text-sm font-medium text-ink-2">{label}</label>
|
<label
|
||||||
|
for={name}
|
||||||
|
class={compact
|
||||||
|
? 'block text-[7px] font-extrabold tracking-[0.5px] text-ink-3 uppercase'
|
||||||
|
: 'block text-sm font-medium text-ink-2'}
|
||||||
|
>{label}</label
|
||||||
|
>
|
||||||
|
|
||||||
<input type="hidden" name={name} bind:value={value} />
|
<input type="hidden" name={name} bind:value={value} />
|
||||||
|
|
||||||
@@ -137,7 +145,9 @@ function clickOutside(node: HTMLElement) {
|
|||||||
oninput={handleInput}
|
oninput={handleInput}
|
||||||
onfocus={handleFocus}
|
onfocus={handleFocus}
|
||||||
placeholder={placeholder ?? m.comp_typeahead_placeholder()}
|
placeholder={placeholder ?? m.comp_typeahead_placeholder()}
|
||||||
class="mt-1 block w-full rounded-md border border-line p-2 shadow-sm focus:border-accent focus:ring-accent"
|
class={compact
|
||||||
|
? 'block h-[30px] w-full rounded-[3px] border-[1.5px] border-line bg-surface px-[7px] text-[9px] text-ink placeholder:text-ink-3 focus:border-primary focus:outline-none'
|
||||||
|
: 'mt-1 block w-full rounded-md border border-line bg-surface p-2 text-ink shadow-sm placeholder:text-ink-3 focus:border-accent focus:ring-accent'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if showDropdown && (results.length > 0 || loading)}
|
{#if showDropdown && (results.length > 0 || loading)}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ let sortDir = $state(untrack(() => data.filters.dir));
|
|||||||
let senderName = $state(untrack(() => data.initialValues.senderName));
|
let senderName = $state(untrack(() => data.initialValues.senderName));
|
||||||
let receiverName = $state(untrack(() => data.initialValues.receiverName));
|
let receiverName = $state(untrack(() => data.initialValues.receiverName));
|
||||||
|
|
||||||
// Sync with server data after navigation
|
// Sync with server data after navigation; persist recent persons once the name is resolved
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
senderId = data.filters.senderId;
|
senderId = data.filters.senderId;
|
||||||
receiverId = data.filters.receiverId;
|
receiverId = data.filters.receiverId;
|
||||||
@@ -30,6 +30,9 @@ $effect(() => {
|
|||||||
sortDir = data.filters.dir;
|
sortDir = data.filters.dir;
|
||||||
senderName = data.initialValues.senderName;
|
senderName = data.initialValues.senderName;
|
||||||
receiverName = data.initialValues.receiverName;
|
receiverName = data.initialValues.receiverName;
|
||||||
|
if (data.filters.senderId && data.initialValues.senderName) {
|
||||||
|
persistRecentPerson(data.filters.senderId, data.initialValues.senderName);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSinglePerson = $derived(!!senderId && !receiverId);
|
const isSinglePerson = $derived(!!senderId && !receiverId);
|
||||||
@@ -51,9 +54,6 @@ function persistRecentPerson(id: string, name: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyFilters() {
|
function applyFilters() {
|
||||||
// Persist to recent persons when a person is selected
|
|
||||||
if (senderId && senderName) persistRecentPerson(senderId, senderName);
|
|
||||||
|
|
||||||
const params = new SvelteURLSearchParams();
|
const params = new SvelteURLSearchParams();
|
||||||
if (senderId) params.set('senderId', senderId);
|
if (senderId) params.set('senderId', senderId);
|
||||||
if (receiverId) params.set('receiverId', receiverId);
|
if (receiverId) params.set('receiverId', receiverId);
|
||||||
|
|||||||
@@ -80,30 +80,30 @@ const newDocUrl = $derived(
|
|||||||
|
|
||||||
{#if isBilateral && documents.length > 0}
|
{#if isBilateral && documents.length > 0}
|
||||||
<div
|
<div
|
||||||
class="flex flex-col gap-1 border-b border-[#E8E4DF] bg-[#F7F5F2] px-[18px] py-2"
|
class="flex flex-col gap-1 border-b border-line bg-muted px-[18px] py-2"
|
||||||
role="img"
|
role="img"
|
||||||
aria-label="Briefverteilung in diesem Zeitraum: {outCount} von {senderName ?? ''}, {inCount} von {receiverName ?? ''}"
|
aria-label="Briefverteilung in diesem Zeitraum: {outCount} von {senderName ?? ''}, {inCount} von {receiverName ?? ''}"
|
||||||
>
|
>
|
||||||
<div class="flex justify-between text-[10px] font-bold">
|
<div class="flex justify-between text-[10px] font-bold">
|
||||||
<span class="text-[#002850]">{outCount} von {shortSenderName} →</span>
|
<span class="text-primary">{outCount} von {shortSenderName} →</span>
|
||||||
<span class="text-[#0F5755]">{inCount} von {shortReceiverName} ←</span>
|
<span class="text-accent">{inCount} von {shortReceiverName} ←</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex h-[5px] overflow-hidden rounded-full bg-[#E0DDD6]">
|
<div class="flex h-[5px] overflow-hidden rounded-full bg-line">
|
||||||
<div class="h-full bg-[#002850] transition-all" style="width: {outPct}%"></div>
|
<div class="h-full bg-primary transition-all" style="width: {outPct}%"></div>
|
||||||
<div class="h-full bg-[#A6DAD8] transition-all" style="width: {100 - outPct}%"></div>
|
<div class="h-full bg-accent transition-all" style="width: {100 - outPct}%"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="overflow-hidden rounded-sm border border-[#E0DDD6] bg-white">
|
<div class="overflow-hidden rounded-sm border border-line bg-surface">
|
||||||
{#each enrichedDocuments as { doc, year, showYearDivider, isOut } (doc.id)}
|
{#each enrichedDocuments as { doc, year, showYearDivider, isOut } (doc.id)}
|
||||||
{#if showYearDivider && year !== null}
|
{#if showYearDivider && year !== null}
|
||||||
<div
|
<div
|
||||||
data-testid="year-divider"
|
data-testid="year-divider"
|
||||||
class="flex items-baseline gap-2 border-t-2 border-b border-[#C8C4BE] border-[#D8D4CE] bg-[#F0EDE6] px-[14px] py-[6px]"
|
class="flex items-baseline gap-2 border-t-2 border-b border-line bg-muted px-[14px] py-[6px]"
|
||||||
>
|
>
|
||||||
<span class="text-base font-black tracking-tight text-[#002850]">{year}</span>
|
<span class="text-[15px] leading-none font-black tracking-tight text-primary">{year}</span>
|
||||||
<span class="text-xs font-bold text-[#AAA]">{countsByYear.get(year) ?? 0} Briefe</span>
|
<span class="text-[10px] font-bold text-ink-3">{countsByYear.get(year) ?? 0} Briefe</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -112,31 +112,31 @@ const newDocUrl = $derived(
|
|||||||
aria-label="{doc.title || doc.originalFilename}, {doc.documentDate
|
aria-label="{doc.title || doc.originalFilename}, {doc.documentDate
|
||||||
? formatDate(doc.documentDate)
|
? formatDate(doc.documentDate)
|
||||||
: ''}"
|
: ''}"
|
||||||
class="group flex min-h-[44px] cursor-pointer items-start gap-[9px] border-b border-l-[3px] border-[#EDEBE4] px-[14px] py-[10px] transition-colors last:border-b-0 hover:bg-[#F7F5F2]"
|
class="group flex min-h-[44px] cursor-pointer items-center gap-[9px] border-b border-l-[3px] border-line-2 px-[14px] py-[10px] transition-colors last:border-b-0 hover:bg-muted"
|
||||||
class:border-l-[#002850]={isOut}
|
class:border-l-primary={isOut}
|
||||||
class:border-l-[#A6DAD8]={!isOut}
|
class:border-l-accent={!isOut}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="w-[14px] shrink-0 pt-[1px] text-xs font-black"
|
class="w-[14px] shrink-0 text-xs font-black"
|
||||||
class:text-[#002850]={isOut}
|
class:text-primary={isOut}
|
||||||
class:text-[#0F5755]={!isOut}
|
class:text-accent={!isOut}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
{isOut ? '→' : '←'}
|
{isOut ? '→' : '←'}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="mb-[2px] truncate text-sm font-bold text-[#0D2240]">
|
<div class="mb-[2px] truncate text-sm font-bold text-ink">
|
||||||
{doc.title || doc.originalFilename}
|
{doc.title || doc.originalFilename}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-[5px] text-xs text-[#888]">
|
<div class="flex items-center gap-[5px] text-xs text-ink-3">
|
||||||
<span>{doc.documentDate ? formatDate(doc.documentDate) : '—'}</span>
|
<span>{doc.documentDate ? formatDate(doc.documentDate) : '—'}</span>
|
||||||
{#if doc.location}
|
{#if doc.location}
|
||||||
<span class="text-[#D1CCC8]">·</span>
|
<span class="text-line">·</span>
|
||||||
<span>{doc.location}</span>
|
<span>{doc.location}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !receiverId}
|
{#if !receiverId}
|
||||||
<span class="text-[#D1CCC8]">·</span>
|
<span class="text-line">·</span>
|
||||||
<span>{otherPartyName(doc)}</span>
|
<span>{otherPartyName(doc)}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<span
|
<span
|
||||||
@@ -147,18 +147,18 @@ const newDocUrl = $derived(
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="shrink-0 text-[#888] opacity-0 transition-opacity group-hover:opacity-100"
|
class="shrink-0 text-ink-3 opacity-0 transition-opacity group-hover:opacity-100"
|
||||||
aria-hidden="true">›</span
|
aria-hidden="true">›</span
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if canWrite}
|
{#if canWrite}
|
||||||
<div class="flex justify-end border-t border-[#E8E4DF] px-[14px] py-[6px]">
|
<div class="flex justify-end border-t border-line px-[14px] py-[6px]">
|
||||||
<a
|
<a
|
||||||
href={newDocUrl}
|
href={newDocUrl}
|
||||||
data-testid="conv-new-doc-link"
|
data-testid="conv-new-doc-link"
|
||||||
class="inline-flex items-center gap-1 text-xs font-bold text-[#002850]/50 transition-colors hover:text-[#002850]"
|
class="inline-flex items-center gap-1 text-xs font-bold text-primary/50 transition-colors hover:text-primary"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
class="h-3 w-3"
|
class="h-3 w-3"
|
||||||
|
|||||||
@@ -79,11 +79,11 @@ function getInitials(person: Correspondent): string {
|
|||||||
role="listbox"
|
role="listbox"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
aria-label={conv_suggestions_heading()}
|
aria-label={conv_suggestions_heading()}
|
||||||
class="absolute top-full right-0 left-0 z-30 mt-1 rounded-sm border border-[#E0DDD6] bg-white shadow-lg"
|
class="absolute top-full right-0 left-0 z-30 mt-1 rounded-sm border border-line bg-surface shadow-lg"
|
||||||
onkeydown={(e) => handleKeydown(e, e.currentTarget as HTMLElement)}
|
onkeydown={(e) => handleKeydown(e, e.currentTarget as HTMLElement)}
|
||||||
>
|
>
|
||||||
<!-- Heading -->
|
<!-- Heading -->
|
||||||
<div class="px-3 pt-2 pb-1 text-[10px] font-bold tracking-widest text-[#888] uppercase">
|
<div class="px-3 pt-2 pb-1 text-[10px] font-bold tracking-widest text-ink-3 uppercase">
|
||||||
{conv_suggestions_heading()}
|
{conv_suggestions_heading()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -94,33 +94,32 @@ function getInitials(person: Correspondent): string {
|
|||||||
role="option"
|
role="option"
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="flex cursor-pointer items-center gap-2 px-3 py-2 text-sm text-[#333] hover:bg-[#F7F5F2] focus:bg-[#F7F5F2] focus:outline-none"
|
class="flex cursor-pointer items-center gap-2 px-3 py-2 text-sm text-ink hover:bg-muted focus:bg-muted focus:outline-none"
|
||||||
onclick={() => onselect(person.id)}
|
onclick={() => onselect(person.id)}
|
||||||
onkeydown={(e) => e.key === 'Enter' && onselect(person.id)}
|
onkeydown={(e) => e.key === 'Enter' && onselect(person.id)}
|
||||||
>
|
>
|
||||||
<!-- Avatar with initials -->
|
<!-- Avatar with initials -->
|
||||||
<span
|
<span
|
||||||
class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-[#002850] text-[10px] font-bold text-white"
|
class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-fg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
{getInitials(person)}
|
{getInitials(person)}
|
||||||
</span>
|
</span>
|
||||||
<!-- Svelte auto-escapes — do not use {@html} here. -->
|
<!-- Svelte auto-escapes — do not use {@html} here. -->
|
||||||
{person.lastName}, {person.firstName}
|
{person.lastName}, {person.firstName}
|
||||||
<!-- TODO: show proportional letter-count bar when counts are available from the API -->
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Separator -->
|
<!-- Separator -->
|
||||||
<div class="mt-1 border-t border-[#E0DDD6]"></div>
|
<div class="mt-1 border-t border-line"></div>
|
||||||
|
|
||||||
<!-- "Alle Korrespondenten" row -->
|
<!-- "Alle Korrespondenten" row -->
|
||||||
<div
|
<div
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected="false"
|
aria-selected="false"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="flex cursor-pointer items-center gap-2 px-3 py-2 text-sm text-[#333] hover:bg-[#F7F5F2] focus:bg-[#F7F5F2] focus:outline-none"
|
class="flex cursor-pointer items-center gap-2 px-3 py-2 text-sm text-ink hover:bg-muted focus:bg-muted focus:outline-none"
|
||||||
onclick={() => onselect('')}
|
onclick={() => onselect('')}
|
||||||
onkeydown={(e) => e.key === 'Enter' && onselect('')}
|
onkeydown={(e) => e.key === 'Enter' && onselect('')}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ onMount(() => {
|
|||||||
|
|
||||||
<div class="mx-auto flex max-w-sm flex-col items-center gap-4 py-16 text-center">
|
<div class="mx-auto flex max-w-sm flex-col items-center gap-4 py-16 text-center">
|
||||||
<!-- Icon circle -->
|
<!-- Icon circle -->
|
||||||
<div class="rounded-full bg-[#F0EDE6] p-4">
|
<div class="rounded-full bg-muted p-4">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
@@ -41,7 +41,7 @@ onMount(() => {
|
|||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
class="text-[#002850]"
|
class="text-primary"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
<rect x="2" y="4" width="20" height="16" rx="2" />
|
<rect x="2" y="4" width="20" height="16" rx="2" />
|
||||||
@@ -50,10 +50,10 @@ onMount(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Heading -->
|
<!-- Heading -->
|
||||||
<h2 class="font-serif text-sm font-black text-[#0D2240]">Korrespondenz durchsuchen</h2>
|
<h2 class="font-serif text-sm font-black text-ink">Korrespondenz durchsuchen</h2>
|
||||||
|
|
||||||
<!-- Subtext -->
|
<!-- Subtext -->
|
||||||
<p class="max-w-[280px] text-xs text-[#888]">
|
<p class="max-w-[280px] text-xs text-ink-3">
|
||||||
Wähle eine Person aus dem Archiv um deren Briefe zu sehen — mit oder ohne Korrespondent.
|
Wähle eine Person aus dem Archiv um deren Briefe zu sehen — mit oder ohne Korrespondent.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ onMount(() => {
|
|||||||
data-testid="conv-empty-search"
|
data-testid="conv-empty-search"
|
||||||
aria-label={conv_empty_search_placeholder()}
|
aria-label={conv_empty_search_placeholder()}
|
||||||
onclick={() => onSelectPerson('')}
|
onclick={() => onSelectPerson('')}
|
||||||
class="flex h-[28px] w-[260px] items-center rounded-sm border border-[#D1D5DB] bg-[#F9F8F6] px-3 text-xs text-[#AAA] italic transition-colors hover:border-[#002850]"
|
class="flex h-[28px] w-[260px] items-center rounded-sm border border-line bg-muted px-3 text-xs text-ink-3 italic transition-colors hover:border-primary"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -86,15 +86,15 @@ onMount(() => {
|
|||||||
|
|
||||||
<!-- Divider -->
|
<!-- Divider -->
|
||||||
<div class="flex w-full items-center gap-2">
|
<div class="flex w-full items-center gap-2">
|
||||||
<div class="flex-1 border-t border-[#E0DDD6]"></div>
|
<div class="flex-1 border-t border-line"></div>
|
||||||
<span class="text-[10px] font-bold tracking-wider text-[#AAA] uppercase">oder</span>
|
<span class="text-[10px] font-bold tracking-wider text-ink-3 uppercase">oder</span>
|
||||||
<div class="flex-1 border-t border-[#E0DDD6]"></div>
|
<div class="flex-1 border-t border-line"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Recent persons -->
|
<!-- Recent persons -->
|
||||||
{#if recentPersons.length > 0}
|
{#if recentPersons.length > 0}
|
||||||
<div class="flex w-full flex-col items-center gap-2">
|
<div class="flex w-full flex-col items-center gap-2">
|
||||||
<span class="text-[10px] font-bold tracking-widest text-[#888] uppercase">
|
<span class="text-[10px] font-bold tracking-widest text-ink-3 uppercase">
|
||||||
{conv_empty_recent_label()}
|
{conv_empty_recent_label()}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex flex-wrap justify-center gap-2">
|
<div class="flex flex-wrap justify-center gap-2">
|
||||||
@@ -103,10 +103,10 @@ onMount(() => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => onSelectPerson(person.id)}
|
onclick={() => onSelectPerson(person.id)}
|
||||||
class="flex items-center gap-1.5 rounded-full border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-bold text-[#333] transition-colors hover:border-[#002850] hover:text-[#002850]"
|
class="flex items-center gap-1.5 rounded-full border border-line bg-surface px-3 py-1.5 text-xs font-bold text-ink transition-colors hover:border-primary hover:text-primary"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-[#002850] text-[10px] text-white"
|
class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-primary text-[10px] text-primary-fg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
>
|
||||||
{person.name.charAt(0).toUpperCase()}
|
{person.name.charAt(0).toUpperCase()}
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ let isActive = $derived(!!(fromDate || toDate || sortDir !== 'DESC'));
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-[10px] border-b border-[#E0DDD6] bg-[#F7F5F2] px-4 py-[5px] transition-opacity sm:px-[18px]"
|
class="flex items-center gap-[10px] border-b border-line bg-muted px-4 py-[5px] transition-opacity sm:px-[18px]"
|
||||||
class:opacity-40={!senderId}
|
class:opacity-40={!senderId}
|
||||||
class:pointer-events-none={!senderId}
|
class:pointer-events-none={!senderId}
|
||||||
aria-disabled={!senderId}
|
aria-disabled={!senderId}
|
||||||
>
|
>
|
||||||
<!-- Period label -->
|
<!-- Period label -->
|
||||||
<span class="hidden text-xs font-bold text-[#888] sm:block">
|
<span class="hidden text-[7px] font-extrabold tracking-[0.5px] text-ink-3 uppercase sm:block">
|
||||||
{conv_strip_period()}
|
{conv_strip_period()}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -50,15 +50,12 @@ let isActive = $derived(!!(fromDate || toDate || sortDir !== 'DESC'));
|
|||||||
onchange={() => onapplyFilters()}
|
onchange={() => onapplyFilters()}
|
||||||
placeholder={conv_strip_from_placeholder()}
|
placeholder={conv_strip_from_placeholder()}
|
||||||
aria-label="Von"
|
aria-label="Von"
|
||||||
class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border px-1 text-xs focus:outline-none sm:min-h-0"
|
class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border-[1.5px] bg-surface px-1 text-[8px] text-ink focus:outline-none sm:min-h-0"
|
||||||
class:border-[#002850]={!!fromDate}
|
class:border-primary={!!fromDate}
|
||||||
class:text-[#333]={!!fromDate}
|
class:border-line={!fromDate}
|
||||||
class:border-[#D1D5DB]={!fromDate}
|
|
||||||
class:text-[#AAA]={!fromDate}
|
|
||||||
class:italic={!fromDate}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<span class="text-xs text-[#AAA]">–</span>
|
<span class="text-xs text-ink-3">–</span>
|
||||||
|
|
||||||
<!-- To date -->
|
<!-- To date -->
|
||||||
<input
|
<input
|
||||||
@@ -67,20 +64,17 @@ let isActive = $derived(!!(fromDate || toDate || sortDir !== 'DESC'));
|
|||||||
onchange={() => onapplyFilters()}
|
onchange={() => onapplyFilters()}
|
||||||
placeholder={conv_strip_to_placeholder()}
|
placeholder={conv_strip_to_placeholder()}
|
||||||
aria-label="Bis"
|
aria-label="Bis"
|
||||||
class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border px-1 text-xs focus:outline-none sm:min-h-0"
|
class="h-[22px] min-h-[44px] w-[80px] rounded-[3px] border-[1.5px] bg-surface px-1 text-[8px] text-ink focus:outline-none sm:min-h-0"
|
||||||
class:border-[#002850]={!!toDate}
|
class:border-primary={!!toDate}
|
||||||
class:text-[#333]={!!toDate}
|
class:border-line={!toDate}
|
||||||
class:border-[#D1D5DB]={!toDate}
|
|
||||||
class:text-[#AAA]={!toDate}
|
|
||||||
class:italic={!toDate}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Document count -->
|
<!-- Document count -->
|
||||||
<span
|
<span
|
||||||
data-testid="conv-strip-count"
|
data-testid="conv-strip-count"
|
||||||
class="ml-auto text-xs font-bold"
|
class="ml-auto text-[8px] font-bold"
|
||||||
class:text-[#002850]={hasDateFilter}
|
class:text-primary={hasDateFilter}
|
||||||
class:text-[#888]={!hasDateFilter}
|
class:text-ink-3={!hasDateFilter}
|
||||||
>
|
>
|
||||||
{conv_letters_count({ count: documentCount ?? 0 })}
|
{conv_letters_count({ count: documentCount ?? 0 })}
|
||||||
</span>
|
</span>
|
||||||
@@ -92,11 +86,11 @@ let isActive = $derived(!!(fromDate || toDate || sortDir !== 'DESC'));
|
|||||||
aria-label="Sortierung umkehren"
|
aria-label="Sortierung umkehren"
|
||||||
aria-pressed={sortDir === 'ASC'}
|
aria-pressed={sortDir === 'ASC'}
|
||||||
onclick={ontoggleSort}
|
onclick={ontoggleSort}
|
||||||
class="flex h-[22px] min-h-[44px] items-center gap-1 rounded-[3px] border px-2 text-xs font-bold sm:min-h-0"
|
class="flex h-[22px] min-h-[44px] items-center gap-1 rounded-[3px] border-[1.5px] px-2 text-[8px] font-bold sm:min-h-0"
|
||||||
class:border-[#002850]={isActive}
|
class:border-primary={isActive}
|
||||||
class:text-[#002850]={isActive}
|
class:text-primary={isActive}
|
||||||
class:border-[#D1D5DB]={!isActive}
|
class:border-line={!isActive}
|
||||||
class:text-[#888]={!isActive}
|
class:text-ink-3={!isActive}
|
||||||
>
|
>
|
||||||
{#if sortDir === 'ASC'}
|
{#if sortDir === 'ASC'}
|
||||||
{conv_strip_sort_oldest()}
|
{conv_strip_sort_oldest()}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function handleSuggestionSelect(id: string) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex items-end gap-[9px] border-b border-[#EAE7E0] bg-white px-4 py-[9px] sm:px-[18px]">
|
<div class="flex items-end gap-[9px] border-b border-line bg-surface px-4 py-[9px] sm:px-[18px]">
|
||||||
<!-- Person A -->
|
<!-- Person A -->
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<PersonTypeahead
|
<PersonTypeahead
|
||||||
@@ -43,6 +43,7 @@ function handleSuggestionSelect(id: string) {
|
|||||||
label="Person"
|
label="Person"
|
||||||
bind:value={senderId}
|
bind:value={senderId}
|
||||||
initialName={initialSenderName}
|
initialName={initialSenderName}
|
||||||
|
compact={true}
|
||||||
restrictToCorrespondentsOf={receiverId || undefined}
|
restrictToCorrespondentsOf={receiverId || undefined}
|
||||||
onchange={() => onapplyFilters()}
|
onchange={() => onapplyFilters()}
|
||||||
/>
|
/>
|
||||||
@@ -54,7 +55,8 @@ function handleSuggestionSelect(id: string) {
|
|||||||
type="button"
|
type="button"
|
||||||
aria-label="Personen tauschen"
|
aria-label="Personen tauschen"
|
||||||
onclick={onswapPersons}
|
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="mb-[1px] flex h-[30px] w-[30px] shrink-0 items-center justify-center rounded-[3px] border border-line bg-surface text-ink-3 transition-colors hover:border-primary hover:text-primary"
|
||||||
|
class:opacity-0={!swapVisible}
|
||||||
class:pointer-events-none={!swapVisible}
|
class:pointer-events-none={!swapVisible}
|
||||||
tabindex={swapVisible ? 0 : -1}
|
tabindex={swapVisible ? 0 : -1}
|
||||||
>
|
>
|
||||||
@@ -80,13 +82,14 @@ function handleSuggestionSelect(id: string) {
|
|||||||
class="relative min-w-0 flex-1"
|
class="relative min-w-0 flex-1"
|
||||||
class:[&_input]:border-dashed={!receiverId}
|
class:[&_input]:border-dashed={!receiverId}
|
||||||
class:[&_input]:border-solid={!!receiverId}
|
class:[&_input]:border-solid={!!receiverId}
|
||||||
class:[&_input]:bg-[#F9F8F6]={!receiverId}
|
class:[&_input]:bg-canvas={!receiverId}
|
||||||
>
|
>
|
||||||
<PersonTypeahead
|
<PersonTypeahead
|
||||||
name="receiverId"
|
name="receiverId"
|
||||||
label={receiverId ? 'Korrespondent' : 'Korrespondent — optional'}
|
label={receiverId ? 'Korrespondent' : 'Korrespondent — optional'}
|
||||||
bind:value={receiverId}
|
bind:value={receiverId}
|
||||||
initialName={initialReceiverName}
|
initialName={initialReceiverName}
|
||||||
|
compact={true}
|
||||||
placeholder="Alle Korrespondenten"
|
placeholder="Alle Korrespondenten"
|
||||||
restrictToCorrespondentsOf={senderId || undefined}
|
restrictToCorrespondentsOf={senderId || undefined}
|
||||||
onchange={() => {
|
onchange={() => {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const makeDoc = (overrides: Record<string, unknown> = {}) => ({
|
|||||||
status: 'UPLOADED' as const,
|
status: 'UPLOADED' as const,
|
||||||
documentDate: '1923-04-12',
|
documentDate: '1923-04-12',
|
||||||
location: 'Berlin',
|
location: 'Berlin',
|
||||||
|
metadataComplete: false,
|
||||||
sender: { id: 'p1', firstName: 'Hans', lastName: 'Müller' },
|
sender: { id: 'p1', firstName: 'Hans', lastName: 'Müller' },
|
||||||
receivers: [{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt' }],
|
receivers: [{ id: 'p2', firstName: 'Anna', lastName: 'Schmidt' }],
|
||||||
tags: [],
|
tags: [],
|
||||||
|
|||||||
Reference in New Issue
Block a user