import type { Metadata, Viewport } from "next"; import { Inter } from "next/font/google"; import { headers, cookies } from "next/headers"; import "./globals.css"; import { Providers } from "@/components/providers"; import { AuthShell } from "@/components/layout/auth-shell"; import { MonitoringBootstrap } from "@/components/monitoring/bootstrap"; import { WebVitalsReporter } from "@/components/monitoring/web-vitals-reporter"; import { parseLocaleFromAcceptLanguage } from "@/lib/format-locale"; import { locales, type Locale } from "@/lib/i18n/config"; async function resolveInitialLocale(): Promise { // Both cookies() and headers() can throw (DynamicServerError, etc.) — // fall back to the default so a locale hiccup never crashes the root // layout into global-error.tsx. try { const cookieStore = await cookies(); const cookieLocale = cookieStore.get("healthlog-locale")?.value; if (cookieLocale && (locales as readonly string[]).includes(cookieLocale)) { return cookieLocale as Locale; } const headerList = await headers(); return parseLocaleFromAcceptLanguage(headerList.get("accept-language")); } catch { return "en"; } } const inter = Inter({ variable: "--font-sans", subsets: ["latin"], weight: ["400", "500", "600", "700"], }); export const metadata: Metadata = { title: "HealthLog", description: "Personal health tracking — weight, blood pressure, pulse, mood, medication compliance", manifest: "/manifest.json", icons: { icon: "/favicon.svg", apple: "/logo-192.png", }, appleWebApp: { capable: true, statusBarStyle: "black-translucent", title: "HealthLog", }, openGraph: { title: "HealthLog", description: "Self-hosted health tracker. Weight, blood pressure, glucose, mood, medications. Withings + Apple Health sync. AI Insights you own.", type: "website", locale: "en_US", alternateLocale: ["de_DE", "fr_FR", "es_ES", "it_IT", "pl_PL"], siteName: "HealthLog", // Drop-in OG asset. Replace with a 1200×630 dashboard-screenshot // capture when an official one ships; the logo render keeps the // unfurl from rendering a blank tile in the meantime. images: [ { url: "/logo-readme.png", width: 1000, height: 1000, alt: "HealthLog — your health data, your server", }, ], }, twitter: { card: "summary_large_image", title: "HealthLog", description: "Self-hosted health tracker. Weight, blood pressure, glucose, mood, medications. Withings + Apple Health sync. AI Insights you own.", images: ["/logo-readme.png"], }, }; export const viewport: Viewport = { width: "device-width", initialScale: 1, viewportFit: "cover", // Match the browser chrome (Android URL bar, iOS PWA status bar) to // the active palette. The hex values are the resolved background of // `--background` from `app/globals.css` for each theme so the bar // edge never seams against the page on cold paint. themeColor: [ { media: "(prefers-color-scheme: light)", color: "#ffffff" }, { media: "(prefers-color-scheme: dark)", color: "#282a36" }, ], }; // Inline script to apply theme before first paint (prevents FOUC) const themeScript = `(function(){try{var t=localStorage.getItem("healthlog-theme");var c=(t==="light"||t==="dark")?t:(window.matchMedia("(prefers-color-scheme:dark)").matches?"dark":"light");document.documentElement.classList.add(c)}catch(e){document.documentElement.classList.add("dark")}})()`; export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { const nonce = process.env.NODE_ENV === "production" ? ((await headers()).get("x-nonce") ?? undefined) : undefined; const initialLocale = await resolveInitialLocale(); return (