mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 20:51:17 +00:00
125 lines
7 KiB
TypeScript
125 lines
7 KiB
TypeScript
import Image from "next/image"
|
|
import Link from "next/link"
|
|
import { EyeIcon } from "lucide-react"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { buttonVariants } from "@/components/ui/button"
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
import { getClients } from "@/modules/admin/queries/clients"
|
|
import { dateFormat, shareState, type ShareState } from "../../lib/preview"
|
|
import { getTemplate, templates } from "../../lib/registry"
|
|
import { getVariants } from "../../queries/variants"
|
|
import { CreateVariantButton } from "../components/create-variant-button"
|
|
|
|
const shareBadge: Record<ShareState, { label: string; variant: "success" | "warning" | "neutral" }> = {
|
|
shared: { label: "Geteilt", variant: "success" },
|
|
expired: { label: "Abgelaufen", variant: "warning" },
|
|
private: { label: "Privat", variant: "neutral" },
|
|
}
|
|
|
|
const TemplatesView = async () => {
|
|
const [variants, clients] = await Promise.all([getVariants(), getClients()])
|
|
const clientNames = new Map(clients.map((client) => [client.id, client.name]))
|
|
|
|
return (
|
|
<div className="flex w-full flex-col gap-10">
|
|
<div className="flex flex-col gap-2">
|
|
<h1 className="text-2xl font-semibold md:text-3xl">Vorlagen</h1>
|
|
<p className="max-w-2xl text-sm text-muted-foreground">
|
|
Demo-Webseiten für Pitches: Vorlage wählen, für den Kunden anpassen und als Link teilen.
|
|
</p>
|
|
</div>
|
|
|
|
<section className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
|
{templates.map((template) => (
|
|
<article key={template.key} className="group flex flex-col overflow-hidden rounded-xl border bg-card">
|
|
<div className="relative aspect-[4/3] overflow-hidden">
|
|
<Image
|
|
src={template.cover}
|
|
alt=""
|
|
fill
|
|
sizes="(min-width: 1280px) 25vw, (min-width: 640px) 50vw, 100vw"
|
|
className="object-cover transition-transform duration-700 group-hover:scale-105"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/10 to-transparent" />
|
|
<span className="absolute top-3 left-3 rounded-full bg-black/50 px-2.5 py-1 text-xs text-white backdrop-blur">
|
|
{template.industry}
|
|
</span>
|
|
<div className="absolute bottom-3 left-3 flex gap-1.5">
|
|
{template.palettes.map((palette) => (
|
|
<span
|
|
key={palette.key}
|
|
title={palette.label}
|
|
className="size-4 rounded-full ring-2 ring-white/70"
|
|
style={{ background: `linear-gradient(135deg, ${palette.bg} 50%, ${palette.accent} 50%)` }}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-1 flex-col gap-2 p-4">
|
|
<h2 className="font-semibold">{template.name}</h2>
|
|
<p className="flex-1 text-sm text-muted-foreground">{template.description}</p>
|
|
<div className="mt-3 flex flex-wrap gap-2">
|
|
<a
|
|
href={`/preview/${template.key}`}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
className={buttonVariants({ variant: "outline", size: "sm" })}
|
|
>
|
|
<EyeIcon /> Ansehen
|
|
</a>
|
|
<CreateVariantButton templateKey={template.key} />
|
|
</div>
|
|
</div>
|
|
</article>
|
|
))}
|
|
</section>
|
|
|
|
<section className="flex flex-col gap-4">
|
|
<h2 className="text-lg font-semibold">Varianten</h2>
|
|
{variants.length === 0 ? (
|
|
<p className="rounded-xl border border-dashed p-8 text-center text-sm text-muted-foreground">
|
|
Noch keine Varianten. Wähle oben eine Vorlage und klicke auf „Anpassen“.
|
|
</p>
|
|
) : (
|
|
<div className="overflow-hidden rounded-xl border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Name</TableHead>
|
|
<TableHead>Vorlage</TableHead>
|
|
<TableHead className="hidden md:table-cell">Client</TableHead>
|
|
<TableHead>Link</TableHead>
|
|
<TableHead className="hidden md:table-cell">Geändert</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{variants.map((variant) => {
|
|
const badge = shareBadge[shareState(variant.share_token, variant.share_expires_at)]
|
|
return (
|
|
<TableRow key={variant.id}>
|
|
<TableCell>
|
|
<Link href={`/admin/templates/${variant.id}`} className="font-medium hover:underline">
|
|
{variant.name}
|
|
</Link>
|
|
</TableCell>
|
|
<TableCell>{getTemplate(variant.template_key)?.name ?? variant.template_key}</TableCell>
|
|
<TableCell className="hidden md:table-cell">
|
|
{(variant.client_id && clientNames.get(variant.client_id)) ?? "—"}
|
|
</TableCell>
|
|
<TableCell><Badge variant={badge.variant}>{badge.label}</Badge></TableCell>
|
|
<TableCell className="hidden text-muted-foreground md:table-cell">
|
|
{dateFormat.format(new Date(variant.updated_at))}
|
|
</TableCell>
|
|
</TableRow>
|
|
)
|
|
})}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
)}
|
|
</section>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default TemplatesView
|