diff --git a/frontend/src/lib/visualizer-palette.ts b/frontend/src/lib/visualizer-palette.ts index e7b2b2f..648e543 100644 --- a/frontend/src/lib/visualizer-palette.ts +++ b/frontend/src/lib/visualizer-palette.ts @@ -60,3 +60,69 @@ export function readPalette(el: Element): Palette { rose: parseHex(s.getPropertyValue("--gradient-rose"), FALLBACK.rose), }; } + +function rgbToHsl({ r, g, b }: RGB): [number, number, number] { + const rn = r / 255; + const gn = g / 255; + const bn = b / 255; + const max = Math.max(rn, gn, bn); + const min = Math.min(rn, gn, bn); + const l = (max + min) / 2; + if (max === min) return [0, 0, l]; + const d = max - min; + const s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + let h: number; + if (max === rn) h = (gn - bn) / d + (gn < bn ? 6 : 0); + else if (max === gn) h = (bn - rn) / d + 2; + else h = (rn - gn) / d + 4; + return [h / 6, s, l]; +} + +function hue2rgb(p: number, q: number, t: number) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; +} + +function hslToRgb(h: number, s: number, l: number): RGB { + if (s === 0) { + const v = Math.round(l * 255); + return { r: v, g: v, b: v }; + } + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + return { + r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255), + g: Math.round(hue2rgb(p, q, h) * 255), + b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255), + }; +} + +/** + * 按主题为「发光画面」调整调色板: + * 暗色提亮提饱和让辉光透亮;亮色加深加饱和,避免粉彩色在白底上发灰。 + */ +export function adaptPalette(palette: Palette, dark: boolean): Palette { + const tune = (c: RGB): RGB => { + const [h, s, l] = rgbToHsl(c); + return dark + ? hslToRgb(h, Math.min(1, s * 1.25), Math.min(0.78, l * 1.15)) + : hslToRgb(h, Math.min(1, s * 1.55), Math.max(0.36, l * 0.6)); + }; + return { + sky: tune(palette.sky), + lav: tune(palette.lav), + rose: tune(palette.rose), + }; +} + +/** 当前是否处于暗色主题(与 ThemeToggle 在 上切换的 .dark 一致) */ +export function isDarkTheme(): boolean { + return ( + typeof document !== "undefined" && + document.documentElement.classList.contains("dark") + ); +}