| ... | @@ -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 |
| 18 | let listeners: Array<() => void> = []; | 18 | let listeners: Array<() => void> = []; |
| 19 | let lastSnapshot: ThemeSnapshot | null = null; | 19 | let lastSnapshot: ThemeSnapshot | null = null; |
| 20 | let lastDesktopTheme: Theme | null = null; | 20 | let lastDesktopTheme: Theme | null = null; |
| | 21 | let lastAppliedTheme: ThemeSnapshot | null = null; |
| 21 | | 22 | |
| 22 | function emitChange() { | 23 | function 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 | } |
| 29 | | 30 | |
| 30 | function getSystemDark() { | 31 | function 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 | } |
| 33 | | 38 | |
| 34 | function getStored(): Theme { | 39 | function getStored(): Theme { |
| ... | @@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() { | ... | @@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() { |
| 89 | | 94 | |
| 90 | function applyTheme(theme: Theme, suppressTransitions = false) { | 95 | function 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); |
| 149 | | 161 | |
| 150 | // Listen for system preference changes | 162 | // 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); |
| 157 | | 169 | |
| 158 | // Listen for storage changes from other tabs | 170 | // 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 { |
| 166 | | 178 | |
| 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 | } |