import type { Metadata, Viewport } from 'next' import { Inter, JetBrains_Mono } from 'next/font/google' import { headers } from 'next/headers' import { ThemeProvider } from 'next-themes' import { NextIntlClientProvider } from 'next-intl' import { getLocale, getMessages } from 'next-intl/server' import { THEME_IDS } from '@/lib/themes' import { ThemeBackground } from '@/components/ui/theme-background' import './globals.css' const inter = Inter({ subsets: ['latin'], variable: '--font-sans', display: 'swap', }) const jetbrainsMono = JetBrains_Mono({ subsets: ['latin'], variable: '--font-mono', display: 'swap', }) function resolveMetadataBase(): URL { const candidates = [ process.env.NEXT_PUBLIC_APP_URL, process.env.MC_PUBLIC_BASE_URL, process.env.APP_URL, process.env.MISSION_CONTROL_PUBLIC_URL, ] .map((value) => String(value || '').trim()) .filter(Boolean) for (const candidate of candidates) { try { return new URL(candidate) } catch { // Ignore invalid URL values and continue fallback chain. } } // Prevent localhost fallback in production metadata when env is unset. return new URL('https://mission-control.local') } const metadataBase = resolveMetadataBase() export const viewport: Viewport = { width: 'device-width', initialScale: 1, maximumScale: 1, viewportFit: 'cover', } export const metadata: Metadata = { title: 'Mission Control', description: 'OpenClaw Agent Orchestration Dashboard', metadataBase, icons: { icon: [ { url: '/icon.png', type: 'image/png', sizes: '256x256' }, { url: '/brand/mc-logo-128.png', type: 'image/png', sizes: '128x128' }, ], apple: [{ url: '/apple-icon.png', sizes: '180x180', type: 'image/png' }], shortcut: ['/icon.png'], }, openGraph: { title: 'Mission Control', description: 'OpenClaw Agent Orchestration Dashboard', images: [{ url: '/brand/mc-logo-512.png', width: 512, height: 512, alt: 'Mission Control logo' }], }, twitter: { card: 'summary', title: 'Mission Control', description: 'OpenClaw Agent Orchestration Dashboard', images: ['/brand/mc-logo-512.png'], }, appleWebApp: { capable: true, statusBarStyle: 'black-translucent', title: 'Mission Control', }, } export default async function RootLayout({ children, }: { children: React.ReactNode }) { const nonce = (await headers()).get('x-nonce') || undefined const locale = await getLocale() const messages = await getMessages() return (
{/* Blocking script to set 'dark' class before first paint, preventing FOUC. Content is a static string literal — no user input, no XSS vector. */}