Files
EvoScientist-WebUI/src/app/layout.tsx
T

79 lines
2.6 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { NuqsAdapter } from "nuqs/adapters/next/app";
import { ThemeProvider, ThemedToaster } from "@/providers/ThemeProvider";
import { AuthRedirectInstaller } from "./components/AuthRedirectInstaller";
import { THEME_STORAGE_KEY } from "@/lib/theme";
import "katex/dist/katex.min.css";
import "@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css";
import localFont from "next/font/local";
import "./globals.css";
export const dynamic = "force-dynamic";
export async function generateMetadata(): Promise<Metadata> {
const { getSystemConfig, brandingVersion } = await import(
"@/lib/server/systemConfig"
);
const config = getSystemConfig();
const faviconVersion = brandingVersion("favicon");
return {
title: `${config.branding.wordmark} WebUI`,
description:
"Web UI for EvoScientist — a self-evolving AI scientist built on DeepAgents/LangGraph.",
icons:
faviconVersion > 0
? { icon: `/api/system/branding/asset/favicon?v=${faviconVersion}` }
: undefined,
};
}
export const viewport: Viewport = {
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#fafafa" },
{ media: "(prefers-color-scheme: dark)", color: "#09090b" },
],
colorScheme: "light dark",
};
// Self-hosted Inter variable font; exposes --font-inter, consumed by globals.css.
// No CJK glyphs — Chinese text falls through to PingFang/YaHei in the stack.
const inter = localFont({
src: "./fonts/InterVariable.woff2",
variable: "--font-inter",
display: "swap",
});
// Runs before paint so the right theme class is on <html> immediately — no flash
// of the wrong theme. Mirrors ThemeProvider's resolution (default: follow the
// system); ThemeProvider takes over once React mounts. Kept inline + minimal.
const themeScript = `(function(){var k=${JSON.stringify(
THEME_STORAGE_KEY
)};var t="system";try{t=localStorage.getItem(k)||"system";}catch(_){}var d=t==="dark"||(t!=="light"&&window.matchMedia("(prefers-color-scheme: dark)").matches);var e=document.documentElement;e.classList.toggle("dark",d);e.style.colorScheme=d?"dark":"light";})();`;
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html
lang="en"
suppressHydrationWarning
>
<body
suppressHydrationWarning
className={inter.variable}
>
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
<NuqsAdapter>
<ThemeProvider>
<AuthRedirectInstaller />
{children}
<ThemedToaster />
</ThemeProvider>
</NuqsAdapter>
</body>
</html>
);
}