Files
xevion.dev/web/src/lib/components/admin/Modal.svelte
Xevion 16bf2b76f3 feat: add admin panel with project and tag management
- Full CRUD interface for projects with GitHub integration and tagging
- Real-time event log with expandable metadata viewer
- Reusable component library (Badge, Button, Input, Modal, Table,
TagPicker)
- Server-side API client with Unix socket and HTTP support
- JWT-based authentication with Svelte 5 reactive stores
- Settings management for social links and site identity
- Remove /admin path from tarpit to allow legitimate access
2026-01-06 10:07:59 -06:00

85 lines
1.8 KiB
Svelte

<script lang="ts">
import { cn } from "$lib/utils";
import Button from "./Button.svelte";
interface Props {
open: boolean;
title?: string;
description?: string;
confirmText?: string;
cancelText?: string;
confirmVariant?: "primary" | "danger";
onconfirm?: () => void;
oncancel?: () => void;
children?: import("svelte").Snippet;
}
let {
open = $bindable(false),
title = "Confirm",
description,
confirmText = "Confirm",
cancelText = "Cancel",
confirmVariant = "primary",
onconfirm,
oncancel,
children,
}: Props = $props();
function handleCancel() {
open = false;
oncancel?.();
}
function handleConfirm() {
open = false;
onconfirm?.();
}
function handleBackdropClick(e: MouseEvent) {
if (e.target === e.currentTarget) {
handleCancel();
}
}
</script>
{#if open}
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4"
onclick={handleBackdropClick}
role="dialog"
aria-modal="true"
>
<div
class="relative w-full max-w-md rounded-xl bg-zinc-900 border border-zinc-800 p-8 shadow-xl shadow-black/50"
>
{#if title}
<h2 class="text-lg font-semibold text-zinc-50 mb-2">
{title}
</h2>
{/if}
{#if description}
<p class="text-sm text-zinc-400 mb-4">
{description}
</p>
{/if}
{#if children}
<div class="mb-4">
{@render children()}
</div>
{/if}
<div class="flex justify-end gap-3">
<Button variant="secondary" onclick={handleCancel}>
{cancelText}
</Button>
<Button variant={confirmVariant} onclick={handleConfirm}>
{confirmText}
</Button>
</div>
</div>
</div>
{/if}