mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 17:02:17 +00:00
Solarized Light/Dark and One Light/Dark ship as theme plugins (plugins/theme-solarized, plugins/theme-one) with complete UI tokens, editor schemes and terminal colours, and the original palettes' MIT notices. Installing a plugin now also copies its LICENSE/NOTICE/COPYING. Theme handling that benefits every plugin theme: - The last plugin theme is restored before first paint (splash, workbench); the native window background follows the theme. - HSL / color-mix() / var() colours are resolved to RGB for native windows, the Settings window and Mermaid. - Mermaid, the terminal and editor schemes follow switches between two themes of the same kind. - An explicitly chosen editor scheme wins over a plugin theme's editor colours. Supersedes #85. Co-authored-by: bghtyu <[email protected]> Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
68 lines
2.8 KiB
TypeScript
68 lines
2.8 KiB
TypeScript
/**
|
||
* Design tokens as concrete colours. Themes may write tokens as `hsl()`,
|
||
* `color-mix()` or `var()`; consumers outside CSS (the native window, Mermaid,
|
||
* xterm) need RGB, so a token is resolved by the browser and parsed here.
|
||
*/
|
||
|
||
/** Red, green, blue (0–255) and alpha (0–1). */
|
||
export type Rgba = [number, number, number, number];
|
||
|
||
/** Parses `#rgb[a]`, `#rrggbb[aa]`, `rgb[a](…)` and `color(srgb …)`; `null` when unknown. */
|
||
export function parseColor(input: string): Rgba | null {
|
||
const s = input.trim().toLowerCase();
|
||
if (s.startsWith("#")) {
|
||
const h = s.slice(1);
|
||
if (!/^[0-9a-f]+$/.test(h)) return null;
|
||
if (h.length === 3 || h.length === 4) {
|
||
const [r, g, b, a = "f"] = h.split("") as [string, string, string, string?];
|
||
return [parseInt(r + r, 16), parseInt(g + g, 16), parseInt(b + b, 16), parseInt(a + a, 16) / 255];
|
||
}
|
||
if (h.length === 6 || h.length === 8) {
|
||
const a = h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;
|
||
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16), a];
|
||
}
|
||
return null;
|
||
}
|
||
let m = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/.exec(s);
|
||
if (m) {
|
||
const alpha = m[4] === undefined ? 1 : m[4].endsWith("%") ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
|
||
return [Number(m[1]), Number(m[2]), Number(m[3]), alpha];
|
||
}
|
||
m = /^color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\s*\)$/.exec(s);
|
||
if (m) {
|
||
return [Number(m[1]) * 255, Number(m[2]) * 255, Number(m[3]) * 255, m[4] === undefined ? 1 : Number(m[4])];
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/** The computed colour of token `name` on `root`, whatever syntax the theme wrote it in. */
|
||
export function resolveTokenColor(name: string, root: HTMLElement = document.documentElement): Rgba | null {
|
||
if (typeof getComputedStyle === "undefined") return null;
|
||
const raw = getComputedStyle(root).getPropertyValue(name).trim();
|
||
if (!raw) return null;
|
||
const direct = parseColor(raw);
|
||
if (direct) return direct;
|
||
const probe = root.ownerDocument.createElement("span");
|
||
probe.hidden = true;
|
||
probe.style.color = `var(${name})`;
|
||
root.appendChild(probe);
|
||
const color = getComputedStyle(probe).color;
|
||
probe.remove();
|
||
return parseColor(color);
|
||
}
|
||
|
||
const byte = (v: number) => Math.min(255, Math.max(0, Math.round(v)));
|
||
|
||
/** `#rrggbb`, or `#rrggbbaa` when translucent. */
|
||
export function toHex([r, g, b, a]: Rgba): string {
|
||
const parts = [r, g, b].map(byte);
|
||
if (byte(a * 255) !== 255) parts.push(byte(a * 255));
|
||
return `#${parts.map((x) => x.toString(16).padStart(2, "0")).join("")}`;
|
||
}
|
||
|
||
/** `rgb(r, g, b)`, or `rgba(r, g, b, a)` when translucent. */
|
||
export function toRgb([r, g, b, a]: Rgba): string {
|
||
const [rr, gg, bb] = [r, g, b].map(byte);
|
||
return a < 1 ? `rgba(${rr}, ${gg}, ${bb}, ${Math.round(a * 1000) / 1000})` : `rgb(${rr}, ${gg}, ${bb})`;
|
||
}
|