feat: futuristic theme ladder + stacked landing banner

Add three opt-in dark themes (BooCode+, BooCode Classic, BooCode
Override) plus an in-place Ember polish, on a class-scoped effects
engine: matrix rain, a neon grid field, and frosted glass, all gated
by a localStorage "Animated background" toggle and prefers-reduced-
motion. Extend the server theme_id whitelist so the new ids persist,
and replace the Home landing wordmark with the stacked mascot +
wordmark banner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 14:16:59 +00:00
parent d10d79399b
commit fc4fbb0b7e
21 changed files with 1822 additions and 30 deletions

View File

@@ -7,23 +7,29 @@
<script>
// themes-v1 FOUC guard: read the last-applied theme from localStorage
// and stamp the class on <html> before React mounts. Falls back to
// obsidian + dark when no cache. Light-only themes (ivory, chalk) with
// a dark mode pref fall back to obsidian dark — mirrors the rule in
// lib/theme.ts effectiveThemeId().
// ember + dark when no cache. Light-only themes (ivory, chalk) with a
// dark mode pref fall back to ember dark — mirrors effectiveThemeId().
// Dark-only themes (boocode-classic, boocode-override) always get the
// dark class regardless of resolved system mode — mirrors applyTheme().
(function () {
try {
var t = JSON.parse(localStorage.getItem('boocode.theme') || '{}');
var id = t.id || 'obsidian';
var id = t.id || 'ember';
var mode = t.mode || 'dark';
if (mode === 'system') {
mode = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
// Light-only themes in dark mode → fall back to ember dark.
if ((id === 'ivory' || id === 'chalk') && mode === 'dark') {
id = 'obsidian';
id = 'ember';
}
// Dark-only themes: force dark class regardless of system preference.
if (id === 'boocode-classic' || id === 'boocode-override') {
mode = 'dark';
}
document.documentElement.className = 'theme-' + id + (mode === 'dark' ? ' dark' : '');
} catch (e) {
document.documentElement.className = 'theme-obsidian dark';
document.documentElement.className = 'theme-ember dark';
}
})();
</script>