authorgravatar for mjc@kernel.orgMika Cohen <mjc@kernel.org> 2026-06-18 23:46:12-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-19 05:46:12+00:00
log20f37f367a146fb4118bd0f0182336f4ab8c6ac8
tree4338a2621fa9e11b2e0968feb7c3ffa01a5d57a2
parent804d44cfb153d264e4abc9adb9c958dd6720cfa5
signature Signed by PGP key B5690EEEBB952194

Avoid repeated theme DOM sync during startup (#2779)

Co-authored-by: Julius Marminge <jmarminge@gmail.com>

1 files changed, 17 insertions(+), 5 deletions(-)

apps/web/src/hooks/useTheme.ts+17-5
......@@ -18,6 +18,7 @@ const DYNAMIC_THEME_COLOR_SELECTOR = `meta[name="${THEME_COLOR_META_NAME}"][data
1818let listeners: Array<() => void> = [];
1919let lastSnapshot: ThemeSnapshot | null = null;
2020let lastDesktopTheme: Theme | null = null;
21let lastAppliedTheme: ThemeSnapshot | null = null;
2122
2223function emitChange() {
2324 for (const listener of listeners) listener();
......@@ -28,7 +29,11 @@ function hasThemeStorage() {
2829}
2930
3031function getSystemDark() {
31 return typeof window !== "undefined" && window.matchMedia(MEDIA_QUERY).matches;
32 return (
33 typeof window !== "undefined" &&
34 typeof window.matchMedia === "function" &&
35 window.matchMedia(MEDIA_QUERY).matches
36 );
3237}
3338
3439function getStored(): Theme {
......@@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() {
8994
9095function applyTheme(theme: Theme, suppressTransitions = false) {
9196 if (typeof document === "undefined" || typeof window === "undefined") return;
97 const systemDark = theme === "system" ? getSystemDark() : false;
98 if (lastAppliedTheme?.theme === theme && lastAppliedTheme.systemDark === systemDark) {
99 syncDesktopTheme(theme);
100 return;
101 }
102
92103 if (suppressTransitions) {
93104 document.documentElement.classList.add("no-transitions");
94105 }
95 const isDark = theme === "dark" || (theme === "system" && getSystemDark());
106 const isDark = theme === "dark" || (theme === "system" && systemDark);
96107 document.documentElement.classList.toggle("dark", isDark);
108 lastAppliedTheme = { theme, systemDark };
97109 syncBrowserChromeTheme();
98110 syncDesktopTheme(theme);
99111 if (suppressTransitions) {
......@@ -148,12 +160,12 @@ function subscribe(listener: () => void): () => void {
148160 listeners.push(listener);
149161
150162 // Listen for system preference changes
151 const mq = window.matchMedia(MEDIA_QUERY);
163 const mq = typeof window.matchMedia === "function" ? window.matchMedia(MEDIA_QUERY) : null;
152164 const handleChange = () => {
153165 if (getStored() === "system") applyTheme("system", true);
154166 emitChange();
155167 };
156 mq.addEventListener("change", handleChange);
168 mq?.addEventListener("change", handleChange);
157169
158170 // Listen for storage changes from other tabs
159171 const handleStorage = (e: StorageEvent) => {
......@@ -166,7 +178,7 @@ function subscribe(listener: () => void): () => void {
166178
167179 return () => {
168180 listeners = listeners.filter((l) => l !== listener);
169 mq.removeEventListener("change", handleChange);
181 mq?.removeEventListener("change", handleChange);
170182 window.removeEventListener("storage", handleStorage);
171183 };
172184}