/** * Color resolution for charts. Tone names map to theme CSS vars so charts are * automatically theme + dark-mode aware; any raw CSS color passes through. */ import type { ThemeType } from '../../../types' const TONES = [ 'blue', 'green', 'red', 'yellow', 'purple', 'brown', 'orange', 'turquoise', 'gray', 'black', 'pink', 'primary', 'white', ] /** A pleasant default multi-series sequence (theme tokens). */ export const SERIES_TONES: ThemeType[] = [ 'primary', 'purple', 'turquoise', 'orange', 'pink', 'green', 'blue', 'yellow', 'red', ] /** Is this string one of the known theme tones (incl. -light/-tint suffixes)? */ function isTone(c: string): boolean { const base = c.replace(/-(light|tint|dark|\d+)$/, '') return TONES.includes(base) } /** * Resolve a caller color into a paintable CSS value. * - tone name → `var(--bgl-)` * - anything else (hex/rgb/var(...)) → returned as-is * - undefined → falls back to the series-index tone */ export function resolveColor(color: ThemeType | string | undefined, index = 0): string { if (!color) return `var(--bgl-${SERIES_TONES[index % SERIES_TONES.length]})` if (typeof color === 'string' && isTone(color)) return `var(--bgl-${color})` return color } /** A translucent version of a resolved color (for area fills / hovers). */ export function alpha(cssColor: string, pct: number): string { return `color-mix(in srgb, ${cssColor} ${pct}%, transparent)` } /** * A monochrome ramp: `count` shades of one base color, from full strength to a * lighter tint. Reads premium for donut/pie slices and stacked categories. * `index 0` is the strongest; later slices fade toward white. */ export function ramp(base: ThemeType | string | undefined, count: number, index = 0): string { const color = resolveColor(base ?? 'primary') if (count <= 1) return color // Spread mix from 100% (strongest) down to ~40% (lightest) of the base. const minPct = 42 const pct = 100 - (index / (count - 1)) * (100 - minPct) return `color-mix(in srgb, ${color} ${pct}%, var(--bgl-box-bg))` }