- JourneyItemCard: 'Brief öffnen' back to a >=44px touch target with the
height regression spec restored
- GeschichteListRow: REISE badges text-[10px] -> text-xs; drop the
hardcoded aria-label and the mobile badge's aria-hidden so phone screen
readers learn a row is a Lesereise; mobile avatar initials -> color dot
- detail page: badge text-xs, metabar Edit/Delete h-9 -> h-11, avatar
color keyed by name to match the list
- JourneyReader: dead border-subtle class -> border-line-2
- DocumentPickerDropdown: aria-controls only while the listbox exists
- JourneyAddBar: aria-expanded/aria-controls on both toggles + focus
hand-off into the revealed picker input / interlude textarea
- GeschichteSidebar: section h2s hidden below sm (summary already shows
the label there)
- JourneyCreate: bg-brand-navy -> semantic bg-primary/text-primary-fg;
title maxlength=255
- JourneyItemRow interlude: neutral frame border + left accent only,
token utilities instead of arbitrary var() syntax and inline style
Review round 3: Leonie (1-8 + round-1 leftovers), Elicit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The detail page stayed at max-w-3xl and looked narrower than every
other page. The outer container now matches the directory width
(max-w-7xl) so the sheet spans the page like Dokumente/Personen, while
an inner max-w-3xl column keeps the prose line length readable.
Refs #799
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reader interlude and the LESEREISE badge hardcoded orange-50/200/
400/700, leaving light text on a light background in dark mode. Switch
to the existing journey-tint/journey/journey-border tokens already used
by the list and editor rows.
Closes#801
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reading sheet used bg-surface (white), so the document cards inside
the article had the same background as the sheet itself. The spec's
three-level hierarchy is canvas → article panel (#FAFAF7) → white cards;
introduce --color-sheet (mode-aware) and use it on the article. Also
move JourneyItemCard from bg-white to bg-surface so dark mode remaps it,
and tint the curator annotation with bg-muted so it stands off the card.
Refs #797
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The R-2 mockup shows the article on a distinct light panel, but the
impl-ref table only specified the centered container, so the page
rendered flat on the canvas. Wrap the <article> in the standard card
pattern (BackButton stays outside on the canvas) and record the sheet
in both spec impl-ref tables so mockup and impl-ref agree.
Closes#797
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Detail header gains the author avatar with a two-line author block;
journeys say 'zusammengestellt am' instead of 'veröffentlicht am'.
Bearbeiten/Löschen move into the metabar for stories too (were at the
article bottom). StoryReader renders real document reference cards
(icon, title, date · von X an Y) instead of a placeholder link, person
chips get avatar initials, and journey items lose the doubled spacing.
Shared formatDocumentMetaLine() in geschichte/utils feeds both readers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JourneyItemCard: restructure from full-<a> to div+card with meta line
(date · von X an Y) and explicit "Brief öffnen →" link; note renders as
mint-border annotation inside the card.
JourneyInterlude: remove ❦ ornament; orange-400 left-border spec classes.
JourneyReader: fix intro classes (dashed border-b); remove bottom author
actions (moved to +page.svelte metabar).
+page.svelte geschichten/[id]: badge above title with spec orange-50 classes;
Bearbeiten/Löschen in metabar right side for isJourney + canBlogWrite.
JourneyItemRow: items-center on main row; drag handle self-center; note
textarea inline in content column (removes border-t section below).
i18n: add journey_item_open, journey_item_meta_from_to to de/en/es.
Tests: update JourneyItemCard + JourneyReader specs to match new structure;
fix datePrecision 'FULL'→'DAY', add receiverCount: 0 to all test fixtures.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds deleteError $state to [id]/+page.svelte, parses backend error via
parseBackendError/getErrorMessage on !res.ok, and displays a role=alert
paragraph. Adds two browser-tier tests: success path (goto called) and
error path (alert visible, goto not called).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves the confirm-then-delete flow out of StoryReader and JourneyReader into
the single [id]/+page.svelte owner. Both reader components gain an optional
ondelete prop — the delete button calls ondelete?.() so the handler is opt-in
and never duplicated. Tests verify the prop is called on click.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GeschichtenCard.svelte: use GeschichteSummary instead of Geschichte
(list endpoint returns summaries; no items/createdAt/updatedAt needed)
- GeschichtenCard.svelte.test.ts: factory returns GeschichteSummary with
lean author shape; drop Geschichte-only fields (createdAt, groups, etc.)
- geschichten/[id]/+page.svelte: add focus:outline-none focus-visible:ring-2
focus-visible:ring-focus-ring to journey item document links (WCAG 2.4.7)
- page.svelte.test.ts ([id]): replace stale documents[] factory field with
items[]; test now checks placeholder text + note caption
- page.svelte.test.ts (new): remove removed initialDocuments from baseData;
rename test to reflect that only initialPersons is passed through
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
item.note is editorial prose — it must not be used as the anchor label.
Always show the i18n placeholder as the link text; render note as a
caption below the link when present.
Adds TODO(#786) comment so the stub degradation is tracked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- db-orm.puml: replace geschichten_documents with journey_items, add type column to geschichten, bump schema version to V72
- l3-backend-3g-supporting.puml: update GeschichteController and GeschichteService descriptions to mention STORY/JOURNEY subtypes and JourneyItem
- geschichten/[id]/+page.svelte: replace raw UUID fallback with m.geschichten_document_link_placeholder() i18n key
- messages/{de,en,es}.json: add geschichten_document_link_placeholder translation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- api.ts: add GeschichteType, JourneyItem, GeschichteSummary schemas;
remove documentId param from list endpoint; change list response to
GeschichteSummary[]; add type + items to Geschichte; remove documents field
- GeschichteEditor: remove DocumentMultiSelect + documentIds from payload
(journey items are managed via the future Lesereisen editor, not here)
- GET /geschichten page: remove documentId filter from server load + URL logic
- geschichten/new: remove documentId pre-population from server load
- geschichten/[id]: replace g.documents with g.items (document-backed JourneyItems)
- geschichten/new + [id]/edit: remove documentIds from submit payload type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces `csrfFetch` (= `makeCsrfFetch(fetch)`) in cookies.ts as a
drop-in fetch replacement that auto-injects X-XSRF-TOKEN on POST/PUT/PATCH/DELETE.
Previously 8 call sites sent mutating requests without the CSRF header —
annotation resize, comment POST/PATCH/DELETE, Geschichte CRUD, Stammbaum
relationship creation, bulk-edit PATCH, and file upload — all would fail
with CSRF_TOKEN_MISSING if the backend's cookie-based protection triggered.
All 14 client-side mutating fetches now use csrfFetch; withCsrf/makeCsrfFetch
remain in the API for injectable-fetch use cases (e.g. useTranscriptionBlocks).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Story-detail body now uses an explicit Tailwind block-element selector
ruleset instead of the `prose` plugin, so the body fills the full max-w-3xl
parent width — previously `prose` clamped to ~65ch inside an already narrow
page.
GeschichtenCard heading and the "+ Geschichte schreiben" link now use
text-ink-2 (#4b5563 = 7.6:1 on white, AAA-passable) instead of text-ink-3
or text-ink/60. Same fix on the "+ Geschichte anhängen" link in the
Document drawer column and on the Personen / Dokumente section headers
on the story detail page.
Closes Leonie's review B1, B2 and S4 on PR #382.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- /geschichten — published-stories index with filter pills + "+ Neue Geschichte"
for BLOG_WRITERs; supports ?personId and ?documentId pre-filtering
- /geschichten/[id] — reader detail with sanitised {@html} body, person and
document chip sections, BLOG_WRITER edit/delete with confirm dialog
- /geschichten/new — editor with optional ?personId and ?documentId pre-fill
(silent ignore on unknown IDs to avoid leaking entity existence)
- /geschichten/[id]/edit — editor populated from existing story; BLOG_WRITE
guard redirects readers to the detail page
All routes load via createApiClient(fetch) with !response.ok error handling
following the project pattern; PATCH/DELETE go through raw fetch which the
Vite dev proxy / Caddy production proxy authenticates via cookie.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>