leistungsbilanz-ts/src/app/layout.tsx
Julian Appel 64ccd1f829 Add dark mode toggle in the sidebar
Adds a persistent dark/light theme toggle (localStorage +
data-bs-theme on <html>) so it applies globally, including the
circuit editor route which has no visible sidebar. An inline
beforeInteractive script sets the theme before hydration to avoid a
flash of the wrong theme.

Bootstrap components pick up data-bs-theme automatically; the custom
circuit-grid CSS previously used ~150 hardcoded hex colors, all
converted to semantic tokens in globals.css with light/dark values.

Verified with a headless-browser pass across the project list, project
detail page, circuit editor, project-device drawer and a settings
modal in both themes; no console errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 21:56:21 +02:00

43 lines
1.3 KiB
TypeScript

import type { Metadata } from "next";
import Script from "next/script";
import "bootstrap/dist/css/bootstrap.min.css";
import "./globals.css";
import { AppShell } from "../frontend/components/AppShell";
export const metadata: Metadata = {
title: "Leistungsbilanz",
description: "Leistungsbilanz für elektrische Verbraucher und Stromkreislisten",
};
// Keep this key literal in sync with THEME_STORAGE_KEY in ThemeToggle.tsx.
// It must stay inline (not imported) so it runs before hydration and never
// flashes the wrong theme on load.
const THEME_INIT_SCRIPT = `
(function () {
try {
var stored = localStorage.getItem("leistungsbilanz:theme");
var theme =
stored === "dark" || stored === "light"
? stored
: window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
document.documentElement.setAttribute("data-bs-theme", theme);
} catch (error) {
// Storage/matchMedia unavailable: fall back to the default light theme.
}
})();
`;
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="de" suppressHydrationWarning>
<body>
<Script id="theme-init" strategy="beforeInteractive">
{THEME_INIT_SCRIPT}
</Script>
<AppShell>{children}</AppShell>
</body>
</html>
);
}