57f4b226f9
Footer: - Newsletter 2-spaltig (Titel/Desc links, Formular rechts), Desc als Translation-Key newsletter_inline_desc - Link-Spalten-Überschriften als kleine Label-Kappen, Links ohne Unterstrich - Bottom-Bar: Logo + Site-Name (data.siteName) links, Copyright/Lizenz rechts - Site-Name-Default "Windwiderstand Thüringen" (constants.ts) OrganisationCard: - Neue Komponente auf InfoCard-Basis; InfoCard um href/media/badge/footer-Slots erweitert - OrganisationsBlock: 4 divergierende Kartenpfade → 1 OrganisationCard - Story + CTA-Button (mitmachen) size md + Icon Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
124 lines
4.3 KiB
Svelte
124 lines
4.3 KiB
Svelte
<script lang="ts">
|
|
/**
|
|
* OrganisationCard — Organisations-Kachel auf InfoCard-Basis.
|
|
* Teilt Shell/Typo/Link-Hover mit InfoCard, behält aber die Besonderheiten:
|
|
* - quadratisches Logo + Fisch-Fallback (statt rundem Icon) via media-Snippet
|
|
* - Badge oben rechts
|
|
* - Social-Chips (WhatsApp/YouTube) im footer
|
|
* - ganze Karte klickbar (org.link)
|
|
* `compact` = engere Variante (Logo links, keine Social-Chips) für dichte Grids.
|
|
*/
|
|
import Icon from "@iconify/svelte";
|
|
import "$lib/iconify-offline";
|
|
import InfoCard from "$lib/components/InfoCard.svelte";
|
|
import Badge from "$lib/components/Badge.svelte";
|
|
import RustyImage from "$lib/components/RustyImage.svelte";
|
|
import { extractCmsImageField } from "$lib/rusty-image";
|
|
import type { OrganisationEntry } from "$lib/block-types";
|
|
|
|
let {
|
|
org,
|
|
compact = false,
|
|
index = 0,
|
|
}: { org: OrganisationEntry; compact?: boolean; index?: number } = $props();
|
|
|
|
const logoField = $derived(extractCmsImageField(org.logo));
|
|
const alt = $derived(
|
|
org.logo && typeof org.logo === "object" && org.logo.description ? org.logo.description : (org.name ?? ""),
|
|
);
|
|
const badge = $derived(org.badge && typeof org.badge === "object" ? org.badge : null);
|
|
const href = $derived(
|
|
typeof org.link === "object" && org.link !== null && typeof org.link.url === "string" && org.link.url.trim() !== ""
|
|
? org.link.url.trim()
|
|
: undefined,
|
|
);
|
|
const hasSocial = $derived(!compact && (!!org.whatsapp || !!org.youtube));
|
|
const fishMaskId = $derived(`org-logo-fallback-${index}`);
|
|
</script>
|
|
|
|
{#snippet media()}
|
|
<div
|
|
class="flex shrink-0 items-center justify-center overflow-hidden rounded-sm border border-stein-100 bg-stein-100 {compact
|
|
? 'h-10 w-10'
|
|
: 'h-12 w-12'}"
|
|
>
|
|
{#if logoField}
|
|
<RustyImage
|
|
src={logoField.url}
|
|
focal={logoField.focal ?? null}
|
|
width={96}
|
|
aspect="1/1"
|
|
fit="contain"
|
|
quality={85}
|
|
{alt}
|
|
class="h-full w-full object-contain p-0.5"
|
|
loading="lazy"
|
|
/>
|
|
{:else}
|
|
<svg
|
|
class="text-stein-300 {compact ? 'h-7 w-7' : 'h-8 w-8'}"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 48 48"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<defs>
|
|
<mask id={fishMaskId}>
|
|
<g fill="none">
|
|
<path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M24 30v14" />
|
|
<path fill="#555555" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M29 23c11 5 16 14 16 14s-12 0-21-8c-9 8-21 8-21 8s5-10 16-14c0-13 5-19 5-19s5 6 5 19" />
|
|
<circle cx="24" cy="24" r="2" fill="#fff" />
|
|
</g>
|
|
</mask>
|
|
</defs>
|
|
<path fill="currentColor" d="M0 0h48v48H0z" mask={`url(#${fishMaskId})`} />
|
|
</svg>
|
|
{/if}
|
|
</div>
|
|
{/snippet}
|
|
|
|
{#snippet badgeSlot()}
|
|
<Badge color={badge?.color as never}>{badge?.label}</Badge>
|
|
{/snippet}
|
|
|
|
{#snippet footer()}
|
|
<div class="flex gap-1.5">
|
|
{#if org.whatsapp}
|
|
<a
|
|
href={org.whatsapp}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
title="WhatsApp"
|
|
onclick={(e) => e.stopPropagation()}
|
|
class="inline-flex items-center gap-1 rounded-sm border border-stein-200 bg-stein-50 px-2 py-0.5 text-[0.6rem] text-stein-600 no-underline transition-colors hover:border-green-300 hover:bg-green-50 hover:text-green-700"
|
|
>
|
|
<Icon icon="mdi:whatsapp" class="size-3 shrink-0" />
|
|
<span>WhatsApp</span>
|
|
</a>
|
|
{/if}
|
|
{#if org.youtube}
|
|
<a
|
|
href={org.youtube}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
title="YouTube"
|
|
onclick={(e) => e.stopPropagation()}
|
|
class="inline-flex items-center gap-1 rounded-sm border border-stein-200 bg-stein-50 px-2 py-0.5 text-[0.6rem] text-stein-600 no-underline transition-colors hover:border-red-300 hover:bg-red-50 hover:text-red-700"
|
|
>
|
|
<Icon icon="lucide:youtube" class="size-3 shrink-0" />
|
|
<span>YouTube</span>
|
|
</a>
|
|
{/if}
|
|
</div>
|
|
{/snippet}
|
|
|
|
<InfoCard
|
|
{href}
|
|
title={org.name ?? ""}
|
|
description={org.description}
|
|
{compact}
|
|
{media}
|
|
badge={badge?.label ? badgeSlot : undefined}
|
|
footer={hasSocial ? footer : undefined}
|
|
/>
|