// 可视化共用的配色工具:从设计 token(--gradient-*)读取调色板, // 让三种可视化样式自动跟随明暗主题,并保持同一套视觉语言。 export type RGB = { r: number; g: number; b: number }; export type Palette = { sky: RGB; lav: RGB; rose: RGB }; /** 浅色主题下的回退值,避免首帧 token 未就绪时闪烁 */ const FALLBACK: Palette = { sky: { r: 168, g: 200, b: 232 }, lav: { r: 200, g: 184, b: 224 }, rose: { r: 232, g: 184, b: 196 }, }; export function parseHex(hex: string, fallback: RGB): RGB { const m = hex.trim().replace("#", ""); if (m.length === 6) { return { r: parseInt(m.slice(0, 2), 16), g: parseInt(m.slice(2, 4), 16), b: parseInt(m.slice(4, 6), 16), }; } if (m.length === 3) { return { r: parseInt(m[0] + m[0], 16), g: parseInt(m[1] + m[1], 16), b: parseInt(m[2] + m[2], 16), }; } return fallback; } export function rgba({ r, g, b }: RGB, a: number) { return `rgba(${r}, ${g}, ${b}, ${a})`; } export function mix(a: RGB, b: RGB, t: number): RGB { return { r: Math.round(a.r + (b.r - a.r) * t), g: Math.round(a.g + (b.g - a.g) * t), b: Math.round(a.b + (b.b - a.b) * t), }; } /** 在 sky → lavender → rose 三色之间取环形插值(首尾相连,适合沿圆周/横向铺色) */ export function cyclicColor({ sky, lav, rose }: Palette, p: number): RGB { const stops = [sky, lav, rose]; const scaled = ((p % 1) + 1) % 1 * stops.length; const i = Math.floor(scaled); return mix(stops[i % stops.length], stops[(i + 1) % stops.length], scaled - i); } /** 从元素上读取当前主题的 --gradient-* token,返回 0~255 的 RGB */ export function readPalette(el: Element): Palette { const s = getComputedStyle(el); return { sky: parseHex(s.getPropertyValue("--gradient-sky"), FALLBACK.sky), lav: parseHex(s.getPropertyValue("--gradient-lavender"), FALLBACK.lav), rose: parseHex(s.getPropertyValue("--gradient-rose"), FALLBACK.rose), }; }