Files
nebula/src/app/layout.tsx
T
florian.wildeandClaude Opus 5 3bad4ace10 feat(ui): Schnellsuche mit Strg+K
Palette ueber die ganze Anwendung: Projekte nach Name, Kurzbeschreibung und
Tags, Notizen ueber die serverseitige Volltextsuche, dazu die Bereiche.
Ohne Eingabe stehen die zuletzt bearbeiteten Projekte bereit - danach sucht
man ueblicherweise.

Bedienung ueber Tastatur, wie man es erwartet: Pfeile waehlen, Enter oeffnet,
Escape schliesst, der ausgewaehlte Eintrag bleibt im Blick.

Die Projektliste wird beim ersten Oeffnen geholt und dann behalten. Sie bei
jedem Tastendruck neu zu laden waere Verschwendung, und veraltet ist sie
hoechstens um die Dauer einer Sitzung. Notizen sucht dagegen der Server,
entprellt ab zwei Zeichen - sie mitzuladen wuerde die Seite aufblaehen.

Wie Menue und Dialog haengt die Palette per Portal am body, aus denselben
Gruenden: overflow-hidden und backdrop-filter der Karten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 11:36:44 +02:00

66 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata, Viewport } from "next";
import { CommandPalette } from "@/components/CommandPalette";
import { TopNav } from "@/components/TopNav";
import { getSessionUser } from "@/lib/auth/session";
import { APP_NAME, APP_TAGLINE, APP_VERSION } from "@/lib/config";
import "./globals.css";
/**
* generateMetadata statt eines konstanten metadata-Objekts: nur so wird
* APP_NAME zur Laufzeit gelesen. Ein konstanter Export waere beim Build
* eingefroren und liesse sich im fertigen Docker-Image nicht mehr aendern.
*/
export async function generateMetadata(): Promise<Metadata> {
return {
title: {
default: `${APP_NAME} – Vibe Coding Dashboard`,
template: `%s · ${APP_NAME}`,
},
description:
"Uebersicht ueber alle Vibe-Coding Projekte: Status, Notizen und Live-Daten aus GitHub, GitLab und Gitea.",
applicationName: APP_NAME,
robots: { index: false, follow: false },
};
}
export const viewport: Viewport = {
themeColor: "#05060f",
width: "device-width",
initialScale: 1,
};
export default async function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
const user = await getSessionUser();
return (
<html lang="de" suppressHydrationWarning>
<body className="min-h-screen antialiased">
<div className="aurora" aria-hidden="true">
<div className="aurora-blob aurora-blob--one" />
<div className="aurora-blob aurora-blob--two" />
<div className="aurora-blob aurora-blob--three" />
</div>
<div className="aurora-grid" aria-hidden="true" />
<TopNav user={user} appName={APP_NAME} tagline={APP_TAGLINE} />
{/* Nur fuer Angemeldete – auf der Anmeldeseite gibt es nichts zu suchen. */}
{user ? <CommandPalette isAdmin={user.role === "ADMIN"} /> : null}
<main className="mx-auto w-full max-w-[1400px] px-4 pb-24 pt-6 sm:px-6 lg:px-8">
{children}
</main>
<footer className="mx-auto w-full max-w-[1400px] px-4 pb-10 text-xs text-slate-500 sm:px-6 lg:px-8">
<div className="flex flex-wrap items-center justify-between gap-2 border-t border-white/5 pt-6">
<span>{APP_NAME} · lokal betrieben, Daten bleiben in deiner PostgreSQL.</span>
<span className="font-mono text-slate-600">v{APP_VERSION}</span>
</div>
</footer>
</body>
</html>
);
}