Spaces:
Runtime error
Runtime error
| import { Inter } from "next/font/google"; | |
| import "./globals.css"; | |
| import { ThemeProvider } from "@/shared/components/ThemeProvider"; | |
| import { NextIntlClientProvider } from "next-intl"; | |
| import { getMessages, getLocale } from "next-intl/server"; | |
| import { RTL_LOCALES } from "@/i18n/config"; | |
| import { normalizeComplianceEventTypes } from "@/i18n/request"; | |
| import { getSettings } from "@/lib/db/settings"; | |
| import type { Viewport } from "next"; | |
| import { PwaRegister } from "@/shared/components/PwaRegister"; | |
| const inter = Inter({ | |
| subsets: ["latin"], | |
| variable: "--font-inter", | |
| }); | |
| export const viewport: Viewport = { | |
| themeColor: "#0b0f1a", | |
| viewportFit: "cover", | |
| }; | |
| export async function generateMetadata() { | |
| const settings = await getSettings(); | |
| const instanceName = settings?.instanceName || "OmniRoute"; | |
| const customFaviconUrl = settings?.customFaviconUrl || settings?.customFaviconBase64; | |
| return { | |
| title: `${instanceName} — AI Gateway for Multi-Provider LLMs`, | |
| description: | |
| "OmniRoute is an AI gateway for multi-provider LLMs. One endpoint for all your AI providers.", | |
| manifest: "/manifest.webmanifest", | |
| applicationName: instanceName, | |
| appleWebApp: { | |
| capable: true, | |
| title: instanceName, | |
| statusBarStyle: "black-translucent", | |
| }, | |
| other: { | |
| "mobile-web-app-capable": "yes", | |
| }, | |
| icons: { | |
| icon: customFaviconUrl | |
| ? "/api/settings/favicon" | |
| : [ | |
| { url: "/favicon.ico", sizes: "any" }, | |
| { url: "/favicon.svg", type: "image/svg+xml" }, | |
| { url: "/icon-512.png", type: "image/png", sizes: "512x512" }, | |
| ], | |
| apple: [{ url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }], | |
| }, | |
| }; | |
| } | |
| export default async function RootLayout({ children }) { | |
| const locale = await getLocale(); | |
| const messages = normalizeComplianceEventTypes((await getMessages()) as Record<string, unknown>); | |
| const isRtl = RTL_LOCALES.includes(locale as (typeof RTL_LOCALES)[number]); | |
| return ( | |
| <html lang={locale} dir={isRtl ? "rtl" : "ltr"} suppressHydrationWarning> | |
| <head> | |
| {/* Material Symbols icon font is self-hosted via globals.css | |
| (@import "material-symbols/outlined.css") so icons render even when | |
| the Google Fonts CDN is unreachable (#3695). */} | |
| <script | |
| dangerouslySetInnerHTML={{ | |
| __html: ` | |
| if (typeof window !== 'undefined') { | |
| if (!window.crypto) { | |
| window.crypto = {}; | |
| } | |
| if (!window.crypto.randomUUID) { | |
| window.crypto.randomUUID = function() { | |
| if (window.crypto.getRandomValues) { | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |
| const r = window.crypto.getRandomValues(new Uint8Array(1))[0] % 16; | |
| const v = c === 'x' ? r : (r & 0x3 | 0x8); | |
| return v.toString(16); | |
| }); | |
| } | |
| return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { | |
| const r = Math.random() * 16 | 0; | |
| const v = c === 'x' ? r : (r & 0x3 | 0x8); | |
| return v.toString(16); | |
| }); | |
| }; | |
| } | |
| } | |
| try { | |
| const stored = localStorage.getItem('theme'); | |
| const parsed = stored ? JSON.parse(stored) : null; | |
| const theme = parsed?.state?.theme || 'system'; | |
| if (theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) { | |
| document.documentElement.classList.add('dark'); | |
| } else { | |
| document.documentElement.classList.remove('dark'); | |
| } | |
| } catch (e) {} | |
| `, | |
| }} | |
| /> | |
| ); | |
| } | |