scratch-gui / src /lib /themes /themePersistance.js
soiz1's picture
Upload folder using huggingface_hub
8fd7a1d verified
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
};