Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 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
7daec77
Update onRenderBody.js
AnkitRewar11 Mar 13, 2026
017f1db
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 13, 2026
cf3513f
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
31498d4
Update ThemeManager.js
AnkitRewar11 Mar 14, 2026
1a4d141
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 14, 2026
da0f2b8
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
23e099a
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
9b69325
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
540703d
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
5379bf5
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
b28a75c
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
1b5251e
Update ThemeManager.js
AnkitRewar11 Mar 14, 2026
b7782ab
Update StyledThemeProvider.js
AnkitRewar11 Mar 14, 2026
b87fa6f
Update ThemeManager.js
AnkitRewar11 Mar 14, 2026
a047e3e
Update StyledThemeProvider.js
AnkitRewar11 Mar 14, 2026
66946e4
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
c2554d1
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 14, 2026
56c3d1c
Update fonts.css
AnkitRewar11 Mar 14, 2026
1b78744
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
165cfdd
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
2c527e1
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
924ab63
Update fonts.css
AnkitRewar11 Mar 14, 2026
2cbe036
Update onRenderBody.js
AnkitRewar11 Mar 14, 2026
68cebea
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
c3b41ee
Update fonts.css
AnkitRewar11 Mar 15, 2026
982b5cc
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
f9967fd
Update fonts.css
AnkitRewar11 Mar 15, 2026
0eac38e
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
f2e4925
Update fonts.css
AnkitRewar11 Mar 15, 2026
3d55b3d
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
abbe4ec
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
91a4d78
Update onRenderBody.js
AnkitRewar11 Mar 15, 2026
7a6af92
Update StyledThemeProvider.js
AnkitRewar11 Mar 15, 2026
ad4ffff
Update ThemeManager.js
AnkitRewar11 Mar 15, 2026
9464fb8
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 16, 2026
7439582
Merge branch 'master' into fix/dark-mode-flicker
AnkitRewar11 Mar 17, 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
41 changes: 19 additions & 22 deletions fonts.css
Original file line number Diff line number Diff line change
@@ -1,144 +1,143 @@
html {
background: var(--background, #121212);
}

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

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

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

@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 +152,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");
}
}
109 changes: 61 additions & 48 deletions onRenderBody.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,70 @@
import React from "react";
import { DarkThemeKey, ThemeSetting } from "./src/theme/app/ThemeManager.js";
import { DarkThemeKey, ThemeSetting } from "./src/theme/app/ThemeManager";
import lighttheme, { darktheme } from "./src/theme/app/themeStyles";

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

const MagicScriptTag = ({ theme }) => {
const themeJSON = JSON.stringify(theme);

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AnkitRewar11 Any reason, why you removed this ? I think we cannot delete this CSS variable injection loop. Layer5's styled components rely on these --primary, --text, etc. variables being present in the HTML before React fully loads.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @YASHMAHAKAL! Thanks for pointing these out.

  1. if (!didLoad) return null I added this to prevent the white flash before the theme loads. My idea was to block rendering until the correct theme is available. I didn’t realize it would break Gatsby SSR and result in empty HTML. I’ll revert this.

  2. CSS variable injection loop I removed it thinking that the data-theme attribute and the backgroundColor inline style would be enough to prevent FOUC. But you’re right, styled components depend on those CSS variables being present before React hydrates, so I’ll restore it.

Also, apart from these changes, am I moving in the right direction?

})()
`;
(function() {
try {
var themeFromLocalStorage = localStorage.getItem('${DarkThemeKey}') || '${ThemeSetting.SYSTEM}';
var systemLightModeSetting = function() {
return window.matchMedia ? window.matchMedia('(prefers-color-scheme: light)') : null;
};
var isLightModeActive = function() {
var mql = systemLightModeSetting();
return mql ? mql.matches : false;
};

var colorMode;
switch (themeFromLocalStorage) {
case '${ThemeSetting.SYSTEM}':
colorMode = isLightModeActive() ? '${ThemeSetting.LIGHT}' : '${ThemeSetting.DARK}';
break;
case '${ThemeSetting.DARK}':
case '${ThemeSetting.LIGHT}':
colorMode = themeFromLocalStorage;
break;
default:
colorMode = '${ThemeSetting.DARK}';
}

var root = document.documentElement;
var parsedTheme = ${themeJSON};
var selectedTheme = parsedTheme[colorMode];

var iterate = function(obj) {
if (!obj) return;
Object.keys(obj).forEach(function(key) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
iterate(obj[key]);
} else {
root.style.setProperty('--' + key, obj[key]);
}
});
};

iterate(selectedTheme);
root.style.setProperty('--initial-color-mode', colorMode);
root.setAttribute('data-theme', colorMode);

window.__theme = colorMode;

} catch (e) {}
})();
`;

return <script dangerouslySetInnerHTML={{ __html: codeToRunOnClient }} />;
};

export const onRenderBody = ( { setPreBodyComponents }) => {
setPreBodyComponents(<MagicScriptTag key="theme-injection" theme={themes} />);
export const onRenderBody = ({ setHeadComponents }) => {
setHeadComponents([
<MagicScriptTag key="theme-initializer" theme={themes} />,
]);
};
10 changes: 1 addition & 9 deletions src/theme/app/StyledThemeProvider.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
//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";

// Safe check for browser environment
const isBrowser = typeof window !== "undefined";

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)),
...(didLoad ? currentTheme : transformTheme(currentTheme)),
};

return (
Expand All @@ -39,5 +33,3 @@ const transformTheme = (theme) => {

return newTheme;
};


Loading
Loading