[Mappe·Page] Dokument-Bearbeiten — edit / new / bulk-edit split-pane (/documents/[id]/edit, /new, /bulk-edit) #865

Open
opened 2026-06-16 10:55:36 +02:00 by marcel · 0 comments
Owner

Page alignment. Part of #853. Prototype: prototypes/Dokument-Bearbeiten.dc.html.

Current gaps (audit)

  • Delete/Cancel/Mark-for-review buttons use raw red-*/gray-*; progress bar uses bg-brand-navy (won't flip dark) → bg-primary; UploadZone hardcodes a dark palette + all eight German user-facing strings are not in Paraglide (see i18n section below); field-label casing inconsistent (font-medium vs font-bold); sub-44px targets; mixed focus rings.

Scope (routes/documents/[id]/edit/+page.svelte, routes/documents/new/+page.svelte, routes/documents/bulk-edit/+page.svelte, lib/document/DocumentEditLayout.svelte, BulkDocumentEditLayout.svelte, UploadZone.svelte)

  • Button tiers per _AUTHORING_KIT §6 (Löschen danger / Abbrechen + Zur Überprüfung secondary / Speichern primary); Card for form sections; progress strip bg-primary.
  • UploadZone: token colors + i18n all user-facing strings (see §i18n below); empty dropzone matches the prototype's single-line layout (see §Empty dropzone copy).
  • Standardize field labels (Montserrat 700 UPPERCASE) + ring-focus-ring.
  • Shared primitives (Card #858, SegmentedControl #857, PageHeader #856) must be imported from $lib/shared/ — do not re-implement inside $lib/document/ while waiting on dependencies.

i18n — UploadZone strings (all 8)

The previous scope named only the two validation strings. All eight user-facing strings in UploadZone.svelte must move to Paraglide — hardcoded German aria-labels are an a11y defect, not cosmetic:

Location Hardcoded string Paraglide key
:28 "Dateityp wird nicht unterstützt" m.error_unsupported_file_type() (key exists)
:32 "Datei ist zu groß" m.error_file_too_large() (key exists)
:53 aria-label="Dateiupload-Bereich" new key upload_zone_label
:53 "Datei wird hochgeladen" (role="status") new key upload_zone_uploading
:63 "Wird hochgeladen …" new key upload_zone_progress_label
:69 "Abbrechen" new key upload_zone_cancel
:74 aria-label="Datei ablegen" new key upload_zone_drop_label
:101 "Noch keine Datei hochgeladen" replaced by prototype copy (see §Empty dropzone copy)
:108–109 aria-label="Datei auswählen" / "Datei auswählen" new keys upload_zone_select_label / upload_zone_select
:112 "oder Datei hier ablegen" replaced by prototype copy (see §Empty dropzone copy)

Add all new keys to messages/{de,en,es}.json. Keys that already exist (error_unsupported_file_type, error_file_too_large) are a wiring change only — no four-site add needed for those two.

Empty dropzone copy

Decided: adopt the prototype's single-line layout (not the current three-line layout).

The prototype (Dokument-Bearbeiten.dc.html:79–80) shows a 34 px upload icon plus a single line "Dateien hier ablegen oder klicken". The current component shows three separate lines ("Noch keine Datei hochgeladen" / "Datei auswählen" / "oder Datei hier ablegen"). The reskin must match the prototype: one line, icon above. This is a copy and layout change, not only a color change.

Responsive stacking (320 px)

Decided: at the mobile breakpoint, the panes stack — dropzone/preview above form — and the action bar remains reachable without horizontal scrolling. This is the Critical path for the senior-phone reader audience.

Dark-mode icon

Decided: use a currentColor-driven token for the upload icon, not the filter:invert(1) brightness(1.6) approach seen in Dokument-Bearbeiten.dc.html:17. Filter inversion is the dark-mode anti-pattern — a text-ink-2 or text-primary colored SVG flips cleanly with the theme.

Security note (implementer)

Two guardrails that must not regress during the reskin:

  1. No {@html} anywhere in the reskin, including prototype-matched icon/markup. All user-visible strings render through {...} escaping or Paraglide.
  2. Keep all four mutating form-actions as server use:enhance (?/save, ?/delete, ?/markForReview, file upload). Do not convert any to a client fetch while restyling the trigger buttons — that would bypass the SSR auth-cookie path (CWE-352-adjacent).

TDD seam

The one logic-bearing change is the UploadZone validation strings → Paraglide. Write a failing *.svelte.spec.ts render test asserting the component outputs m.error_unsupported_file_type() (not the German literal), then go green by removing the hardcoded string at :28. That is the red/green gate for the entire i18n move.

Verification

Proofshot all three route variants (/edit, /new, /bulk-edit) at 320 / 768 / 1440 px in both light and dark themes. axe-core must pass both themes.

Acceptance

  • All three routes match prototypes/Dokument-Bearbeiten.dc.html variants — proofshot at 320 / 768 / 1440 px in light and dark; axe-core passes both themes; ≥4.5:1 contrast; focus-visible preserved
  • All eight UploadZone user-facing strings via Paraglide (incl. all aria-labels); empty dropzone shows the prototype's single-line copy with 34 px icon
  • 44 px touch targets everywhere; tokens only (no raw red-*/gray-*/white/* palette classes)
  • Consistent button tiers per _AUTHORING_KIT §6 + Montserrat 700 UPPERCASE field labels + ring-focus-ring
  • Upload-progress strip keeps aria-live="polite" / role="status" after token swap
  • UploadZone render test: m.error_unsupported_file_type() output, not German literal
  • Shared primitives imported from $lib/shared/ (eslint boundaries-clean); not re-implemented in $lib/document/
  • Mobile breakpoint: panes stack (preview/dropzone above form), action bar reachable; upload icon uses currentColor token, not filter:invert

Out of Scope

  • No change to form-action behavior, validation thresholds (50 MB / PDF-JPG-PNG-TIFF), or save/delete/mark-for-review contracts
  • No backend changes, no Flyway migration, no new environment variables, no CI workflow changes
  • Admin, OCR, and Briefwechsel routes — phase-2 per epic #853
  • No rewiring of consumers outside the documents domain

Depends on: #854 tokens · #856 PageHeader (compact) · #857 SegmentedControl · #858 Card.

**Page alignment.** Part of #853. **Prototype:** `prototypes/Dokument-Bearbeiten.dc.html`. ## Current gaps (audit) - Delete/Cancel/Mark-for-review buttons use raw `red-*`/`gray-*`; progress bar uses `bg-brand-navy` (won't flip dark) → `bg-primary`; `UploadZone` hardcodes a dark palette + **all eight German user-facing strings are not in Paraglide** (see i18n section below); field-label casing inconsistent (`font-medium` vs `font-bold`); sub-44px targets; mixed focus rings. ## Scope (`routes/documents/[id]/edit/+page.svelte`, `routes/documents/new/+page.svelte`, `routes/documents/bulk-edit/+page.svelte`, `lib/document/DocumentEditLayout.svelte`, `BulkDocumentEditLayout.svelte`, `UploadZone.svelte`) - Button tiers per `_AUTHORING_KIT §6` (Löschen danger / Abbrechen + Zur Überprüfung secondary / Speichern primary); `Card` for form sections; progress strip `bg-primary`. - `UploadZone`: token colors + i18n **all** user-facing strings (see §i18n below); empty dropzone matches the prototype's single-line layout (see §Empty dropzone copy). - Standardize field labels (Montserrat 700 UPPERCASE) + `ring-focus-ring`. - Shared primitives (`Card` #858, `SegmentedControl` #857, `PageHeader` #856) must be imported from `$lib/shared/` — do not re-implement inside `$lib/document/` while waiting on dependencies. ## i18n — UploadZone strings (all 8) The previous scope named only the two validation strings. **All eight** user-facing strings in `UploadZone.svelte` must move to Paraglide — hardcoded German `aria-label`s are an a11y defect, not cosmetic: | Location | Hardcoded string | Paraglide key | |---|---|---| | :28 | `"Dateityp wird nicht unterstützt"` | `m.error_unsupported_file_type()` (key exists) | | :32 | `"Datei ist zu groß"` | `m.error_file_too_large()` (key exists) | | :53 | `aria-label="Dateiupload-Bereich"` | new key `upload_zone_label` | | :53 | `"Datei wird hochgeladen"` (`role="status"`) | new key `upload_zone_uploading` | | :63 | `"Wird hochgeladen …"` | new key `upload_zone_progress_label` | | :69 | `"Abbrechen"` | new key `upload_zone_cancel` | | :74 | `aria-label="Datei ablegen"` | new key `upload_zone_drop_label` | | :101 | `"Noch keine Datei hochgeladen"` | replaced by prototype copy (see §Empty dropzone copy) | | :108–109 | `aria-label="Datei auswählen"` / `"Datei auswählen"` | new keys `upload_zone_select_label` / `upload_zone_select` | | :112 | `"oder Datei hier ablegen"` | replaced by prototype copy (see §Empty dropzone copy) | Add all new keys to `messages/{de,en,es}.json`. Keys that already exist (`error_unsupported_file_type`, `error_file_too_large`) are a wiring change only — no four-site add needed for those two. ## Empty dropzone copy **Decided:** adopt the prototype's single-line layout (not the current three-line layout). The prototype (`Dokument-Bearbeiten.dc.html:79–80`) shows a 34 px upload icon plus a single line **"Dateien hier ablegen oder klicken"**. The current component shows three separate lines ("Noch keine Datei hochgeladen" / "Datei auswählen" / "oder Datei hier ablegen"). The reskin must match the prototype: one line, icon above. This is a copy and layout change, not only a color change. ## Responsive stacking (320 px) **Decided:** at the mobile breakpoint, the panes stack — dropzone/preview above form — and the action bar remains reachable without horizontal scrolling. This is the Critical path for the senior-phone reader audience. ## Dark-mode icon **Decided:** use a `currentColor`-driven token for the upload icon, not the `filter:invert(1) brightness(1.6)` approach seen in `Dokument-Bearbeiten.dc.html:17`. Filter inversion is the dark-mode anti-pattern — a `text-ink-2` or `text-primary` colored SVG flips cleanly with the theme. ## Security note (implementer) Two guardrails that must not regress during the reskin: 1. **No `{@html}`** anywhere in the reskin, including prototype-matched icon/markup. All user-visible strings render through `{...}` escaping or Paraglide. 2. **Keep all four mutating form-actions as server `use:enhance`** (`?/save`, `?/delete`, `?/markForReview`, file upload). Do not convert any to a client `fetch` while restyling the trigger buttons — that would bypass the SSR auth-cookie path (CWE-352-adjacent). ## TDD seam The one logic-bearing change is the UploadZone validation strings → Paraglide. Write a failing `*.svelte.spec.ts` render test asserting the component outputs `m.error_unsupported_file_type()` (not the German literal), then go green by removing the hardcoded string at `:28`. That is the red/green gate for the entire i18n move. ## Verification Proofshot all three route variants (`/edit`, `/new`, `/bulk-edit`) at 320 / 768 / 1440 px in both light and dark themes. axe-core must pass both themes. ## Acceptance - [ ] All three routes match `prototypes/Dokument-Bearbeiten.dc.html` variants — proofshot at 320 / 768 / 1440 px in light and dark; axe-core passes both themes; ≥4.5:1 contrast; focus-visible preserved - [ ] All eight UploadZone user-facing strings via Paraglide (incl. all `aria-label`s); empty dropzone shows the prototype's single-line copy with 34 px icon - [ ] 44 px touch targets everywhere; tokens only (no raw `red-*`/`gray-*`/`white/*` palette classes) - [ ] Consistent button tiers per `_AUTHORING_KIT §6` + Montserrat 700 UPPERCASE field labels + `ring-focus-ring` - [ ] Upload-progress strip keeps `aria-live="polite"` / `role="status"` after token swap - [ ] UploadZone render test: `m.error_unsupported_file_type()` output, not German literal - [ ] Shared primitives imported from `$lib/shared/` (eslint `boundaries`-clean); not re-implemented in `$lib/document/` - [ ] Mobile breakpoint: panes stack (preview/dropzone above form), action bar reachable; upload icon uses `currentColor` token, not `filter:invert` ## Out of Scope - No change to form-action behavior, validation thresholds (50 MB / PDF-JPG-PNG-TIFF), or save/delete/mark-for-review contracts - No backend changes, no Flyway migration, no new environment variables, no CI workflow changes - Admin, OCR, and Briefwechsel routes — phase-2 per epic #853 - No rewiring of consumers outside the `documents` domain **Depends on:** #854 tokens · #856 PageHeader (compact) · #857 SegmentedControl · #858 Card.
marcel added this to the Mappe Visual Redesign milestone 2026-06-16 10:55:36 +02:00
marcel added the P2-mediumfeatureredesign-mappeui labels 2026-06-16 11:06:28 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#865