Keeps the current card-based layout. Applies three targeted changes to reduce friction: a required-fields progress bar above the form, required fields moved to the first row within each card, and a proper no-PDF upload state in the left panel.
Both cards keep their existing structure. Fields are reordered so a user can fill the essentials top-to-bottom without skipping around. Optional fields still live in the same card — they're just pushed below a thin divider.
<div> elements inside the existing grid-cols-2.$derived value from existing bindable state.Row 1 is now entirely required. A user who fills Date + Sender and moves on has completed all mandatory who/when data.
Title stays first. Tags move up to row 2 (more useful than archive location during enrichment). Archive Location drops below the "Optional" divider — it's an administrative field, not enrichment work.
The familiar split-pane layout with the reorganized form. Required-fields bar shows 2 of 3 filled; the one missing required field (Sender) is visible immediately at the top of the first card.
autofocus or a Svelte $effect that targets the first empty required input. No user action needed to know where to start.When a document has no file yet (status PLACEHOLDER from Excel import), the left panel shows the same dark background but with a centered upload zone. The original filename is shown if known. Drag-and-drop is supported; clicking the CTA opens the file picker. Once a file is selected it uploads and the panel transitions to the normal PDF viewer.
doc.originalFilename is always populated. Showing it in the upload zone reassures the user they're uploading the right file, and in the top bar title it gives context while the form is empty.| Element | File | Change | Tailwind / Code |
|---|---|---|---|
| WhoWhenSection field order | WhoWhenSection.svelte |
Reorder the four <div> children of the grid-cols-2 container: Date → Sender → Receivers → Location |
No class changes. Grid order is source order. |
| DescriptionSection field order | DescriptionSection.svelte |
Move documentLocation field to last. Move Tags before Summary. |
No class changes to existing fields. |
| Optional divider inside DescriptionSection | DescriptionSection.svelte |
Add divider element before documentLocation field. |
<div class="flex items-center gap-2 my-3"><div class="flex-1 border-t border-line"></div><span class="text-[9px] font-bold uppercase tracking-widest text-ink-3">Optional</span><div class="flex-1 border-t border-line"></div></div> |
| Required-fields progress bar | enrich/[id]/+page.svelte |
Add strip between .enrich-bar and the split pane. Derive count from bindable state already in scope. |
Strip: flex items-center gap-3 border-b border-line bg-surface px-6 py-1.5. Track: h-0.5 flex-1 rounded-full bg-line. Fill: h-full rounded-full bg-brand-navy transition-all duration-300 with style="width:{pct}%". |
| Required fields derivation | enrich/[id]/+page.svelte |
Derive from existing state variables, no new props needed. | const requiredFilled = $derived([doc.title || titleValue, dateIso, senderId].filter(Boolean).length); — 3 total required fields in enrich mode. |
| Auto-focus first empty required field | WhoWhenSection.svelte |
Add autofocus on the Date input when initialDateIso is empty; on the Sender PersonTypeahead otherwise. |
{#if !initialDateIso}<input ... autofocus />{:else}<PersonTypeahead ... autofocus />{/if} |
| No-PDF upload zone | enrich/[id]/+page.svelte (new conditional block) |
Conditionally render upload zone in the left panel when !doc.filePath. |
Zone: flex-1 flex items-center justify-center bg-[#4A4846]. Inner: border border-dashed border-white/20 rounded-sm p-8 flex flex-col items-center gap-3 text-center. |
| Upload zone drag-and-drop | enrich/[id]/+page.svelte |
Add ondragover / ondrop to zone element. On drop, trigger same upload action as the file input. |
ondragover={(e) => { e.preventDefault(); isDragging = true; }} + ondrop={(e) => { e.preventDefault(); handleFile(e.dataTransfer?.files[0]); }}. Dragging state: border-brand-mint bg-mint/5 transition. |
| Upload zone — original filename | enrich/[id]/+page.svelte |
Show doc.originalFilename inside the zone as a label. Always available from the load function. |
<p class="text-xs font-medium text-white/50 truncate max-w-[200px]">{doc.originalFilename}</p> |
| Uploading / progress state | enrich/[id]/+page.svelte |
Use existing FileLoader hook's isLoading state. Show indeterminate progress bar when loading. |
Progress track: w-full h-0.5 bg-white/10 rounded-full overflow-hidden. Fill: h-full bg-brand-mint/70 animate-[slide_1.4s_ease-in-out_infinite]. |
| Replace file button (edit mode) | FileSectionEdit.svelte |
Move "Datei ersetzen" from the card in the form scroll to a ghost button in the PDF toolbar. Toolbar is visible in both states. | Button: ml-auto text-[10px] font-bold uppercase tracking-widest text-white/40 hover:text-white/70 transition-colors. Label: "Datei ersetzen". Hidden input triggers file picker. |