Let the server set the theme based on the cookie sent at request time, which should stop flashing

This commit is contained in:
2025-10-17 13:39:25 +01:00
parent 8e687fe176
commit 052b14ca40
4 changed files with 28 additions and 24 deletions

View File

@@ -1,4 +1,5 @@
import type { Metadata } from "next";
import { cookies } from "next/headers";
import "@/scss/nbn.scss";
import NavbarClient from "@/components/Navbar";
@@ -9,25 +10,35 @@ export const metadata: Metadata = {
formatDetection: { email: false, address: false, telephone: false },
};
const noFlashThemeScript = `
(function() {
try {
var cookieMatch = document.cookie.match(/(?:^|; )theme=([^;]+)/);
var stored = cookieMatch ? decodeURIComponent(cookieMatch[1]) : null;
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
var effective = (stored === 'light' || stored === 'dark') ? stored : (prefersDark ? 'dark' : 'light');
var el = document.documentElement;
if (el.getAttribute('data-bs-theme') !== effective) {
el.setAttribute('data-bs-theme', effective);
}
} catch(_) {}
})();`;
function themeInitScript() {
return `(function(){
try {
var cookie = document.cookie.split('; ').find(function(c){return c.indexOf('NBN-theme=')===0});
var value = cookie ? decodeURIComponent(cookie.split('=').slice(1).join('=')) : null;
var theme;
if (value === 'light' || value === 'dark') {
theme = value;
} else {
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
theme = prefersDark ? 'dark' : 'light';
}
var html = document.documentElement;
if (html.getAttribute('data-bs-theme') !== theme) {
html.setAttribute('data-bs-theme', theme);
}
} catch(_) {}
})();`;
}
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const cookieStore = await cookies();
const stored = cookieStore.get("NBN-theme")?.value;
const serverTheme = stored === "light" || stored === "dark" ? stored : "light";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<html lang="en" data-bs-theme={serverTheme}>
<head>
<script dangerouslySetInnerHTML={{ __html: noFlashThemeScript }} />
<script dangerouslySetInnerHTML={{ __html: themeInitScript() }} />
</head>
<body>
<NavbarClient />