anvilsign in

collin/strudel-claude

pre-demo / src / themes.js
1// Two independent theme axes:
2// • the site theme — the room's lighting (palette + haze), defined in style.css
3// as :root[data-site-theme='…'] blocks;
4// • the code theme — one of Strudel's CodeMirror themes, for syntax colors.
5// They are separate because the code pane deliberately drops its own background
6// and sits in the site's haze, so only a code theme's *colors* usually apply.
7import { themes as codeThemes, settings as codeThemeSettings } from '@strudel/codemirror';
8
9// Each site theme names the code theme whose syntax colors sit best in its light.
10export const SITE_THEMES = [
11 { id: 'haze', label: 'Purple haze', code: 'aura' },
12 { id: 'ember', label: 'Ember', code: 'monokai' },
13 { id: 'laser', label: 'Laser', code: 'strudelTheme' },
14 { id: 'blackout', label: 'Blackout', code: 'vscodeDark' },
15];
16
17export const CODE_THEMES = Object.keys(codeThemes).sort((a, b) => a.localeCompare(b));
18
19// A code theme that expects a light background can't sit in a dark haze.
20const isLight = (code) => Boolean(codeThemeSettings[code]?.light);
21
22const KEY = 'strudel-claude-theme';
23const DEFAULT = { site: 'haze', code: 'aura' };
24
25function load() {
26 try {
27 const saved = JSON.parse(localStorage.getItem(KEY) || '{}');
28 return {
29 site: SITE_THEMES.some((t) => t.id === saved.site) ? saved.site : DEFAULT.site,
30 code: CODE_THEMES.includes(saved.code) ? saved.code : DEFAULT.code,
31 };
32 } catch {
33 return { ...DEFAULT };
34 }
35}
36
37let current = load();
38export const currentTheme = () => ({ ...current });
39
40// `editor` is the StrudelMirror instance; it owns the CodeMirror theme extension.
41function apply(editor) {
42 document.documentElement.dataset.siteTheme = current.site;
43 document.body.classList.toggle('code-light', isLight(current.code));
44 editor.setTheme(current.code);
45 try {
46 localStorage.setItem(KEY, JSON.stringify(current));
47 } catch {
48 /* storage blocked — the theme still applies, it just won't persist */
49 }
50}
51
52export function setSiteTheme(editor, id) {
53 const site = SITE_THEMES.find((t) => t.id === id);
54 if (!site) return;
55 // Switching rigs also switches to that rig's paired code theme; picking a code
56 // theme afterwards overrides it.
57 current = { site: site.id, code: site.code };
58 apply(editor);
59}
60
61export function setCodeTheme(editor, code) {
62 if (!CODE_THEMES.includes(code)) return;
63 current = { ...current, code };
64 apply(editor);
65}
66
67export function initThemes(editor) {
68 apply(editor);
69}