Skip-first-run $effect tracks selectedPersons array length; any add/remove
after mount marks the editor dirty so the unsaved-warning fires on nav.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
JourneyEditor now renders UnsavedWarningBanner when showUnsavedWarning
is true. save() wraps onSubmit in try/catch so clearOnSuccess only fires
on success. edit/+page.svelte handleSubmit throws instead of returning
on non-ok responses so JourneyEditor sees the failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses the remaining #792 review blockers and concerns in the journey
editor cluster:
- Interlude rows show 'Zwischentext' (dedicated key), not the add-button text
- All four mutation handlers route the backend ErrorCode through
getErrorMessage (a 409 duplicate no longer says 'bitte Seite neu laden')
and console.error their failures so client-side errors leave a trace
- Remove implements the spec'd pending state: row stays dimmed with an
aria-live 'wird entfernt…' until the DELETE resolves; failure keeps the row
- Move announcements fire after the reorder resolves (no false 'verschoben')
- Touch targets ≥44px (remove ×, note links, create submit); focus moves to
the new row after add, to a sensible neighbor after remove, back to × on
confirm-cancel; drag handle is pointer-only; title/intro get aria-labels;
publish-disabled reason is a visible hint, not a title tooltip
- Amber warning styles use new --color-warning-* tokens with dark remaps
- Blocked interlude-clear restores the draft instead of showing phantom text
- useBlockDragDrop moves to $lib/shared/hooks — geschichte no longer imports
another domain's internals
- Test hardening: reorder-failure rollback (non-ok + reject), publish/
unpublish/empty-warning surface, destructive confirm path, maxlength
assertions, JourneyCreate failure path, edit-page STORY/JOURNEY branch,
fixture factory, m.* assertions, all fixed sleeps replaced with polling
67 component tests green across 6 spec files; transcription consumer of the
moved hook re-verified (30 green).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JourneyEditor fed GeschichteView.PersonView (no displayName) straight into
the displayName-rendering PersonMultiSelect, so every chip on a journey was
empty. The name mapping both editors need now lives once in
$lib/person/personOption.ts (with the [Unbekannt] fallback matching
GeschichteService.toView), and PersonMultiSelect/GeschichteSidebar import
the narrow PersonOption contract from there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DocumentPickerDropdown and DocumentMultiSelect had identical createTypeahead
configs, fetch logic, and formatDocLabel helpers. Extracted to
documentTypeahead.ts; all four consumers import from the shared module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
null ?? undefined evaluated to undefined, causing JSON.stringify to omit
the key entirely — the backend treated an absent note field as a no-op,
so clearing a note never persisted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NVDA+Chrome and VoiceOver+Safari can re-announce a persistent non-empty
aria-live region when adjacent DOM mutations occur. Clearing with a
500ms delay gives the announcement time to fire once before going quiet.
The two svelte-ignore a11y_no_static_element_interactions suppressions are
given preceding comments explaining the keyboard accessibility contract so
they are not mistaken for unaddressed tech debt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously the item list area was blank when no items had been added.
The empty-state paragraph uses the existing journey_empty_state i18n key.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The screen-reader live announcement was calling m.journey_item_moved()
without the required {position, total, newPosition} parameters, which
the i18n template uses to build the full announcement string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Main editing surface for JOURNEY-type Geschichten. Manages sorted item list
with optimistic add/remove/reorder (rollback on failure), drag-and-drop reorder
via createBlockDragDrop, intro textarea, and sidebar via GeschichteSidebar.
Publish requires at least one item + non-empty title.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>