feat(frontend): reorder WhoWhenSection grid, expose dateIso bindable, add autofocus
Required fields (Datum, Absender) move to row 1; optional fields (Empfänger, Ort) to row 2. dateIso is now bindable for the progress bar. Autofocus lands on the first empty required field on page load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ interface Person {
|
||||
let {
|
||||
senderId = $bindable(''),
|
||||
selectedReceivers = $bindable<Person[]>([]),
|
||||
dateIso = $bindable(''),
|
||||
initialDateIso = '',
|
||||
initialLocation = '',
|
||||
initialSenderName = '',
|
||||
@@ -22,6 +23,7 @@ let {
|
||||
}: {
|
||||
senderId?: string;
|
||||
selectedReceivers?: Person[];
|
||||
dateIso?: string;
|
||||
initialDateIso?: string;
|
||||
initialLocation?: string;
|
||||
initialSenderName?: string;
|
||||
@@ -30,7 +32,7 @@ let {
|
||||
} = $props();
|
||||
|
||||
let dateDisplay = $state(untrack(() => isoToGerman(initialDateIso)));
|
||||
let dateIso = $state(untrack(() => initialDateIso));
|
||||
dateIso = untrack(() => initialDateIso);
|
||||
let dateDirty = $state(false);
|
||||
|
||||
const dateInvalid = $derived(dateDirty && dateDisplay.length > 0 && dateIso === '');
|
||||
@@ -57,7 +59,7 @@ $effect(() => {
|
||||
</h2>
|
||||
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2">
|
||||
<!-- Datum -->
|
||||
<!-- Datum (required — row 1, col 1) -->
|
||||
<div>
|
||||
<label for="documentDate" class="mb-1 block text-sm font-medium text-ink-2"
|
||||
>{m.form_label_date()}</label
|
||||
@@ -70,6 +72,7 @@ $effect(() => {
|
||||
oninput={handleDateInput}
|
||||
placeholder={m.form_placeholder_date()}
|
||||
maxlength="10"
|
||||
autofocus={!initialDateIso}
|
||||
class="block w-full rounded border border-line p-2 text-sm shadow-sm
|
||||
{dateInvalid ? 'border-red-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500' : 'focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring'}"
|
||||
aria-describedby={dateInvalid ? 'date-error' : undefined}
|
||||
@@ -80,7 +83,25 @@ $effect(() => {
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Ort -->
|
||||
<!-- Absender (required — row 1, col 2) -->
|
||||
<div>
|
||||
<PersonTypeahead
|
||||
name="senderId"
|
||||
label={m.form_label_sender()}
|
||||
bind:value={senderId}
|
||||
initialName={initialSenderName}
|
||||
suggestedName={suggestedSenderName}
|
||||
autofocus={!!initialDateIso}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Empfänger (optional — row 2, col 1) -->
|
||||
<div>
|
||||
<p class="mb-1 block text-sm font-medium text-ink-2">{m.form_label_receivers()}</p>
|
||||
<PersonMultiSelect bind:selectedPersons={selectedReceivers} />
|
||||
</div>
|
||||
|
||||
<!-- Ort (optional — row 2, col 2) -->
|
||||
<div>
|
||||
<label for="location" class="mb-1 block text-sm font-medium text-ink-2"
|
||||
>{m.form_label_location()}</label
|
||||
@@ -94,22 +115,5 @@ $effect(() => {
|
||||
class="block w-full rounded border border-line p-2 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Absender -->
|
||||
<div>
|
||||
<PersonTypeahead
|
||||
name="senderId"
|
||||
label={m.form_label_sender()}
|
||||
bind:value={senderId}
|
||||
initialName={initialSenderName}
|
||||
suggestedName={suggestedSenderName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Empfänger -->
|
||||
<div>
|
||||
<p class="mb-1 block text-sm font-medium text-ink-2">{m.form_label_receivers()}</p>
|
||||
<PersonMultiSelect bind:selectedPersons={selectedReceivers} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user