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>
71 lines
2.1 KiB
Svelte
71 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import { m } from '$lib/paraglide/messages.js';
|
|
import JourneyItemCard from './JourneyItemCard.svelte';
|
|
import JourneyInterlude from './JourneyInterlude.svelte';
|
|
import type { components } from '$lib/generated/api';
|
|
|
|
type GeschichteView = components['schemas']['GeschichteView'];
|
|
type JourneyItemView = components['schemas']['JourneyItemView'];
|
|
|
|
interface Props {
|
|
geschichte: GeschichteView;
|
|
canBlogWrite: boolean;
|
|
ondelete?: () => Promise<void>;
|
|
}
|
|
|
|
let { geschichte: g, canBlogWrite, ondelete }: Props = $props();
|
|
|
|
// Render intro only when body is a non-empty, non-whitespace string.
|
|
const introText = $derived(g.body?.trim() ? g.body : null);
|
|
|
|
// Omit items that have neither a document nor a non-blank note (dangling deleted-document guard).
|
|
const validItems = $derived(
|
|
g.items.filter(
|
|
(item: JourneyItemView) =>
|
|
item.document != null || (item.note != null && item.note.trim().length > 0)
|
|
)
|
|
);
|
|
</script>
|
|
|
|
{#if introText}
|
|
<!-- plaintext — do NOT use {@html} here -->
|
|
<p class="mb-8 font-serif text-base leading-relaxed text-ink-2 italic">{introText}</p>
|
|
{/if}
|
|
|
|
{#if validItems.length === 0}
|
|
<p class="font-sans text-sm text-ink-3" data-testid="journey-empty-state">
|
|
{m.journey_empty_state()}
|
|
</p>
|
|
{:else}
|
|
<ol class="flex list-none flex-col gap-4">
|
|
{#each validItems as item (item.id)}
|
|
<li>
|
|
{#if item.document != null}
|
|
<JourneyItemCard item={item} />
|
|
{:else}
|
|
<JourneyInterlude note={item.note!} />
|
|
{/if}
|
|
</li>
|
|
{/each}
|
|
</ol>
|
|
{/if}
|
|
|
|
<!-- Author actions -->
|
|
{#if canBlogWrite}
|
|
<div class="mt-10 flex items-center gap-3 border-t border-line pt-6">
|
|
<a
|
|
href="/geschichten/{g.id}/edit"
|
|
class="inline-flex h-11 items-center rounded border border-line bg-surface px-4 font-sans text-sm font-medium text-ink hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
>
|
|
{m.btn_edit()}
|
|
</a>
|
|
<button
|
|
type="button"
|
|
onclick={() => ondelete?.()}
|
|
class="inline-flex h-11 items-center rounded font-sans text-sm font-medium text-danger hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
|
|
>
|
|
{m.btn_delete()}
|
|
</button>
|
|
</div>
|
|
{/if}
|