feat(geschichte-detail): avatar metabar + doc reference cards per spec R-2/LR-2

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>
This commit is contained in:
Marcel
2026-06-10 21:59:56 +02:00
parent 906e75ec96
commit 07ed9719e7
10 changed files with 156 additions and 112 deletions

View File

@@ -3,6 +3,7 @@ import { goto } from '$app/navigation';
import { m } from '$lib/paraglide/messages.js';
import { formatDate } from '$lib/shared/utils/date';
import { formatAuthorDisplayName } from '$lib/geschichte/utils';
import { getInitials, personAvatarColor } from '$lib/person/personFormat';
import { getConfirmService } from '$lib/shared/services/confirm.svelte';
import { csrfFetch } from '$lib/shared/cookies';
import { parseBackendError, getErrorMessage } from '$lib/shared/errors';
@@ -61,15 +62,34 @@ async function handleDelete() {
{m.journey_badge_detail()}
</span>
{/if}
<h1 id="geschichte-title" class="mb-4 font-serif text-3xl leading-tight font-bold text-ink">
<h1 id="geschichte-title" class="mb-4 font-serif text-3xl leading-tight text-ink">
{g.title}
</h1>
<div class="border-subtle mb-4 flex items-center gap-3 border-b pb-4">
<p class="font-sans text-sm text-ink-3">
{authorName}
{#if publishedAt}· {m.geschichten_published_on({ date: publishedAt })}{/if}
</p>
{#if isJourney && data.canBlogWrite}
<div class="mb-4 flex items-center gap-3 border-b border-line-2 pb-4">
{#if authorName}
<span
aria-hidden="true"
class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full font-sans text-xs font-bold text-white"
style="background-color: {personAvatarColor(g.author?.id ?? authorName)}"
>
{getInitials(authorName)}
</span>
{/if}
<div>
{#if authorName}
<p class="font-sans text-sm leading-tight font-semibold text-ink">{authorName}</p>
{/if}
{#if publishedAt}
<p class="font-sans text-xs text-ink-3">
{#if isJourney}
{m.journey_compiled_on({ date: publishedAt })}
{:else}
{m.geschichten_published_on({ date: publishedAt })}
{/if}
</p>
{/if}
</div>
{#if data.canBlogWrite}
<div class="ml-auto flex items-center gap-3">
<a
href="/geschichten/{g.id}/edit"
@@ -101,7 +121,7 @@ async function handleDelete() {
{#if isJourney}
<JourneyReader geschichte={g} />
{:else}
<StoryReader geschichte={g} canBlogWrite={data.canBlogWrite} ondelete={handleDelete} />
<StoryReader geschichte={g} />
{/if}
</article>
</div>