135 lines
5.7 KiB
TypeScript
135 lines
5.7 KiB
TypeScript
export const dynamic = 'force-dynamic';
|
||
import { unstable_noStore as noStore } from 'next/cache';
|
||
import Link from "next/link";
|
||
import { pb, COUNTRY_LABELS, COUNTRY_FLAGS } from "@/lib/pb";
|
||
|
||
async function getStats() {
|
||
noStore();
|
||
try {
|
||
const [kz, diplo, gesehen] = await Promise.all([
|
||
pb.collection("kennzeichen").getList(1, 1, { filter: "active=true" }),
|
||
pb.collection("diplomatenkennzeichen").getList(1, 1),
|
||
pb.collection("gesehen").getList(1, 1),
|
||
]);
|
||
return {
|
||
kennzeichen: kz.totalItems,
|
||
diplomaten: diplo.totalItems,
|
||
gesehen: gesehen.totalItems,
|
||
};
|
||
} catch {
|
||
return { kennzeichen: 0, diplomaten: 0, gesehen: 0 };
|
||
}
|
||
}
|
||
|
||
async function getLasteSeen() {
|
||
noStore();
|
||
try {
|
||
return pb.collection("gesehen").getList(1, 5, { sort: "-datum" });
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export default async function Home() {
|
||
const [stats, latest] = await Promise.all([getStats(), getLasteSeen()]);
|
||
|
||
const countries = Object.entries(COUNTRY_LABELS).slice(0, 12);
|
||
|
||
return (
|
||
<div className="max-w-6xl mx-auto px-6 py-16">
|
||
|
||
{/* Hero */}
|
||
<div className="mb-20">
|
||
<div className="inline-block mb-6 px-3 py-1 border border-[var(--accent)] rounded-sm text-[var(--accent)] text-xs font-mono tracking-widest uppercase">
|
||
Open Data · Eigensammlung
|
||
</div>
|
||
<h1 style={{ fontFamily: "'Syne', sans-serif", fontWeight: 800, fontSize: "clamp(2.5rem, 6vw, 4.5rem)", lineHeight: 1.05, letterSpacing: "-0.03em" }}
|
||
className="text-[var(--ink)] mb-6 max-w-3xl">
|
||
Kennzeichen.<br />Gesammelt, dokumentiert,<br />
|
||
<span className="text-[var(--accent)]">geteilt.</span>
|
||
</h1>
|
||
<p className="text-[var(--muted)] text-lg max-w-xl leading-relaxed">
|
||
Persönliche Datenbank europäischer Kfz-Kennzeichen — mit Sonderformen,
|
||
Diplomatenkennzeichen und allem was sich nicht einfach einordnen lässt.
|
||
</p>
|
||
<div className="flex gap-3 mt-8">
|
||
<Link href="/kennzeichen"
|
||
className="px-5 py-2.5 bg-[var(--ink)] text-[var(--paper)] rounded-md text-sm font-medium hover:bg-[var(--accent)] transition-colors"
|
||
style={{ fontFamily: "'Syne', sans-serif" }}>
|
||
Datenbank →
|
||
</Link>
|
||
<Link href="/blog"
|
||
className="px-5 py-2.5 border border-[var(--warm)] text-[var(--ink)] rounded-md text-sm font-medium hover:border-[var(--ink)] transition-colors"
|
||
style={{ fontFamily: "'Syne', sans-serif" }}>
|
||
Blog lesen
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Stats */}
|
||
<div className="grid grid-cols-3 gap-4 mb-20">
|
||
{[
|
||
{ label: "Kennzeichen", value: stats.kennzeichen.toLocaleString("de") },
|
||
{ label: "Diplomatenkz.", value: stats.diplomaten.toLocaleString("de") },
|
||
{ label: "Gesehen", value: stats.gesehen.toLocaleString("de") },
|
||
].map((s) => (
|
||
<div key={s.label} className="border border-[var(--warm)] rounded-lg p-6 bg-white/40">
|
||
<div style={{ fontFamily: "'Syne', sans-serif", fontWeight: 700, fontSize: "2.25rem", lineHeight: 1 }}
|
||
className="text-[var(--ink)] mb-1">
|
||
{s.value}
|
||
</div>
|
||
<div className="text-sm text-[var(--muted)]">{s.label}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Länder */}
|
||
<div className="mb-20">
|
||
<h2 style={{ fontFamily: "'Syne', sans-serif", fontWeight: 700, fontSize: "1.25rem" }}
|
||
className="mb-6 text-[var(--ink)]">
|
||
Länder in der Datenbank
|
||
</h2>
|
||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
|
||
{countries.map(([key, label]) => (
|
||
<Link key={key} href={`/kennzeichen?land=${key}`}
|
||
className="flex items-center gap-2.5 px-4 py-3 border border-[var(--warm)] rounded-lg bg-white/40 hover:border-[var(--ink)] hover:bg-white/80 transition-all text-sm">
|
||
<span className="text-xl">{COUNTRY_FLAGS[key] ?? "🌍"}</span>
|
||
<span>{label}</span>
|
||
</Link>
|
||
))}
|
||
<Link href="/kennzeichen"
|
||
className="flex items-center justify-center gap-2 px-4 py-3 border border-dashed border-[var(--warm)] rounded-lg text-sm text-[var(--muted)] hover:text-[var(--ink)] hover:border-[var(--ink)] transition-all">
|
||
Alle anzeigen →
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Zuletzt gesehen */}
|
||
{latest && latest.items.length > 0 && (
|
||
<div>
|
||
<h2 style={{ fontFamily: "'Syne', sans-serif", fontWeight: 700, fontSize: "1.25rem" }}
|
||
className="mb-6 text-[var(--ink)]">
|
||
Zuletzt gesehen
|
||
</h2>
|
||
<div className="space-y-2">
|
||
{latest.items.map((item: any) => (
|
||
<div key={item.id} className="flex items-center gap-4 px-4 py-3 border border-[var(--warm)] rounded-lg bg-white/40">
|
||
{item.kennzeichen_code && <span className="kz-badge seen">{item.kennzeichen_code}</span>}
|
||
<div className="flex-1">
|
||
<span className="text-sm font-medium">{item.kennzeichen_name || "—"}</span>
|
||
<span className="text-xs text-[var(--muted)] ml-2">{COUNTRY_FLAGS[item.land] ?? ""}</span>
|
||
</div>
|
||
<span className="text-xs text-[var(--muted)] font-mono">
|
||
{new Date(item.datum).toLocaleDateString("de-DE")}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<Link href="/sammlung" className="inline-block mt-4 text-sm text-[var(--accent)] hover:underline">
|
||
Gesamte Sammlung →
|
||
</Link>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|