Spaces:
Runtime error
Runtime error
import {BLOCKS_CUSTOM, Theme} from '.'; | |
import {customThemeManager, CustomTheme} from './custom-themes.js'; | |
const matchMedia = query => (window.matchMedia ? window.matchMedia(query) : null); | |
const PREFERS_HIGH_CONTRAST_QUERY = matchMedia('(prefers-contrast: more)'); | |
const PREFERS_DARK_QUERY = matchMedia('(prefers-color-scheme: dark)'); | |
const STORAGE_KEY = 'tw:theme'; | |
/** | |
* @returns {Theme} detected theme | |
*/ | |
const systemPreferencesTheme = () => { | |
if (PREFERS_HIGH_CONTRAST_QUERY && PREFERS_HIGH_CONTRAST_QUERY.matches) { | |
return Theme.highContrast; | |
} | |
if (PREFERS_DARK_QUERY && PREFERS_DARK_QUERY.matches) { | |
return Theme.dark; | |
} | |
return Theme.light; | |
}; | |
/** | |
* @param {function} onChange callback; no guarantees about arguments | |
* @returns {function} call to remove event listeners to prevent memory leak | |
*/ | |
const onSystemPreferenceChange = onChange => { | |
if ( | |
!PREFERS_HIGH_CONTRAST_QUERY || | |
!PREFERS_DARK_QUERY || | |
// Some old browsers don't support addEventListener on media queries | |
!PREFERS_HIGH_CONTRAST_QUERY.addEventListener || | |
!PREFERS_DARK_QUERY.addEventListener | |
) { | |
return () => {}; | |
} | |
PREFERS_HIGH_CONTRAST_QUERY.addEventListener('change', onChange); | |
PREFERS_DARK_QUERY.addEventListener('change', onChange); | |
return () => { | |
PREFERS_HIGH_CONTRAST_QUERY.removeEventListener('change', onChange); | |
PREFERS_DARK_QUERY.removeEventListener('change', onChange); | |
}; | |
}; | |
/** | |
* @returns {Theme} the theme | |
*/ | |
const detectTheme = () => { | |
const systemPreferences = systemPreferencesTheme(); | |
try { | |
const local = localStorage.getItem(STORAGE_KEY); | |
// Migrate legacy preferences | |
if (local === 'dark') { | |
return Theme.dark; | |
} | |
if (local === 'light') { | |
return Theme.light; | |
} | |
const parsed = JSON.parse(local); | |
// Check if this is a custom theme | |
if (parsed.isCustom && parsed.customThemeUuid) { | |
const customTheme = customThemeManager.getTheme(parsed.customThemeUuid); | |
if (customTheme) { | |
return customTheme; | |
} | |
// Fall back to system preferences if custom theme not found | |
console.warn(`Custom theme ${parsed.customThemeUuid} not found, falling back to system preferences`); | |
} | |
// Any invalid values in storage will be handled by Theme itself | |
const wallpaper = parsed.wallpaper || { url: '', opacity: 0.3, darkness: 0, gridVisible: true, history: [] }; | |
// Add backward compatibility for gridVisible | |
if (typeof wallpaper.gridVisible === 'undefined') { | |
wallpaper.gridVisible = true; | |
} | |
return new Theme( | |
parsed.accent || systemPreferences.accent, | |
parsed.gui || systemPreferences.gui, | |
parsed.blocks || systemPreferences.blocks, | |
parsed.menuBarAlign || systemPreferences.menuBarAlign, | |
wallpaper, | |
parsed.fonts || { system: [], google: [], history: [] } | |
); | |
} catch (e) { | |
// ignore | |
} | |
return systemPreferences; | |
}; | |
/** | |
* @param {Theme} theme the theme | |
*/ | |
const persistTheme = theme => { | |
const systemPreferences = systemPreferencesTheme(); | |
const nonDefaultSettings = {}; | |
// Handle custom themes differently | |
if (theme instanceof CustomTheme) { | |
nonDefaultSettings.customThemeUuid = theme.uuid; | |
nonDefaultSettings.isCustom = true; | |
} else { | |
if (theme.accent !== systemPreferences.accent) { | |
nonDefaultSettings.accent = theme.accent; | |
} | |
if (theme.gui !== systemPreferences.gui) { | |
nonDefaultSettings.gui = theme.gui; | |
} | |
// custom blocks are managed by addon at runtime, don't save here | |
if (theme.blocks !== systemPreferences.blocks && theme.blocks !== BLOCKS_CUSTOM) { | |
nonDefaultSettings.blocks = theme.blocks; | |
} | |
if (theme.menuBarAlign !== systemPreferences.menuBarAlign) { | |
nonDefaultSettings.menuBarAlign = theme.menuBarAlign; | |
} | |
// Always save wallpaper settings if they exist | |
if (theme.wallpaper && (theme.wallpaper.url || theme.wallpaper.history.length > 0)) { | |
nonDefaultSettings.wallpaper = theme.wallpaper; | |
} | |
// Always save fonts settings if they exist | |
if (theme.fonts && (theme.fonts.system.length > 0 || theme.fonts.google.length > 0 || theme.fonts.history.length > 0)) { | |
nonDefaultSettings.fonts = theme.fonts; | |
} | |
} | |
if (Object.keys(nonDefaultSettings).length === 0) { | |
try { | |
localStorage.removeItem(STORAGE_KEY); | |
} catch (e) { | |
// ignore | |
} | |
} else { | |
try { | |
localStorage.setItem(STORAGE_KEY, JSON.stringify(nonDefaultSettings)); | |
} catch (e) { | |
// ignore | |
} | |
} | |
}; | |
export { | |
onSystemPreferenceChange, | |
detectTheme, | |
persistTheme | |
}; | |