f77314dc49
Neue Komponenten: SectionGrid, InfoCard (tone/compact), ArrowLink, ContactFormBlock, SectionGridBlock. CMS-Blöcke section_grid + contact_form (info_card-Collection). OrganisationsBlock: presentation "grid" (SectionGrid + InfoCard-Tiles). Kontaktformular-Submit: size md + Send-Icon. Konsolidierung Tier 1: - .card-surface + Card-Atom → rounded-lg, .chip → rounded-full, Input-Atome → rounded-md - tote .btn-*-Klassen aus app.css entfernt (Atom nutzt --color-btn-*-Tokens) - hardcoded Hex → stein-Tokens (InfoCard, ContactFormBlock) - redundante rounded-sm auf card-surface-Nutzern entfernt Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
78 lines
2.8 KiB
Svelte
78 lines
2.8 KiB
Svelte
<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';
|
|
import ArrowLink from '$lib/components/ArrowLink.svelte';
|
|
|
|
let {
|
|
number = undefined,
|
|
kicker = undefined,
|
|
title = undefined,
|
|
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; // optional — z.B. Kicker-only-Header (nur "01 · DIREKTER DRAHT")
|
|
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 (\n → harter Umbruch, wie HeadlineBlock). Optional — Kicker-only-Header. -->
|
|
{#if title}
|
|
<svelte:element this={tag} class="text-3xl font-bold tracking-[-0.02em] text-stein-800 lg:text-[34px]">
|
|
{#each title.split('\n') as line, i}{#if i > 0}<br />{/if}{line}{/each}
|
|
</svelte:element>
|
|
{/if}
|
|
|
|
{#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}
|
|
<ArrowLink href={actionHref ?? "#"} label={actionLabel ?? ""} size="md" />
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
</div>
|