SPB Git forge

spb/spb-cloud

Public
10commits 1branches 0releases
3.2 MBsize
maindefault branch
1 h agolast push
JavaScript 56.7% TypeScript 42.6%
2.6 KB · 86 lines tsx
Raw Blame History
1import type { Metadata, Viewport } from "next";2import localFont from "next/font/local";3import "./globals.css";4import ThemeProvider from "@/components/theme/ThemeProvider";5import { DynamicToaster } from "@/components/theme/DynamicToaster";67const geist = localFont({8  src: "./fonts/GeistVF.woff",9  variable: "--font-geist",10  weight: "100 900",11  display: "swap",12});1314const geistMono = localFont({15  src: "./fonts/GeistMonoVF.woff",16  variable: "--font-geist-mono",17  weight: "100 900",18  display: "swap",19});2021export const metadata: Metadata = {22  title: { default: "SPB Cloud", template: "%s · SPB Cloud" },23  description: "Cloud personnel privé, chiffré et local-first.",24  applicationName: "SPB Cloud",25  manifest: "/manifest.webmanifest",26  appleWebApp: {27    capable: true,28    title: "SPB Cloud",29    statusBarStyle: "black-translucent",30  },31  icons: {32    icon: [{ url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" }],33    apple: [{ url: "/icons/apple-touch-icon.png", sizes: "180x180" }],34  },35  formatDetection: { telephone: false },36};3738export const viewport: Viewport = {39  width: "device-width",40  initialScale: 1,41  viewportFit: "cover",42  themeColor: [43    { media: "(prefers-color-scheme: light)", color: "#f5f6f8" },44    { media: "(prefers-color-scheme: dark)", color: "#0a0b10" },45  ],46};4748// Appliqué avant le premier rendu : thème, accent, densité, mouvement.49// ⚠️ Garder synchronisé avec lib/prefs.ts (clés) et ThemeProvider.50const PREPAINT = `(function(){try{51var d=document.documentElement,ls=localStorage;52var t=ls.getItem('spb-theme');53var dark=t==='dark'||(t==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);54d.classList.toggle('dark',dark);d.classList.toggle('light',!dark);d.style.colorScheme=dark?'dark':'light';55var a=ls.getItem('spb-accent');d.setAttribute('data-accent',a||'aurore');56var de=ls.getItem('spb-density');d.setAttribute('data-density',de==='compact'?'compact':'comfortable');57var m=ls.getItem('spb-motion');d.setAttribute('data-motion',m==='reduced'?'reduced':'normal');58}catch(e){}})();`;5960export default function RootLayout({61  children,62}: Readonly<{63  children: React.ReactNode;64}>) {65  return (66    <html67      lang="fr"68      className={`light ${geist.variable} ${geistMono.variable}`}69      data-accent="aurore"70      data-density="comfortable"71      data-motion="normal"72      suppressHydrationWarning73    >74      <head>75        <script dangerouslySetInnerHTML={{ __html: PREPAINT }} />76      </head>77      <body className="antialiased font-sans">78        <ThemeProvider>79          {children}80          <DynamicToaster />81        </ThemeProvider>82      </body>83    </html>84  );85}86