/** * Vega-Lite chart config per UI theme (docs/architecture/05 §3, 09 §6). * * Portable core: a Vega-Lite `Config` styles every chart globally so charts * visually belong to the app rather than looking like stock Vega-Lite. This is * the single source of truth mapping a `UiTheme` to a config; it is applied at * embed time (never baked into the user's stored spec). Adding a UI theme = one * config object plus one map entry here. * * Values track the design language: IBM Plex font, axis/grid colors from the * Carbon neutral ramp (matching `--text-secondary` / `--border`), and a * categorical `range.category` palette transcribed from Carbon's data-viz * 14-color pairing (white theme for light, g100 for dark — see * carbon-charts `packages/core/scss/_color-palette.scss`). This is the * expressive "free color" layer (doc §3.5, §5). */ import type { Config } from 'vega-lite'; import type { UiTheme } from './theme'; const PLEX = '"IBM Plex Sans", system-ui, -apple-system, sans-serif'; /** Carbon data-viz 14-color categorical palette — white (light) theme. */ const lightCategory = [ '#6929c4', // purple 70 '#1192e8', // cyan 50 '#005d5d', // teal 70 '#9f1853', // magenta 70 '#fa4d56', // red 50 '#520408', // red 90 '#198038', // green 60 '#002d9c', // blue 80 '#ee5396', // magenta 50 '#b28600', // yellow 50 '#009d9a', // teal 50 '#012749', // cyan 90 '#8a3800', // orange 70 '#a56eff', // purple 50 ]; /** Carbon data-viz 14-color categorical palette — g100 (dark) theme. */ const darkCategory = [ '#8a3ffc', // purple 60 '#33b1ff', // cyan 40 '#007d79', // teal 60 '#ff7eb6', // magenta 40 '#fa4d56', // red 50 '#fff1f1', // red 10 '#6fdc8c', // green 30 '#4589ff', // blue 50 '#d02670', // magenta 60 '#d2a106', // yellow 40 '#08bdba', // teal 40 '#bae6ff', // cyan 20 '#ba4e00', // orange 60 '#d4bbff', // purple 30 ]; export const lightChartConfig: Config = { background: 'transparent', font: PLEX, title: { fontSize: 16, fontWeight: 600, color: '#161616' }, axis: { domainColor: '#c6c6c6', // --border-strong (light) gridColor: '#e0e0e0', // --border (light) gridDash: [2, 2], labelColor: '#525252', // --text-secondary (light) titleColor: '#161616', // --text (light) labelFontSize: 11, titleFontSize: 12, titleFontWeight: 600, }, range: { category: lightCategory }, view: { stroke: 'transparent' }, }; export const darkChartConfig: Config = { background: 'transparent', font: PLEX, title: { fontSize: 16, fontWeight: 600, color: '#f4f4f4' }, axis: { domainColor: '#525252', // --border-strong (dark) gridColor: '#393939', // --border (dark) gridDash: [2, 2], labelColor: '#a8a8a8', // --text-secondary (dark) titleColor: '#f4f4f4', // --text (dark) labelFontSize: 11, titleFontSize: 12, titleFontWeight: 600, }, range: { category: darkCategory }, view: { stroke: 'transparent' }, }; const CHART_CONFIG: Record = { light: lightChartConfig, dark: darkChartConfig, }; /** The Vega-Lite config for a UI theme — the only theme → config mapping. */ export function chartConfigFor(theme: UiTheme): Config { return CHART_CONFIG[theme]; }