feat(termin): vollwertige Detailseite + QR/Detail-Link im Kalender
Deploy / verify (push) Successful in 1m15s
Deploy / deploy (push) Successful in 1m25s

/termin/<slug> ist jetzt echte Seite statt Redirect:
- alle Infos ungekürzt (Datum/Zeit in Europe/Berlin, Ort+Maps, Tags,
  Bild+Lightbox, volle Beschreibung, Anhang, externer Link)
- alle Aktionen: ICS, Google, Link kopieren, Teilen, QR, Social-Bild
- Link zum Kalender drunter (kein Auto-Redirect mehr)
- Breite via Layout-.container-custom (gleich wie andere Seiten)
- SEO: OG/Twitter/canonical zentral aus Layout (kein Doppel-Tag),
  Event-JSON-LD + Breadcrumb für Rich Results / Share-Preview

CalendarBlock: QR-Button + "Details →"-Link je Termin (→ /termin/<slug>/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-06-19 13:50:09 +02:00
parent fdc18ab5b8
commit 6925ffee45
3 changed files with 413 additions and 56 deletions
+46 -1
View File
@@ -17,6 +17,7 @@
import Icon from "@iconify/svelte";
import ImageModal from "$lib/components/ImageModal.svelte";
import SocialImageModal from "$lib/components/SocialImageModal.svelte";
import QrModal from "$lib/components/QrModal.svelte";
type EventCardItem = CalendarItemData & {
start: Date;
@@ -458,6 +459,18 @@
socialModal = null;
}
// QR-Code zum direkten Ausgeben/Scannen (Aushang, Infostand). Nutzt die
// canonical /termin/<slug>-URL (hat OG-Tags + Redirect), Fallback = Hash-
// Anchor im Kalender wenn kein Slug.
let qrModal = $state<{ value: string; label: string } | null>(null);
function openQr(item: EventCardItem) {
const url = item._slug
? `${window.location.origin}/termin/${encodeURIComponent(item._slug)}/`
: `${window.location.origin}${window.location.pathname}#${eventId(item)}`;
qrModal = { value: url, label: item.title || "Termin" };
}
function eventId(item: EventCardItem): string {
if (item._slug) return `event-${item._slug}`;
const titlePart = (item.title || "event")
@@ -781,8 +794,21 @@
<!-- Aktionen: Primary-Reihe (Info/Karte/Anhang) + kompakte Action-Toolbar -->
<div class="pt-2 space-y-2">
{#if eventHref || locText || item.attachment?.src}
{#if item._slug || eventHref || locText || item.attachment?.src}
<div class="flex flex-wrap gap-2">
{#if item._slug}
<a
href={`/termin/${encodeURIComponent(item._slug)}/`}
class="btn-tertiary btn-sm"
>
Details
<Icon
icon="mdi:arrow-right"
class="size-3.5"
aria-hidden="true"
/>
</a>
{/if}
{#if eventHref}
<a
href={eventHref}
@@ -902,6 +928,16 @@
Bild
</button>
{/if}
<button
type="button"
onclick={() => openQr(item)}
class="inline-flex items-center gap-1 rounded px-1.5 py-1 text-[11px] text-stein-700 hover:bg-white"
title="QR-Code anzeigen & herunterladen"
aria-label="QR-Code anzeigen & herunterladen"
>
<Icon icon="mdi:qrcode" class="size-3.5" />
QR
</button>
</div>
{/if}
@@ -1325,6 +1361,15 @@
/>
{/if}
{#if qrModal}
<QrModal
value={qrModal.value}
label={qrModal.label}
sublabel="Termin-Link"
onclose={() => (qrModal = null)}
/>
{/if}
<style>
/* Heute-Markierung im Kalendergrid: dezenter Rand + leichtes Glow.
Ergänzt das Event-Badge, damit auch leere Tage als "Heute"