feat(design-system): Storybook + Button-Atom-Vereinheitlichung + SectionHeader
Storybook (SvelteKit-Framework, Tailwind v4, MSW, Translation-Decorator): Stories für Atoms/Molecules/Organisms + alle CMS-Blocks. Button-Atom: 5 .btn-*-Varianten (primary/secondary/tertiary/outline/warning), class-Merge-Prop, href→<a>, Loading-Spinner neben Label, rounded-md/font-medium. Alle rohen .btn-*- und Hand-Style-Buttons app-weit aufs Atom migriert. SectionHeader-Molecule (kicker/number/title/subtitle/action) + Integration in 7 CMS-Blocks (post_overview, organisations, organisations_map, searchable_text, image_gallery, youtube_video_gallery, files) via neuem section_header-Schema. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* SectionHeader — zusammengesetzter Sektionskopf (Kicker + Titel + Subline + Aktion).
|
||||
* Nutzt HeadlineBlock NICHT (das bleibt CMS-Primitiv für Fließtext-Headlines);
|
||||
* dies ist das wiederverwendbare Layout-Muster für Seitensektionen.
|
||||
*
|
||||
* <SectionHeader number="03" kicker="Vor Ort" title="Beteiligte Initiativen"
|
||||
* subtitle="13 Bürgerinitiativen im Bündnis — direkt vor Ort ansprechbar."
|
||||
* actionLabel="Zum Adressbuch" actionHref="/adressbuch" />
|
||||
*/
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let {
|
||||
number = undefined,
|
||||
kicker = undefined,
|
||||
title,
|
||||
subtitle = undefined,
|
||||
actionLabel = undefined,
|
||||
actionHref = undefined,
|
||||
tag = 'h2',
|
||||
children = undefined,
|
||||
}: {
|
||||
number?: string; // z. B. "03" — tabular-nums, wald-500
|
||||
kicker?: string; // Label, uppercase — optional (CMS-Blocks liefern oft nur title)
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
actionLabel?: string;
|
||||
actionHref?: string;
|
||||
tag?: 'h1' | 'h2' | 'h3';
|
||||
children?: Snippet; // optionaler eigener Aktions-Slot rechts
|
||||
} = $props();
|
||||
|
||||
const hasAction = $derived(!!children || (!!actionLabel && !!actionHref));
|
||||
// Kicker-Zeile (Nummer · Linie · Label) nur wenn Nummer ODER Kicker gesetzt —
|
||||
// sonst dangelt die Deko-Linie allein.
|
||||
const hasKickerRow = $derived(!!number || !!kicker);
|
||||
</script>
|
||||
|
||||
<div class="flex items-end justify-between gap-6">
|
||||
<div>
|
||||
<!-- Kicker: Nummer · Linie · Label -->
|
||||
{#if hasKickerRow}
|
||||
<div class="mb-3.5 flex items-center gap-3">
|
||||
{#if number}
|
||||
<span class="text-[13px] font-semibold tabular-nums text-wald-500">{number}</span>
|
||||
{/if}
|
||||
<span class="h-px w-7 bg-wald-200"></span>
|
||||
{#if kicker}
|
||||
<span class="text-xs font-semibold uppercase tracking-[0.14em] text-stein-500">{kicker}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Titel -->
|
||||
<svelte:element this={tag} class="text-3xl font-bold tracking-[-0.02em] text-stein-800 lg:text-[34px]">
|
||||
{title}
|
||||
</svelte:element>
|
||||
|
||||
{#if subtitle}
|
||||
<p class="mt-2 text-base text-stein-500">{subtitle}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Aktion (Slot hat Vorrang, sonst Label+Href) -->
|
||||
{#if hasAction}
|
||||
<div class="whitespace-nowrap">
|
||||
{#if children}
|
||||
{@render children()}
|
||||
{:else}
|
||||
<a
|
||||
href={actionHref}
|
||||
class="inline-flex items-center gap-1.5 text-[15px] font-semibold text-himmel-500 no-underline hover:text-himmel-600"
|
||||
>
|
||||
{actionLabel}
|
||||
<svg class="size-4" viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user