Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0a904a2
fix: resolve dark mode white flash on initial page load
AnkitRewar11 Mar 2, 2026
e4034dd
fix: add fallback background color to prevent white flash
AnkitRewar11 Mar 2, 2026
16be0d1
fix: correct setHtmlAttributes style format
AnkitRewar11 Mar 2, 2026
4c00b0f
fix: use correct dark theme color and inject head styles to prevent w…
AnkitRewar11 Mar 3, 2026
e238605
fix: set isDark default to true to prevent white flash on SSR
AnkitRewar11 Mar 3, 2026
852ec25
fix: dynamically apply correct SSR background to prevent theme flash
AnkitRewar11 Mar 3, 2026
dc10791
fix: revert isDark default to false to prevent dark flash
AnkitRewar11 Mar 3, 2026
cdd8e7d
fix: prevent FOUC using head CSS and class injection
AnkitRewar11 Mar 3, 2026
8fd5caa
Refactor theme handling in onRenderBody.js
AnkitRewar11 Mar 3, 2026
5f76bbf
Fix export statement for wrapPageElement
AnkitRewar11 Mar 7, 2026
9c62040
Add setPreBodyComponents to onRenderBody function
AnkitRewar11 Mar 7, 2026
9095d71
Change background color for dark mode and light mode
AnkitRewar11 Mar 7, 2026
3116aa9
Refactor theme management in onRenderBody.js
AnkitRewar11 Mar 7, 2026
322087f
Fix export statement for wrapPageElement
AnkitRewar11 Mar 7, 2026
2a16756
Improve comments and add dark theme styles
AnkitRewar11 Mar 7, 2026
5e7754e
Update theme handling in onRenderBody.js
AnkitRewar11 Mar 7, 2026
c91e7ac
Simplify theme detection and background color setting
AnkitRewar11 Mar 7, 2026
63cb585
Set default theme to dark mode
AnkitRewar11 Mar 7, 2026
b4d50da
fix: set dark mode as default to prevent white flash on initial load
AnkitRewar11 Mar 7, 2026
317d48d
Clean up comments in onRenderBody.js
AnkitRewar11 Mar 7, 2026
0aca758
Refactor StyledThemeProvider by cleaning up comments
AnkitRewar11 Mar 7, 2026
0626e11
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
5b275bf
Update ThemeManager.js
AnkitRewar11 Mar 12, 2026
a56ebe2
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 12, 2026
f3c5dcf
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
daea70b
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
c839a55
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
03365ec
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
624c764
Update onRenderBody.js
AnkitRewar11 Mar 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions fonts.css
Original file line number Diff line number Diff line change
@@ -1,144 +1,144 @@
/* FOUC fix — CSS loads before JS, so dark bg is set immediately */
html {
background-color: #121212;
}

html[data-theme="light"],
html[data-theme="light"] body {
background-color: #FFFFFF;
}

html[data-theme="dark"],
html[data-theme="dark"] body {
background-color: #121212;
}

body {
background-color: var(--background, #121212);
}

@font-face {
font-family: "Qanelas Soft Black";
src: url('./static/fonts/qanelas-soft/QanelasSoftBlack.otf') format('opentype');
font-weight: normal;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Black Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftBlackItalic.otf') format('opentype');
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Heavy";
src: url('./static/fonts/qanelas-soft/QanelasSoftHeavy.otf') format('opentype');
font-weight: 900;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Heavy Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftHeavyItalic.otf') format('opentype');
font-weight: 900;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft ExtraBold";
src: url('./static/fonts/qanelas-soft/QanelasSoftExtraBold.otf') format('opentype');
font-weight: 800;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft ExtraBold Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftExtraBoldItalic.otf') format('opentype');
font-weight: 800;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Bold";
src: url('./static/fonts/qanelas-soft/QanelasSoftBold.otf') format('opentype');
font-weight: bold;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Bold Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftBoldItalic.otf') format('opentype');
font-weight: bold;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft";
src: url('./static/fonts/qanelas-soft/QanelasSoftSemiBold.otf') format('opentype');
font-weight: 600;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft SemiBold Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftSemiBoldItalic.otf') format('opentype');
font-weight: 600;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Medium";
src: url('./static/fonts/qanelas-soft/QanelasSoftMedium.otf') format('opentype');
font-weight: 500;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Medium Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftMediumItalic.otf') format('opentype');
font-weight: 500;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft";
src: url('./static/fonts/qanelas-soft/QanelasSoftRegular.otf') format('opentype');
font-weight: 400;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Regular Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftRegularItalic.otf') format('opentype');
font-weight: 400;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Light";
src: url('./static/fonts/qanelas-soft/QanelasSoftLight.otf') format('opentype');
font-weight: 300;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Light Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftLightItalic.otf') format('opentype');
font-weight: 300;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft UltraLight";
src: url('./static/fonts/qanelas-soft/QanelasSoftUltraLight.otf') format('opentype');
font-weight: 200;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft UltraLight Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftUltraLightItalic.otf') format('opentype');
font-weight: 200;
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Thin";
src: url('./static/fonts/qanelas-soft/QanelasSoftThin.otf') format('opentype');
font-weight: 100;
font-display: swap;
}

@font-face {
font-family: "Qanelas Soft Thin Italic";
src: url('./static/fonts/qanelas-soft/QanelasSoftThinItalic.otf') format('opentype');
Expand All @@ -153,19 +153,17 @@
font-display: swap;
src: url("./static/fonts/open-sans/OpenSans-Regular.ttf") format("truetype");
}

@font-face {
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("./static/fonts/open-sans/OpenSans-SemiBold.ttf") format("truetype");
}

@font-face {
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("./static/fonts/open-sans/OpenSans-Bold.ttf") format("truetype");
}
}
91 changes: 39 additions & 52 deletions onRenderBody.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,44 @@
import React from "react";
import { DarkThemeKey, ThemeSetting } from "./src/theme/app/ThemeManager.js";
import lighttheme, { darktheme } from "./src/theme/app/themeStyles";

const themes = { light: lighttheme, dark: darktheme };

const MagicScriptTag = (props) => {
const codeToRunOnClient = `
(function() {
// 1. Keeps SYSTEM as the priority preference
const themeFromLocalStorage = localStorage.getItem('${DarkThemeKey}') || '${ThemeSetting.SYSTEM}';

// 2. We change the check to look for LIGHT mode explicitly
const systemLightModeSetting = () => window.matchMedia ? window.matchMedia('(prefers-color-scheme: light)') : null;

const isLightModeActive = () => {
return !!systemLightModeSetting()?.matches;
};

let colorMode;
switch (themeFromLocalStorage) {
case '${ThemeSetting.SYSTEM}':
// LOGIC CHANGE: If Light is active -> Light. Otherwise (Dark, No Preference, or Error) -> Dark.
colorMode = isLightModeActive() ? '${ThemeSetting.LIGHT}' : '${ThemeSetting.DARK}'
break
case '${ThemeSetting.DARK}':
case '${ThemeSetting.LIGHT}':
colorMode = themeFromLocalStorage
break
default:
// 3. Fallback to DARK in case of error
colorMode = '${ThemeSetting.DARK}'
}

const root = document.documentElement;
const iterate = (obj) => {
if (!obj) return;
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object') {
iterate(obj[key])
} else {
root.style.setProperty("--" + key, obj[key])
}
})
}
const parsedTheme = JSON.parse('${JSON.stringify(props.theme)}')
const theme = parsedTheme[colorMode]
iterate(theme)
root.style.setProperty('--initial-color-mode', colorMode);
})()
export const onRenderBody = ({ setHeadComponents }) => {
const scriptContent = `
(function() {
try {
var stored = localStorage.getItem('theme');
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
var isDark = stored === 'dark' || (stored === null && prefersDark);
var bg = isDark ? '#121212' : '#FFFFFF';
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
document.documentElement.style.backgroundColor = bg;
document.documentElement.style.setProperty('--initial-color-mode', isDark ? 'dark' : 'light');
} catch(e) {
document.documentElement.style.backgroundColor = '#121212';
}
document.documentElement.style.visibility = 'visible';
})();
`;
return <script dangerouslySetInnerHTML={{ __html: codeToRunOnClient }} />;
};

export const onRenderBody = ( { setPreBodyComponents }) => {
setPreBodyComponents(<MagicScriptTag key="theme-injection" theme={themes} />);
setHeadComponents([
<style
key="critical-theme-css"
dangerouslySetInnerHTML={{
__html: `
html {
visibility: hidden;
background-color: #121212;
}
html[data-theme="dark"] body {
background-color: #121212 !important;
}
html[data-theme="light"] body {
background-color: #FFFFFF !important;
}
`,
}}
/>,
<script
key="critical-theme-script"
dangerouslySetInnerHTML={{ __html: scriptContent }}
/>,
]);
};
7 changes: 1 addition & 6 deletions src/theme/app/StyledThemeProvider.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//uses isDark state to choose styled-component theme (in themeStyles.js)
//and use ThemeProvider to allow all styled components access to values via props.theme

import React, { useContext } from "react";
import { ThemeProvider } from "styled-components";
import { ThemeManagerContext } from "./ThemeManager";
Expand All @@ -12,11 +9,9 @@ export const StyledThemeProvider = (props) => {
const { children, darkTheme, lightTheme } = props;
const { isDark, didLoad } = useContext(ThemeManagerContext);

// For SSR, we need to provide a consistent theme initially
// This ensures the server and client render the same thing initially
const currentTheme = isDark ? darkTheme : lightTheme;
const theme = {
...(didLoad || !isBrowser ? currentTheme : transformTheme(currentTheme)),
...(currentTheme),
};

return (
Expand Down
Loading
Loading