23faef550e
- calendar_item schema: flyer → image (type: image), attachment (assetUrl)
- CalendarItemData: image + attachment fields
- event anchor IDs (#event-{slug}) with onMount hash scroll + auto-open
- share button uses direct calendar anchor URL
- copy link button (mdi:link-variant) copies anchor URL to clipboard
- ImageModal extracted as reusable component
- action buttons always show text (no expand-on-hover)
- onDestroy window guard (SSR fix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
45 lines
1.2 KiB
Svelte
45 lines
1.2 KiB
Svelte
<script lang="ts">
|
|
import { onMount, onDestroy } from "svelte";
|
|
import Icon from "@iconify/svelte";
|
|
import "$lib/iconify-offline";
|
|
|
|
let {
|
|
src,
|
|
alt = "",
|
|
onclose,
|
|
}: { src: string; alt?: string; onclose: () => void } = $props();
|
|
|
|
function onKeydown(e: KeyboardEvent) {
|
|
if (e.key === "Escape") onclose();
|
|
}
|
|
|
|
onMount(() => window.addEventListener("keydown", onKeydown));
|
|
onDestroy(() => {
|
|
if (typeof window !== "undefined")
|
|
window.removeEventListener("keydown", onKeydown);
|
|
});
|
|
</script>
|
|
|
|
<div
|
|
class="fixed inset-0 z-[9999] flex items-center justify-center bg-black/80 p-4 cursor-zoom-out"
|
|
onclick={onclose}
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-label={alt || "Bild Vollansicht"}
|
|
>
|
|
<img
|
|
{src}
|
|
{alt}
|
|
class="max-w-full max-h-full object-contain rounded shadow-2xl cursor-default"
|
|
onclick={(e) => e.stopPropagation()}
|
|
/>
|
|
<button
|
|
type="button"
|
|
onclick={onclose}
|
|
class="absolute top-4 right-4 p-2 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
|
aria-label="Schließen"
|
|
>
|
|
<Icon icon="mdi:close" class="size-5" aria-hidden="true" />
|
|
</button>
|
|
</div>
|