Files
Speisekarte/app/layout.tsx
T
florian.wilde 08a5ef8a2b v1.6: RSS-Feed für den Speiseplan + Badge für offene Rezeptvorschläge
app/feed.xml: RSS-2.0-Feed mit einem Eintrag pro Tag (aktuelle +
nächste Woche), Gerichte je Essenszeit im CDATA-Beschreibungstext.
Immer auf Deutsch, da Feedreader kein Sprach-Cookie mitschicken.

Autodiscovery-Link im <head> (app/layout.tsx) sowie sichtbares
RSS-Icon im Header der öffentlichen Speisekarte (neben Sprachumschalter/
Anmelden – die einzige Stelle, die auf allen Bildschirmgrößen sichtbar
ist).

AppHeader: "Vorschläge"-Navigationspunkt zeigt jetzt die Anzahl
offener Rezeptvorschläge als Zahl im roten Kreis (GET
/api/dish-suggestions, bereits staff/admin-beschränkt), aktualisiert
sich bei Navigation innerhalb des internen Bereichs.
2026-07-18 12:18:46 +02:00

68 lines
2.3 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 } from "next";
import { Geist } from "next/font/google";
import "./globals.css";
import { getSettings } from "@/lib/db/settings";
import { COLOR_VARS, DEFAULT_COLORS, faviconUrl, SITE_TITLE } from "@/lib/types";
import { getDictionary, getLocale } from "@/lib/i18n";
import { LocaleProvider } from "@/components/i18n/LocaleProvider";
import packageJson from "@/package.json";
// Farben/Logo/Favicon sollen Änderungen sofort widerspiegeln.
export const dynamic = "force-dynamic";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
export async function generateMetadata(): Promise<Metadata> {
const settings = await getSettings();
return {
title: SITE_TITLE,
description: "Speisekarte der Betriebskantine",
// Immer explizit setzen: app/favicon.ico würde sonst zusätzlich zu
// einem eigenen Favicon eingebunden (Next.js kombiniert Datei-
// Konvention und Metadata statt sie zu ersetzen).
icons: { icon: faviconUrl(settings?.favicon_path) ?? "/favicon.ico" },
// Autodiscovery für Feedreader (Browser zeigen dafür kein eigenes
// Icon mehr an, daher zusätzlich ein sichtbares RSS-Icon im Header
// der öffentlichen Speisekarte, s. app/page.tsx).
alternates: {
types: {
"application/rss+xml": [{ url: "/feed.xml", title: `${SITE_TITLE} – Speiseplan` }],
},
},
};
}
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const [settings, locale] = await Promise.all([getSettings(), getLocale()]);
const dict = getDictionary(locale);
const colors: Record<string, string> = {
...DEFAULT_COLORS,
...(settings?.colors ?? {}),
};
const style = Object.fromEntries(
Object.entries(COLOR_VARS).map(([key, cssVar]) => [cssVar, colors[key]])
) as React.CSSProperties;
return (
<html lang={locale} className={`${geistSans.variable} h-full antialiased`}>
<body style={style} className="min-h-full flex flex-col">
<LocaleProvider locale={locale} dict={dict}>
{children}
</LocaleProvider>
<footer className="mt-auto px-4 py-2 text-right text-xs text-gray-400 select-none">
Version {packageJson.version}
</footer>
</body>
</html>
);
}