feat: Social-Bild-Modal mit QR-Code für Kalender-Termine
Single Button öffnet Vorschau-Modal mit beiden Formaten side-by-side. Pro Format Download-Button. ESC + Click-outside schließen. Endpoint generiert zusätzlich QR-Code (qrcode → PNG-Buffer), der direkt auf den Termin im Kalender-Grid verweist (/kalender/#event-<slug>). Pin-Icon, QR und Layout für OG (1200x630) und Square (1080x1080). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -446,6 +446,16 @@
|
||||
let copyToastKey = $state<string | null>(null);
|
||||
let modalImage = $state<{ src: string; alt: string } | null>(null);
|
||||
let linkedSlug = $state<string | null>(null);
|
||||
let socialModal = $state<{ slug: string; title: string } | null>(null);
|
||||
|
||||
function openSocial(item: EventCardItem) {
|
||||
if (!item._slug) return;
|
||||
socialModal = { slug: item._slug, title: item.title || "Termin" };
|
||||
}
|
||||
|
||||
function closeSocial() {
|
||||
socialModal = null;
|
||||
}
|
||||
|
||||
function eventId(item: EventCardItem): string {
|
||||
if (item._slug) return `event-${item._slug}`;
|
||||
@@ -887,34 +897,20 @@
|
||||
</button>
|
||||
{/if}
|
||||
{#if item._slug}
|
||||
<a
|
||||
href={`/api/social/calendar/${item._slug}?format=og`}
|
||||
download={`termin-${item._slug}-og.png`}
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => openSocial(item)}
|
||||
class="btn-outline btn-sm group"
|
||||
aria-label="Social-Bild (Quer 1200×630)"
|
||||
title="Social-Bild Quer (1200×630)"
|
||||
aria-label="Social-Bild als Vorschau öffnen"
|
||||
title="Social-Bild Vorschau"
|
||||
>
|
||||
<Icon
|
||||
icon="mdi:image-outline"
|
||||
class="size-3.5 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="whitespace-nowrap">Bild quer</span>
|
||||
</a>
|
||||
<a
|
||||
href={`/api/social/calendar/${item._slug}?format=square`}
|
||||
download={`termin-${item._slug}-square.png`}
|
||||
class="btn-outline btn-sm group"
|
||||
aria-label="Social-Bild (Quadrat 1080×1080)"
|
||||
title="Social-Bild Quadrat (1080×1080)"
|
||||
>
|
||||
<Icon
|
||||
icon="mdi:crop-square"
|
||||
class="size-3.5 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="whitespace-nowrap">Bild quadr.</span>
|
||||
</a>
|
||||
<span class="whitespace-nowrap">Social-Bild</span>
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
@@ -1326,6 +1322,82 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if socialModal}
|
||||
{@const ogUrl = `/api/social/calendar/${socialModal.slug}?format=og`}
|
||||
{@const sqUrl = `/api/social/calendar/${socialModal.slug}?format=square`}
|
||||
<div
|
||||
class="fixed inset-0 z-[100] flex items-center justify-center bg-black/80 p-4"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Social-Bild-Vorschau"
|
||||
onclick={closeSocial}
|
||||
onkeydown={(e) => { if (e.key === 'Escape') closeSocial(); }}
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="relative max-h-[92vh] w-full max-w-4xl overflow-y-auto rounded-lg bg-white p-5 shadow-2xl"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<div class="mb-4 flex items-start justify-between gap-3">
|
||||
<div class="min-w-0">
|
||||
<p class="text-xs uppercase tracking-wider text-stein-500">Social-Bild</p>
|
||||
<p class="truncate text-sm font-semibold text-stein-800">{socialModal.title}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={closeSocial}
|
||||
class="shrink-0 text-stein-400 hover:text-stein-700"
|
||||
aria-label="Schließen"
|
||||
>
|
||||
<Icon icon="mdi:close" class="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-xs font-medium text-stein-600">Quer · 1200 × 630</p>
|
||||
<img
|
||||
src={ogUrl}
|
||||
alt="Social-Bild Quer"
|
||||
class="w-full rounded-sm border border-stein-200 bg-stein-50"
|
||||
loading="eager"
|
||||
/>
|
||||
<a
|
||||
href={ogUrl}
|
||||
download={`termin-${socialModal.slug}-og.png`}
|
||||
class="btn-outline btn-sm justify-center no-underline!"
|
||||
>
|
||||
<Icon icon="mdi:download" class="size-3.5" />
|
||||
Quer herunterladen
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-xs font-medium text-stein-600">Quadrat · 1080 × 1080</p>
|
||||
<img
|
||||
src={sqUrl}
|
||||
alt="Social-Bild Quadrat"
|
||||
class="mx-auto w-full max-w-[300px] rounded-sm border border-stein-200 bg-stein-50 sm:max-w-none"
|
||||
loading="eager"
|
||||
/>
|
||||
<a
|
||||
href={sqUrl}
|
||||
download={`termin-${socialModal.slug}-square.png`}
|
||||
class="btn-outline btn-sm justify-center no-underline!"
|
||||
>
|
||||
<Icon icon="mdi:download" class="size-3.5" />
|
||||
Quadrat herunterladen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-4 text-[11px] text-stein-400">
|
||||
Die Bilder werden automatisch generiert. Für Posts auf Instagram, Facebook, WhatsApp oder als Hintergrund-Grafik.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
/* Heute-Markierung im Kalendergrid: dezenter Rand + leichtes Glow.
|
||||
Ergänzt das Event-Badge, damit auch leere Tage als "Heute"
|
||||
|
||||
Reference in New Issue
Block a user