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...@@ -18,6 +18,7 @@ const DYNAMIC_THEME_COLOR_SELECTOR = `meta[name="${THEME_COLOR_META_NAME}"][data
18let listeners: Array<() => void> = [];18let listeners: Array<() => void> = [];
19let lastSnapshot: ThemeSnapshot | null = null;19let lastSnapshot: ThemeSnapshot | null = null;
20let lastDesktopTheme: Theme | null = null;20let lastDesktopTheme: Theme | null = null;
21let lastAppliedTheme: ThemeSnapshot | null = null;
2122
22function emitChange() {23function emitChange() {
23 for (const listener of listeners) listener();24 for (const listener of listeners) listener();
...@@ -28,7 +29,11 @@ function hasThemeStorage() {...@@ -28,7 +29,11 @@ function hasThemeStorage() {
28}29}
2930
30function getSystemDark() {31function 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 );
32}37}
3338
34function getStored(): Theme {39function getStored(): Theme {
...@@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() {...@@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() {
8994
90function applyTheme(theme: Theme, suppressTransitions = false) {95function applyTheme(theme: Theme, suppressTransitions = false) {
91 if (typeof document === "undefined" || typeof window === "undefined") return;96 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
92 if (suppressTransitions) {103 if (suppressTransitions) {
93 document.documentElement.classList.add("no-transitions");104 document.documentElement.classList.add("no-transitions");
94 }105 }
95 const isDark = theme === "dark" || (theme === "system" && getSystemDark());106 const isDark = theme === "dark" || (theme === "system" && systemDark);
96 document.documentElement.classList.toggle("dark", isDark);107 document.documentElement.classList.toggle("dark", isDark);
108 lastAppliedTheme = { theme, systemDark };
97 syncBrowserChromeTheme();109 syncBrowserChromeTheme();
98 syncDesktopTheme(theme);110 syncDesktopTheme(theme);
99 if (suppressTransitions) {111 if (suppressTransitions) {
...@@ -148,12 +160,12 @@ function subscribe(listener: () => void): () => void {...@@ -148,12 +160,12 @@ function subscribe(listener: () => void): () => void {
148 listeners.push(listener);160 listeners.push(listener);
149161
150 // Listen for system preference changes162 // Listen for system preference changes
151 const mq = window.matchMedia(MEDIA_QUERY);163 const mq = typeof window.matchMedia === "function" ? window.matchMedia(MEDIA_QUERY) : null;
152 const handleChange = () => {164 const handleChange = () => {
153 if (getStored() === "system") applyTheme("system", true);165 if (getStored() === "system") applyTheme("system", true);
154 emitChange();166 emitChange();
155 };167 };
156 mq.addEventListener("change", handleChange);168 mq?.addEventListener("change", handleChange);
157169
158 // Listen for storage changes from other tabs170 // Listen for storage changes from other tabs
159 const handleStorage = (e: StorageEvent) => {171 const handleStorage = (e: StorageEvent) => {
...@@ -166,7 +178,7 @@ function subscribe(listener: () => void): () => void {...@@ -166,7 +178,7 @@ function subscribe(listener: () => void): () => void {
166178
167 return () => {179 return () => {
168 listeners = listeners.filter((l) => l !== listener);180 listeners = listeners.filter((l) => l !== listener);
169 mq.removeEventListener("change", handleChange);181 mq?.removeEventListener("change", handleChange);
170 window.removeEventListener("storage", handleStorage);182 window.removeEventListener("storage", handleStorage);
171 };183 };
172}184}