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

View File

@@ -25,13 +25,13 @@ export default function ThemeDropdown() {
const apply = useCallback((t: Theme) => { const apply = useCallback((t: Theme) => {
const effective = t === "auto" ? (prefersDark() ? "dark" : "light") : t; const effective = t === "auto" ? (prefersDark() ? "dark" : "light") : t;
document.documentElement.setAttribute("data-bs-theme", effective); document.documentElement.setAttribute("data-bs-theme", effective);
}, []); }, []);
useEffect(() => { useEffect(() => {
setMounted(true); setMounted(true);
const v = getCookie(COOKIE); const v = getCookie(COOKIE);
console.log("Cookie:", v);
const initial: Theme = v === "light" || v === "dark" || v === "auto" ? (v as Theme) : "auto"; const initial: Theme = v === "light" || v === "dark" || v === "auto" ? (v as Theme) : "auto";
setTheme(initial); setTheme(initial);
// Important: apply immediately so “auto” reflects system after hydration // Important: apply immediately so “auto” reflects system after hydration

View File

@@ -77,7 +77,6 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
// }); // });
} else if (trimmedLine.startsWith('*')) { } else if (trimmedLine.startsWith('*')) {
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/); const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
console.log("NOTE MATCH",noteMatch);
if (noteMatch) { if (noteMatch) {
accessData.notes.push({ accessData.notes.push({
ref: noteMatch[1], ref: noteMatch[1],
@@ -89,8 +88,6 @@ export const parseDescriptionDefault = (reg: Register, description: string) => {
reg.text += `${line}\n`; reg.text += `${line}\n`;
continue; continue;
} }
// console.log("LINE",line);
console.log(line.match(/^\s+/), line);
if (line.match(/^\s+/) && accessData.operations.length > 0) { if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`; accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else { } else {

View File

@@ -24,7 +24,6 @@ export const parseDescriptionF0 = (reg: Register, description: string) => {
if(spaces_at_start == 2) { if(spaces_at_start == 2) {
if (trimmedLine.startsWith('*')) { if (trimmedLine.startsWith('*')) {
console.log("PARENT",trimmedLine);
const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/); const noteMatch = trimmedLine.match(/^(\*+)\s*(.*)/);
if (noteMatch) { if (noteMatch) {
reg.notes.push({ reg.notes.push({
@@ -88,7 +87,6 @@ export const parseDescriptionF0 = (reg: Register, description: string) => {
const footnoteMatch = bitDescription.match(/(\*+)$/); const footnoteMatch = bitDescription.match(/(\*+)$/);
let footnoteRef: string | undefined = undefined; let footnoteRef: string | undefined = undefined;
if (footnoteMatch) { if (footnoteMatch) {
console.log("FOOTNOTE",footnoteMatch);
footnoteRef = footnoteMatch[1]; footnoteRef = footnoteMatch[1];
bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim(); bitDescription = bitDescription.substring(0, bitDescription.length - footnoteRef.length).trim();
} }
@@ -112,7 +110,6 @@ export const parseDescriptionF0 = (reg: Register, description: string) => {
} }
} }
} else if (trimmedLine) { } else if (trimmedLine) {
console.log("LINE", trimmedLine);
if (line.match(/^\s+/) && accessData.operations.length > 0) { if (line.match(/^\s+/) && accessData.operations.length > 0) {
accessData.operations[accessData.operations.length - 1].description += `\n${line}`; accessData.operations[accessData.operations.length - 1].description += `\n${line}`;
} else { } else {
@@ -125,7 +122,6 @@ export const parseDescriptionF0 = (reg: Register, description: string) => {
} }
if (currentAccess) { if (currentAccess) {
detail[currentAccess] = accessData; detail[currentAccess] = accessData;
console.log("FINAL",detail,currentAccess);
} }
// Push the parsed detail into modes // Push the parsed detail into modes