Files
openidea/public/boot.js
l0ng-aiandbghtyu b424cb32a8 feat(themes): Solarized and One theme plugins; plugin themes from the first frame
Add two contribution-only theme plugins, each with a light and a dark theme
that sets every UI token plus an editor colour scheme with syntax, editor
and terminal ANSI colours:

- plugins/theme-solarized: Solarized Light, Solarized Dark
- plugins/theme-one: One Light, One Dark (Atom One, original HSL values)

They replace the partial theme-solarized-dark sample. Each package ships
the MIT notice of its palette in LICENSE, which is now copied on install
with the files the manifest references. scripts/theme checks every theme
plugin in plugins/ against the token list of tokens.css.

Theme handling that any theme benefits from:

- Start-up: boot.js restores the selected plugin theme's stylesheet and the
  last resolved frame, text and accent colours before any CSS loads, so the
  splash and workbench no longer show the built-in theme until the plugin
  host answers. The UI keeps the boot theme until the first plugin list,
  and the list now waits for the initial plugin load.
- Native windows: the UI reports the plugin theme's resolved frame colour,
  which the plugin host persists and new project windows open in.
- hsl(), color-mix() and var() tokens are resolved to RGB for Tauri's window
  background, the native Settings window (hex) and Mermaid diagrams.
- Mermaid, the terminal and the editor colour scheme follow switches between
  plugin themes of the same light / dark base; an explicit editor scheme
  now replaces a plugin theme's editor colours.

Supersedes #85.

Co-authored-by: bghtyu <3931591+bghtyu@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
2026-10-27 17:50:44 +08:00

39 lines
1.9 KiB
JavaScript

/* global document, localStorage, window */
// Runs before the app's CSS loads: restores the last theme (theme.ts stores it)
// so a new window starts in it instead of flashing the light default.
// An external file because the CSP forbids inline scripts.
try {
const root = document.documentElement;
const addStyle = (id, css) => {
const style = document.createElement("style");
style.id = id;
style.textContent = css;
document.head.appendChild(style);
};
const last = JSON.parse(localStorage.getItem("openidea.theme") ?? "null");
if (last?.theme) root.dataset.theme = last.theme;
if (last?.contrast) root.dataset.contrast = last.contrast;
// A plugin theme's stylesheet (plugins/bridge.ts), so the workbench doesn't
// show the built-in theme until the plugin host answers.
const plugin = JSON.parse(localStorage.getItem("openidea.pluginTheme") ?? "null");
if (typeof plugin?.id === "string" && typeof plugin.css === "string" && !/[<\\]|url\(/i.test(plugin.css)) {
addStyle("openidea-plugin-theme", plugin.css);
root.dataset.pluginTheme = plugin.id;
root.dataset.pluginThemeKind = root.dataset.theme = plugin.kind === "light" ? "light" : "dark";
delete root.dataset.contrast;
}
// The splash's frame, text and accent colours, resolved by theme.ts (splash.css).
const colors = [
["--boot-frame", last?.frame],
["--boot-fg", last?.fg],
["--boot-accent", last?.accent],
].filter(([, v]) => typeof v === "string" && /^#[0-9a-f]{3,8}$/i.test(v));
if (colors.length) addStyle("openidea-boot-colors", `:root { ${colors.map(([k, v]) => `${k}: ${v};`).join(" ")} }`);
} catch {
/* storage unavailable */
}
// Settings windows (`settings-<parent>`) load this page too: splash.css drops the logo for them.
if (window.__TAURI_INTERNALS__?.metadata?.currentWindow?.label?.startsWith("settings-")) {
document.documentElement.dataset.window = "settings";
}