feat(lesereisen): implement lesereisen
All checks were successful
CI / Unit & Component Tests (push) Successful in 4m34s
CI / OCR Service Tests (push) Successful in 27s
CI / Backend Unit Tests (push) Successful in 5m1s
CI / fail2ban Regex (push) Successful in 47s
CI / Semgrep Security Scan (push) Successful in 23s
CI / Compose Bucket Idempotency (push) Successful in 1m11s

This commit was merged in pull request #787.
This commit is contained in:
2026-06-12 14:04:02 +02:00
parent 4bcf568ed4
commit b33d0eb850
142 changed files with 11643 additions and 917 deletions

View File

@@ -0,0 +1,82 @@
<script lang="ts">
import type { components } from '$lib/generated/api';
import { m } from '$lib/paraglide/messages.js';
import PersonMultiSelect from '$lib/person/PersonMultiSelect.svelte';
import type { PersonOption } from '$lib/person/personOption';
import StoryDocumentPanel from './StoryDocumentPanel.svelte';
type JourneyItemView = components['schemas']['JourneyItemView'];
interface Props {
status: 'DRAFT' | 'PUBLISHED';
selectedPersons: PersonOption[];
/** When set, the story document panel is rendered (STORY edit only). */
geschichteId?: string;
items?: JourneyItemView[];
}
let {
status,
selectedPersons = $bindable(),
geschichteId = undefined,
items = []
}: Props = $props();
const isDraft = $derived(status === 'DRAFT');
</script>
<aside class="flex flex-col gap-6">
<!-- Status section -->
<details open class="sm:contents">
<summary
class="flex min-h-[44px] cursor-pointer items-center px-4 font-sans text-xs font-bold tracking-widest text-ink-3 uppercase sm:hidden"
>
{m.geschichte_sidebar_status()}
</summary>
<section class="rounded border border-line bg-surface p-4 shadow-sm">
<!-- hidden below sm: the <summary> already shows this label there -->
<h2
class="mb-1 hidden font-sans text-xs font-bold tracking-widest text-ink-3 uppercase sm:block"
>
{m.geschichte_sidebar_status()}
</h2>
<p class="mb-3">
<span
class="inline-flex items-center rounded px-2 py-1 font-sans text-xs font-bold tracking-widest uppercase {isDraft
? 'bg-muted text-ink-2'
: 'bg-accent-bg text-ink'}"
>
{isDraft ? m.geschichte_editor_status_draft() : m.geschichte_editor_status_published()}
</span>
</p>
<p class="font-sans text-xs text-ink-3">
{isDraft
? m.geschichte_editor_status_draft_hint()
: m.geschichte_editor_status_published_hint()}
</p>
</section>
</details>
<!-- Persons section -->
<details open class="sm:contents">
<summary
class="flex min-h-[44px] cursor-pointer items-center px-4 font-sans text-xs font-bold tracking-widest text-ink-3 uppercase sm:hidden"
>
{m.geschichte_editor_personen_heading()}
</summary>
<section class="rounded border border-line bg-surface p-4 shadow-sm">
<h2
class="mb-2 hidden font-sans text-xs font-bold tracking-widest text-ink-3 uppercase sm:block"
>
{m.geschichte_editor_personen_heading()}
</h2>
<p class="mb-3 font-sans text-xs text-ink-3">{m.geschichte_editor_personen_hint()}</p>
<PersonMultiSelect bind:selectedPersons={selectedPersons} />
</section>
</details>
<!-- Documents section — STORY edit only; journeys manage items in the editor column -->
{#if geschichteId}
<StoryDocumentPanel geschichteId={geschichteId} items={items} />
{/if}
</aside>