Files
Psychotoxical-psysonic/public/startup-splash-preflight.js
T
cucadmuh 5167d8f49e feat(ui): themed startup splash with deferred window show (#1030)
* feat(ui): add themed startup splash with deferred window show

Show a theme-aware loading splash before the Vite bundle mounts, hide the
native window until it paints, and use per-theme logo gradient colors.

* docs: note startup splash in CHANGELOG and credits for PR #1030

* docs: attribute PR #1030 startup splash to cucadmuh
2026-06-08 12:59:07 +03:00

162 lines
5.2 KiB
JavaScript

/**
* Synchronous startup splash theme (before the Vite bundle loads).
* Keep palette ids/hex in sync with `src/config/startupSplashPalettes.ts`.
*/
(function startupSplashPreflight() {
var THEME_KEY = 'psysonic_theme';
var INSTALLED_KEY = 'psysonic_installed_themes';
var DEFAULT = {
bg: '#1e1e2e',
text: '#cdd6f4',
muted: '#a6adc8',
accent: '#cba6f7',
track: '#313244',
logoStart: '#cba6f7',
logoEnd: '#89b4fa',
};
var BUILTIN = {
mocha: DEFAULT,
latte: {
bg: '#eff1f5',
text: '#4c4f69',
muted: '#6c6f85',
accent: '#8839ef',
track: '#ccd0da',
logoStart: '#8839ef',
logoEnd: '#1e66f5',
},
'kanagawa-wave': {
bg: '#1F1F28',
text: '#DCD7BA',
muted: '#727169',
accent: '#7E9CD8',
track: '#2A2A37',
logoStart: '#7E9CD8',
logoEnd: '#957FB8',
},
'stark-hud': {
bg: '#0b0f15',
text: '#e0f7fa',
muted: '#7da5aa',
accent: '#00f2ff',
track: '#141b24',
logoStart: '#00f2ff',
logoEnd: '#7df9ff',
},
'vision-dark': {
bg: '#0d0b12',
text: '#f2eef8',
muted: '#a6a2b8',
accent: '#ffd700',
track: '#16131e',
logoStart: '#ffd700',
logoEnd: '#a07af8',
},
'vision-navy': {
bg: '#0a1628',
text: '#e8eef8',
muted: '#9caac2',
accent: '#ffd700',
track: '#12213a',
logoStart: '#ffd700',
logoEnd: '#a07af8',
},
};
function readCssVar(css, name) {
var match = css.match(new RegExp(name + '\\s*:\\s*([^;]+);'));
var value = match && match[1] ? match[1].trim() : '';
return value || null;
}
function resolveScheduledTheme(state) {
if (!state.enableThemeScheduler) return state.theme;
var now = new Date();
var nowMins = now.getHours() * 60 + now.getMinutes();
var dayParts = state.timeDayStart.split(':').map(Number);
var nightParts = state.timeNightStart.split(':').map(Number);
var dayMins = dayParts[0] * 60 + dayParts[1];
var nightMins = nightParts[0] * 60 + nightParts[1];
var isDay = dayMins < nightMins
? nowMins >= dayMins && nowMins < nightMins
: nowMins >= dayMins || nowMins < nightMins;
return isDay ? state.themeDay : state.themeNight;
}
function readThemeState() {
try {
var raw = localStorage.getItem(THEME_KEY);
if (!raw) return null;
var parsed = JSON.parse(raw);
var s = parsed && parsed.state;
if (!s) return null;
return {
enableThemeScheduler: !!s.enableThemeScheduler,
theme: String(s.theme || 'mocha'),
themeDay: String(s.themeDay || 'latte'),
themeNight: String(s.themeNight || 'mocha'),
timeDayStart: String(s.timeDayStart || '07:00'),
timeNightStart: String(s.timeNightStart || '19:00'),
};
} catch (_err) {
return null;
}
}
function readInstalledThemes() {
try {
var raw = localStorage.getItem(INSTALLED_KEY);
if (!raw) return [];
var parsed = JSON.parse(raw);
var themes = parsed && parsed.state && parsed.state.themes;
return Array.isArray(themes) ? themes : [];
} catch (_err) {
return [];
}
}
function paletteForTheme(themeId, installedThemes) {
if (BUILTIN[themeId]) return BUILTIN[themeId];
for (var i = 0; i < installedThemes.length; i += 1) {
var theme = installedThemes[i];
if (!theme || theme.id !== themeId || !theme.css) continue;
var bg = readCssVar(theme.css, '--bg-app');
var accent = readCssVar(theme.css, '--accent');
if (!bg || !accent) break;
var logoStart = readCssVar(theme.css, '--logo-color-start') || accent;
var logoEnd = readCssVar(theme.css, '--logo-color-end')
|| readCssVar(theme.css, '--accent-2')
|| accent;
return {
bg: bg,
text: readCssVar(theme.css, '--text-primary') || readCssVar(theme.css, '--ctp-text') || DEFAULT.text,
muted: readCssVar(theme.css, '--text-muted') || readCssVar(theme.css, '--ctp-subtext0') || DEFAULT.muted,
accent: accent,
track: readCssVar(theme.css, '--bg-card') || readCssVar(theme.css, '--border-subtle') || DEFAULT.track,
logoStart: logoStart,
logoEnd: logoEnd,
};
}
return DEFAULT;
}
function applyPalette(themeId, palette) {
var root = document.documentElement;
root.setAttribute('data-theme', themeId);
root.style.setProperty('--startup-splash-bg', palette.bg);
root.style.setProperty('--startup-splash-text', palette.text);
root.style.setProperty('--startup-splash-muted', palette.muted);
root.style.setProperty('--startup-splash-accent', palette.accent);
root.style.setProperty('--startup-splash-track', palette.track);
root.style.setProperty('--startup-splash-logo-start', palette.logoStart);
root.style.setProperty('--startup-splash-logo-end', palette.logoEnd);
root.style.background = palette.bg;
if (document.body) document.body.style.background = palette.bg;
}
var persisted = readThemeState();
var themeId = persisted ? resolveScheduledTheme(persisted) : 'mocha';
var palette = paletteForTheme(themeId, readInstalledThemes());
applyPalette(themeId, palette);
})();