feat(headline): optionaler SectionHeader-Modus (kicker/number/action)
Deploy / verify (push) Successful in 1m28s
Deploy / deploy (push) Successful in 1m36s

HeadlineBlock rendert als SectionHeader sobald kicker oder action gesetzt ist,
sonst schlichte Text-Headline wie bisher (rückwärtskompatibel, opt-in).
SectionHeader-Titel unterstützt jetzt \n → <br>. headline-Schema extends
section_header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-07-11 23:48:23 +02:00
parent 03e84c1f28
commit b60da59c92
4 changed files with 48 additions and 8 deletions
+6
View File
@@ -45,6 +45,12 @@ export interface HeadlineBlockData {
_slug?: string; _slug?: string;
tag?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; tag?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
text?: string; text?: string;
/** SectionHeader: Label über dem Titel (uppercase). Gesetzt → Headline rendert als Sektionskopf. */
kicker?: string;
/** SectionHeader: Index vor dem Kicker, z.B. "03". */
number?: string;
/** SectionHeader: CTA-Link (aufgelöst: url, linkName). */
action?: string | { url?: string; linkName?: string; newTab?: boolean };
align?: "left" | "center" | "right"; align?: "left" | "center" | "right";
layout?: BlockLayout; layout?: BlockLayout;
} }
+2 -2
View File
@@ -51,9 +51,9 @@
</div> </div>
{/if} {/if}
<!-- Titel --> <!-- Titel (\n → harter Umbruch, wie HeadlineBlock) -->
<svelte:element this={tag} class="text-3xl font-bold tracking-[-0.02em] text-stein-800 lg:text-[34px]"> <svelte:element this={tag} class="text-3xl font-bold tracking-[-0.02em] text-stein-800 lg:text-[34px]">
{title} {#each title.split('\n') as line, i}{#if i > 0}<br />{/if}{line}{/each}
</svelte:element> </svelte:element>
{#if subtitle} {#if subtitle}
@@ -36,3 +36,15 @@ export const MitUmbruch: Story = {
}, },
}, },
}; };
// Sobald kicker/action gesetzt → Headline rendert als SectionHeader.
export const AlsSektionskopf: Story = {
args: {
block: {
tag: 'h2',
text: 'Wir sind keine Lobby,\nkeine Partei, keine NGO.',
kicker: 'Über uns',
action: { url: '/about', linkName: 'Mehr über uns' },
},
},
};
@@ -1,10 +1,21 @@
<script lang="ts"> <script lang="ts">
import { getBlockLayoutClasses } from "$lib/block-layout"; import { getBlockLayoutClasses } from "$lib/block-layout";
import SectionHeader from "$lib/components/SectionHeader.svelte";
import type { HeadlineBlockData } from "$lib/block-types"; import type { HeadlineBlockData } from "$lib/block-types";
let { block }: { block: HeadlineBlockData } = $props(); let { block }: { block: HeadlineBlockData } = $props();
const layoutClasses = $derived(getBlockLayoutClasses(block.layout)); const layoutClasses = $derived(getBlockLayoutClasses(block.layout));
// Sektionskopf-Modus: sobald kicker ODER action gesetzt ist, rendert die
// Headline als SectionHeader. Sonst schlichte Text-Headline wie bisher.
const actionRef = $derived(
block.action && typeof block.action === "object" ? block.action : null,
);
const useSection = $derived(!!block.kicker || !!actionRef);
// SectionHeader kennt nur h1h3; h4h6 → h2.
const sectionTag = $derived(
block.tag === "h1" || block.tag === "h2" || block.tag === "h3" ? block.tag : "h2",
);
const alignClass = $derived( const alignClass = $derived(
block.align === "center" block.align === "center"
? "text-center" ? "text-center"
@@ -20,10 +31,21 @@
</script> </script>
<div class={layoutClasses} data-block="Headline" data-block-type="headline" data-block-slug={block._slug}> <div class={layoutClasses} data-block="Headline" data-block-type="headline" data-block-slug={block._slug}>
{#if useSection}
<SectionHeader
number={block.number}
kicker={block.kicker}
title={block.text ?? ""}
tag={sectionTag}
actionLabel={actionRef?.linkName}
actionHref={actionRef?.url}
/>
{:else}
<svelte:element <svelte:element
this={Tag} this={Tag}
class={alignClass} class={alignClass}
> >
{#each lines as line, i}{#if i > 0}<br />{/if}{line}{/each} {#each lines as line, i}{#if i > 0}<br />{/if}{line}{/each}
</svelte:element> </svelte:element>
{/if}
</div> </div>