101 lines
3.2 KiB
Svelte
101 lines
3.2 KiB
Svelte
<script lang="ts">
|
|
import * as Card from '$lib/components/ui/card';
|
|
import { Button } from '$lib/components/ui/button';
|
|
|
|
type TrainingVideo = {
|
|
id: string;
|
|
title: string;
|
|
description: string | null;
|
|
created: string;
|
|
videoUrl: string;
|
|
};
|
|
|
|
type AdminFormState = {
|
|
error?: string;
|
|
} | null;
|
|
|
|
let { data, form }: { data: { videos: TrainingVideo[] }; form: AdminFormState } = $props();
|
|
|
|
const videos = $derived(data.videos);
|
|
|
|
function formatDate(created: string) {
|
|
if (!created) return '';
|
|
const d = new Date(created);
|
|
return d.toLocaleDateString(undefined, {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
year: d.getFullYear() !== new Date().getFullYear() ? 'numeric' : undefined
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>Training admin — Base</title>
|
|
</svelte:head>
|
|
|
|
<main class="flex min-h-0 flex-1 flex-col items-center p-4 sm:p-6">
|
|
<div class="flex w-full max-w-5xl flex-col gap-4 sm:gap-6">
|
|
<div class="flex items-center justify-between gap-3">
|
|
<a href="/training">
|
|
<Button variant="ghost" size="sm">← Training</Button>
|
|
</a>
|
|
<h1 class="text-xl font-semibold">Training admin</h1>
|
|
</div>
|
|
|
|
<Card.Root>
|
|
<Card.Header class="pb-2">
|
|
<Card.Title>Videos</Card.Title>
|
|
<Card.Description>Manage training videos in the Media collection.</Card.Description>
|
|
</Card.Header>
|
|
<Card.Content class="space-y-3">
|
|
{#if form?.error}
|
|
<p class="text-destructive text-sm">{form.error}</p>
|
|
{/if}
|
|
|
|
{#if videos.length === 0}
|
|
<p class="text-muted-foreground text-sm">No videos found.</p>
|
|
{:else}
|
|
<div class="space-y-3">
|
|
{#each videos as video (video.id)}
|
|
<div class="flex items-start justify-between gap-3 rounded-md border bg-card/40 p-3">
|
|
<div class="min-w-0 space-y-1">
|
|
<div class="flex items-center gap-2">
|
|
<p class="font-medium truncate">{video.title}</p>
|
|
<span class="text-muted-foreground text-xs">{formatDate(video.created)}</span>
|
|
</div>
|
|
{#if video.description}
|
|
<p class="text-muted-foreground text-xs line-clamp-2">
|
|
{video.description}
|
|
</p>
|
|
{/if}
|
|
{#if video.videoUrl}
|
|
<p class="text-muted-foreground text-xs truncate">
|
|
{video.videoUrl}
|
|
</p>
|
|
{/if}
|
|
</div>
|
|
<form method="POST" class="flex flex-col items-end gap-2">
|
|
<input type="hidden" name="id" value={video.id} />
|
|
<Button
|
|
type="submit"
|
|
name="intent"
|
|
value="delete"
|
|
variant="destructive"
|
|
size="sm"
|
|
>
|
|
Delete
|
|
</Button>
|
|
<a href={`/training/${video.id}`}>
|
|
<Button variant="outline" size="sm">Open</Button>
|
|
</a>
|
|
</form>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
{/if}
|
|
</Card.Content>
|
|
</Card.Root>
|
|
</div>
|
|
</main>
|
|
|