Files
windwiderstand/src/lib/components/blocks/LinkListBlock.svelte
T
Peter Meier 7788e0370e
Deploy / verify (push) Successful in 1m13s
Deploy / deploy (push) Successful in 1m28s
feat(link-list): CMS-Feld columns (auto|single) für Spaltenlayout
single = immer untereinander, auto = breitenbasiert mehrspaltig ab >4.
Regionalplan-Generatorenliste (w1-w40) auf single.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 22:40:30 +02:00

69 lines
2.2 KiB
Svelte

<script lang="ts">
import Icon from "@iconify/svelte";
import "$lib/iconify-offline";
import { getBlockLayoutClasses } from "$lib/block-layout";
import type { LinkListBlockData } from "$lib/block-types";
type LinkEntry = {
_slug?: string;
url?: string;
linkName?: string;
icon?: string;
showText?: boolean;
newTab?: boolean;
alt?: string;
};
let { block }: { block: LinkListBlockData } = $props();
const layoutClasses = $derived(
block.layout ? getBlockLayoutClasses(block.layout) : "col-span-12 mb-4",
);
const links = $derived(((block.links ?? []) as unknown[]).filter(
(l): l is LinkEntry => typeof l === "object" && l !== null && "url" in l,
));
const iconOnlyAll = $derived(
links.length > 0 &&
links.every((l) => l.icon && l.showText === false),
);
// "single" = immer einspaltig (CMS-Override); sonst breitenbasiert mehrspaltig bei >4
const multiColumn = $derived(block.columns !== "single" && links.length > 4);
</script>
<div class="link-list {layoutClasses}" data-block="LinkList" data-block-type="link_list" data-block-slug={block._slug}>
{#if block.headline}
<h3 class="mb-3 text-sm font-semibold">{block.headline}</h3>
{/if}
<ul
class={iconOnlyAll
? "flex flex-wrap gap-3"
: multiColumn
? "grid grid-cols-[repeat(auto-fill,minmax(13rem,1fr))] gap-x-8 gap-y-1.5"
: "flex flex-col gap-1.5"}
>
{#each links as link}
{@const hasIcon = !!link.icon}
{@const showText = link.showText !== false}
{@const label = link.linkName ?? link.alt ?? link.url ?? ""}
<li>
<a
href={link.url ?? "#"}
class="inline-flex items-center gap-2 hover:opacity-80 transition-opacity"
class:underline={showText}
target={link.newTab ? "_blank" : undefined}
rel={link.newTab ? "noopener noreferrer" : undefined}
aria-label={!showText ? label : undefined}
title={!showText ? label : undefined}
>
{#if hasIcon}
<Icon icon={link.icon!} class={showText ? "size-4 shrink-0" : "size-5 shrink-0"} aria-hidden="true" />
{/if}
{#if showText}
<span>{label}</span>
{/if}
</a>
</li>
{/each}
</ul>
</div>