import type { Metadata, Viewport } from "next"; import "./globals.css"; import { Toaster } from "@/components/ui/toast"; import { SessionProviderWrapper } from "@/components/session-provider-wrapper"; import { getAISettings } from "@/app/actions/ai-settings"; import { getUserSettings } from "@/app/actions/user-settings"; import { ThemeInitializer } from "@/components/theme-initializer"; import { DirectionInitializer } from "@/components/direction-initializer"; import { ErrorReporter } from "@/components/error-reporter"; import { auth } from "@/auth"; import Script from "next/script"; import { getThemeScript } from "@/lib/theme-script"; import { normalizeThemeId } from "@/lib/apply-document-theme"; import { Inter, Manrope, Playfair_Display, JetBrains_Mono } from "next/font/google"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", }); const manrope = Manrope({ subsets: ["latin"], variable: "--font-manrope", }); const playfair = Playfair_Display({ subsets: ["latin"], variable: "--font-memento-serif", weight: ["400", "500", "600", "700"], }); const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-jetbrains-mono", weight: ["400", "500"], }); export const metadata: Metadata = { title: "Memento - Your Digital Notepad", description: "A beautiful note-taking app built with Next.js 16", manifest: "/manifest.json", icons: { icon: "/icons/icon-512.svg", apple: "/icons/icon-512.svg", }, appleWebApp: { capable: true, statusBarStyle: "default", title: "Memento", }, }; export const viewport: Viewport = { themeColor: "#1C1C1C", }; function serverHtmlThemeState(theme?: string | null): { className?: string; dataTheme?: string } { const t = normalizeThemeId(theme || 'light') if (t === 'auto') return {} if (t === 'dark') return { className: 'dark' } if (t === 'light') return {} if (t === 'midnight') return { className: 'dark', dataTheme: 'midnight' } const named = ['sepia', 'rose', 'green', 'lavender', 'sand', 'ocean', 'sunset', 'blue'] as const if ((named as readonly string[]).includes(t)) return { dataTheme: t } return {} } /** * Inline script that runs BEFORE React hydrates. * Reads the user's saved language from localStorage and sets * `dir` on immediately — prevents RTL/LTR flash. */ const directionScript = ` (function(){ try { var lang = localStorage.getItem('user-language'); if (!lang) { var c = document.cookie.split(';').map(function(s){return s.trim()}).find(function(s){return s.startsWith('user-language=')}); if (c) lang = c.split('=')[1]; } if (lang === 'fa' || lang === 'ar') { document.documentElement.dir = 'rtl'; document.documentElement.lang = lang; } } catch(e) {} })(); `; export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { const session = await auth(); const userId = session?.user?.id; const [aiSettings, userSettings] = await Promise.all([ getAISettings(userId), getUserSettings(userId), ]) const htmlTheme = serverHtmlThemeState(userSettings.theme) return (