Files
flimmer/src/app/page.tsx
T
Florian Wilde b001e62695 feat: App-Hülle mit Header, Theme-Umschalter und Übersicht
Layout mit Inline-Skript, das data-theme setzt, bevor der erste Pixel
gemalt wird — sonst blitzt beim Laden das falsche Farbschema auf. Logo als
React-Komponente statt als Bilddatei: nimmt Theme-Farben an, spart einen
Netzwerkabruf und die Verläufe liegen einmalig im Root-Layout.

Im hellen Modus greifen eigene Tokens für Verlaufstext und Wortmarke; der
vollfarbige Signaturverlauf fällt auf warmem Weiß sonst unter WCAG AA.
2026-09-01 18:46:47 +02:00

84 lines
3.2 KiB
TypeScript

import Link from "next/link";
import { requireUser } from "@/lib/auth";
import { getSettings } from "@/lib/settings";
import { env } from "@/lib/env";
import { AppShell } from "@/components/AppShell";
import { FlimmerMark } from "@/components/brand/FlimmerLogo";
/**
* Übersichtsseite.
*
* In dieser Etappe steht hier die Begrüßung und der Hinweis auf die nächsten
* Schritte; ab Etappe 5 ziehen „Weiterschauen", Kalender und Neuzugänge ein.
*/
export default async function DashboardPage() {
const user = await requireUser();
const settings = await getSettings();
return (
<AppShell user={user} instanceName={settings.instanceName}>
<section className="fl-card relative overflow-hidden p-6 sm:p-10">
<div
aria-hidden
className="pointer-events-none absolute -right-24 -top-32 h-72 w-72 rounded-full opacity-30 blur-3xl"
style={{ backgroundImage: "var(--fl-gradient)" }}
/>
<div className="relative">
<FlimmerMark className="h-12 w-12" />
<h1 className="mt-4 text-3xl font-semibold tracking-tight sm:text-4xl">
Hallo {user.name.split(" ")[0]}.
</h1>
<p className="mt-2 max-w-xl text-[var(--fl-muted)]">
Schön, dass du da bist. Sobald du deinen ersten Titel hinzufügst, findest du hier
deine laufenden Serien, die nächsten Episoden und was auf deiner Watchlist gerade
verfügbar geworden ist.
</p>
<div className="mt-6 flex flex-wrap gap-3">
<Link href="/suche" className="fl-btn fl-btn-primary">
Titel suchen und hinzufügen
</Link>
<Link href="/bibliothek" className="fl-btn fl-btn-ghost">
Zur Bibliothek
</Link>
</div>
{!env.tmdb.isConfigured && (
<p className="mt-6 max-w-xl rounded-xl border border-[color-mix(in_oklab,var(--fl-warning)_40%,transparent)] bg-[color-mix(in_oklab,var(--fl-warning)_10%,transparent)] px-3 py-2 text-sm text-[var(--fl-warning)]">
Es ist noch kein TMDB-Schlüssel hinterlegt. Ohne ihn findet die Suche keine
Metadaten — trage <code>TMDB_API_KEY</code> in der <code>.env</code> ein und starte
die Instanz neu.
</p>
)}
</div>
</section>
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<PlaceholderCard
title="Weiterschauen"
text="Deine laufenden Serien mit der jeweils nächsten Episode."
/>
<PlaceholderCard
title="Demnächst"
text="Kalender der Episoden, die in den nächsten Wochen ausgestrahlt werden."
/>
<PlaceholderCard
title="Neu verfügbar"
text="Watchlist-Titel, die auf einem deiner Dienste aufgetaucht sind."
/>
</div>
</AppShell>
);
}
function PlaceholderCard({ title, text }: { title: string; text: string }) {
return (
<div className="fl-card p-5">
<h2 className="text-sm font-semibold tracking-wide text-[var(--fl-muted)] uppercase">
{title}
</h2>
<p className="mt-2 text-sm text-[var(--fl-faint)]">{text}</p>
</div>
);
}