@@ -15,6 +15,7 @@ const STORAGE_KEY = "okcode:theme";
1515const COLOR_THEME_STORAGE_KEY = "okcode:color-theme" ;
1616const FONT_FAMILY_STORAGE_KEY = "okcode:font-family" ;
1717const MEDIA_QUERY = "(prefers-color-scheme: dark)" ;
18+ const canUseDOM = typeof window !== "undefined" && typeof document !== "undefined" ;
1819
1920const SERVER_SNAPSHOT : ThemeSnapshot = {
2021 theme : "system" ,
@@ -30,18 +31,46 @@ function emitChange() {
3031 for ( const listener of listeners ) listener ( ) ;
3132}
3233
34+ function safeLocalStorageGet ( key : string ) : string | null {
35+ if ( ! canUseDOM ) {
36+ return null ;
37+ }
38+
39+ try {
40+ return window . localStorage . getItem ( key ) ;
41+ } catch {
42+ return null ;
43+ }
44+ }
45+
46+ function safeLocalStorageSet ( key : string , value : string ) {
47+ if ( ! canUseDOM ) {
48+ return ;
49+ }
50+
51+ try {
52+ window . localStorage . setItem ( key , value ) ;
53+ } catch {
54+ // Ignore storage failures and keep the in-memory theme usable.
55+ }
56+ }
57+
3358function getSystemDark ( ) : boolean {
59+ if ( ! canUseDOM ) {
60+ return false ;
61+ }
62+
3463 return window . matchMedia ( MEDIA_QUERY ) . matches ;
3564}
3665
3766function getStored ( ) : Theme {
38- const raw = localStorage . getItem ( STORAGE_KEY ) ;
67+ const raw = safeLocalStorageGet ( STORAGE_KEY ) ;
3968 if ( raw === "light" || raw === "dark" || raw === "system" ) return raw ;
4069 return "system" ;
4170}
4271
4372function getStoredColorTheme ( ) : ColorTheme {
44- const raw = localStorage . getItem ( COLOR_THEME_STORAGE_KEY ) ;
73+ const raw = safeLocalStorageGet ( COLOR_THEME_STORAGE_KEY ) ;
4574 const normalized = raw === "cotton-candy" ? "purple-stuff" : raw ;
4675
4776 if (
@@ -52,8 +81,8 @@ function getStoredColorTheme(): ColorTheme {
5281 normalized === "hot-tamale" ||
5382 normalized === "custom"
5483 ) {
55- if ( normalized !== raw ) {
56- localStorage . setItem ( COLOR_THEME_STORAGE_KEY , normalized ) ;
84+ if ( normalized !== raw && raw !== null ) {
85+ safeLocalStorageSet ( COLOR_THEME_STORAGE_KEY , normalized ) ;
5786 }
5887
5988 return normalized ;
@@ -62,7 +91,7 @@ function getStoredColorTheme(): ColorTheme {
6291}
6392
6493function getStoredFontFamily ( ) : FontFamily {
65- const raw = localStorage . getItem ( FONT_FAMILY_STORAGE_KEY ) ;
94+ const raw = safeLocalStorageGet ( FONT_FAMILY_STORAGE_KEY ) ;
6695 if ( raw === "dm-sans" || raw === "inter" || raw === "plus-jakarta-sans" ) {
6796 return raw ;
6897 }
@@ -167,12 +196,18 @@ function syncDesktopTheme(theme: Theme) {
167196}
168197
169198// Initialize custom theme + overrides on module load
170- initCustomTheme ( ) ;
199+ if ( canUseDOM ) {
200+ initCustomTheme ( ) ;
171201
172- // Apply immediately on module load to prevent flash
173- applyTheme ( getStored ( ) ) ;
202+ // Apply immediately on module load to prevent flash
203+ applyTheme ( getStored ( ) ) ;
204+ }
174205
175206function getSnapshot ( ) : ThemeSnapshot {
207+ if ( ! canUseDOM ) {
208+ return SERVER_SNAPSHOT ;
209+ }
210+
176211 const theme = getStored ( ) ;
177212 const systemDark = theme === "system" ? getSystemDark ( ) : false ;
178213 const colorTheme = getStoredColorTheme ( ) ;
@@ -197,6 +232,10 @@ function getServerSnapshot(): ThemeSnapshot {
197232}
198233
199234function subscribe ( listener : ( ) => void ) : ( ) => void {
235+ if ( ! canUseDOM ) {
236+ return ( ) => { } ;
237+ }
238+
200239 listeners . push ( listener ) ;
201240
202241 // Listen for system preference changes
@@ -237,19 +276,19 @@ export function useTheme() {
237276 theme === "system" ? ( snapshot . systemDark ? "dark" : "light" ) : theme ;
238277
239278 const setTheme = useCallback ( ( next : Theme ) => {
240- localStorage . setItem ( STORAGE_KEY , next ) ;
279+ safeLocalStorageSet ( STORAGE_KEY , next ) ;
241280 applyTheme ( next , true ) ;
242281 emitChange ( ) ;
243282 } , [ ] ) ;
244283
245284 const setColorTheme = useCallback ( ( next : ColorTheme ) => {
246- localStorage . setItem ( COLOR_THEME_STORAGE_KEY , next ) ;
285+ safeLocalStorageSet ( COLOR_THEME_STORAGE_KEY , next ) ;
247286 applyTheme ( getStored ( ) , true ) ;
248287 emitChange ( ) ;
249288 } , [ ] ) ;
250289
251290 const setFontFamily = useCallback ( ( next : FontFamily ) => {
252- localStorage . setItem ( FONT_FAMILY_STORAGE_KEY , next ) ;
291+ safeLocalStorageSet ( FONT_FAMILY_STORAGE_KEY , next ) ;
253292 applyFont ( next ) ;
254293 emitChange ( ) ;
255294 } , [ ] ) ;
0 commit comments