@@ -8,25 +8,36 @@ type ThemeSnapshot = {
88
99const STORAGE_KEY = "t3code:theme" ;
1010const MEDIA_QUERY = "(prefers-color-scheme: dark)" ;
11+ const DEFAULT_THEME_SNAPSHOT : ThemeSnapshot = {
12+ theme : "system" ,
13+ systemDark : false ,
14+ } ;
1115
1216let listeners : Array < ( ) => void > = [ ] ;
1317let lastSnapshot : ThemeSnapshot | null = null ;
1418let lastDesktopTheme : Theme | null = null ;
19+
1520function emitChange ( ) {
1621 for ( const listener of listeners ) listener ( ) ;
1722}
1823
19- function getSystemDark ( ) : boolean {
20- return window . matchMedia ( MEDIA_QUERY ) . matches ;
24+ function hasThemeStorage ( ) {
25+ return typeof window !== "undefined" && typeof localStorage !== "undefined" ;
26+ }
27+
28+ function getSystemDark ( ) {
29+ return typeof window !== "undefined" && window . matchMedia ( MEDIA_QUERY ) . matches ;
2130}
2231
2332function getStored ( ) : Theme {
33+ if ( ! hasThemeStorage ( ) ) return DEFAULT_THEME_SNAPSHOT . theme ;
2434 const raw = localStorage . getItem ( STORAGE_KEY ) ;
2535 if ( raw === "light" || raw === "dark" || raw === "system" ) return raw ;
26- return "system" ;
36+ return DEFAULT_THEME_SNAPSHOT . theme ;
2737}
2838
2939function applyTheme ( theme : Theme , suppressTransitions = false ) {
40+ if ( typeof document === "undefined" || typeof window === "undefined" ) return ;
3041 if ( suppressTransitions ) {
3142 document . documentElement . classList . add ( "no-transitions" ) ;
3243 }
@@ -44,6 +55,7 @@ function applyTheme(theme: Theme, suppressTransitions = false) {
4455}
4556
4657function syncDesktopTheme ( theme : Theme ) {
58+ if ( typeof window === "undefined" ) return ;
4759 const bridge = window . desktopBridge ;
4860 if ( ! bridge || lastDesktopTheme === theme ) {
4961 return ;
@@ -58,9 +70,12 @@ function syncDesktopTheme(theme: Theme) {
5870}
5971
6072// Apply immediately on module load to prevent flash
61- applyTheme ( getStored ( ) ) ;
73+ if ( typeof document !== "undefined" && hasThemeStorage ( ) ) {
74+ applyTheme ( getStored ( ) ) ;
75+ }
6276
6377function getSnapshot ( ) : ThemeSnapshot {
78+ if ( ! hasThemeStorage ( ) ) return DEFAULT_THEME_SNAPSHOT ;
6479 const theme = getStored ( ) ;
6580 const systemDark = theme === "system" ? getSystemDark ( ) : false ;
6681
@@ -72,7 +87,12 @@ function getSnapshot(): ThemeSnapshot {
7287 return lastSnapshot ;
7388}
7489
90+ function getServerSnapshot ( ) {
91+ return DEFAULT_THEME_SNAPSHOT ;
92+ }
93+
7594function subscribe ( listener : ( ) => void ) : ( ) => void {
95+ if ( typeof window === "undefined" ) return ( ) => { } ;
7696 listeners . push ( listener ) ;
7797
7898 // Listen for system preference changes
@@ -100,13 +120,14 @@ function subscribe(listener: () => void): () => void {
100120}
101121
102122export function useTheme ( ) {
103- const snapshot = useSyncExternalStore ( subscribe , getSnapshot ) ;
123+ const snapshot = useSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
104124 const theme = snapshot . theme ;
105125
106126 const resolvedTheme : "light" | "dark" =
107127 theme === "system" ? ( snapshot . systemDark ? "dark" : "light" ) : theme ;
108128
109129 const setTheme = useCallback ( ( next : Theme ) => {
130+ if ( ! hasThemeStorage ( ) ) return ;
110131 localStorage . setItem ( STORAGE_KEY , next ) ;
111132 applyTheme ( next , true ) ;
112133 emitChange ( ) ;
0 commit comments