e8839b15a0
- Theme is now class-based (.dark on <html>) with a System/Light/Dark toggle in the sidebar, persisted to localStorage and applied pre-paint by an inline script (no flash). Replaces the prefers-color-scheme-only behavior, so a phone on a light OS theme can still choose dark and vice versa. - New brand-derived --line token (Ink at 55%): a dark line on the light paper, light on dark. The family-chart tree connectors had the library's default white stroke and were invisible in light mode — now they use --line, as do the pedigree brackets and the fan-chart sectors. - Light/dark tokens use the exact brand palette (Ink/Muted flip; Bronze/Paper constant). Frontend only — no migration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
35 lines
1.3 KiB
TypeScript
35 lines
1.3 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { Fraunces, Inter } from "next/font/google";
|
|
|
|
import "./globals.css";
|
|
|
|
const serif = Fraunces({
|
|
subsets: ["latin"],
|
|
variable: "--font-fraunces",
|
|
display: "swap",
|
|
axes: ["opsz"],
|
|
});
|
|
const sans = Inter({ subsets: ["latin"], variable: "--font-inter", display: "swap" });
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Provenance — where it came from matters",
|
|
description:
|
|
"Trace your family and your land in one place — every fact linked to the record it came from. Self-hosted, sourced, and yours to keep.",
|
|
icons: { icon: "/favicon.svg" },
|
|
};
|
|
|
|
// Sets the theme class before first paint to avoid a flash; reads the saved
|
|
// choice ("light"/"dark"/"system") or falls back to the OS preference.
|
|
const themeScript = `(function(){try{var t=localStorage.getItem("theme");var d=t==="dark"||((!t||t==="system")&&window.matchMedia("(prefers-color-scheme: dark)").matches);document.documentElement.classList.toggle("dark",d);}catch(e){}})();`;
|
|
|
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html lang="en" className={`${serif.variable} ${sans.variable}`} suppressHydrationWarning>
|
|
<head>
|
|
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
|
</head>
|
|
<body className="min-h-screen antialiased">{children}</body>
|
|
</html>
|
|
);
|
|
}
|