The PH/CW/DIG grid in the Stats panel is the fastest read in the app and its palette was fixed per theme. Settings -> Appearance now offers the six: the four status fills, the never-worked fill, and the ring on the cell being entered. Stored as OVERRIDES, not as a palette. Each of the twelve themes ships an --mx-* ramp tuned to its own background, so an operator who only wants a different green must not thereby freeze the other four to the theme they happened to be using that day. An empty value means "whatever the theme says"; the chosen ones are stamped inline on <html>, where they win over every theme; switching the feature off hands the colours straight back. The pickers are seeded from what the matrix is painting at that moment rather than from a fixed palette, so the choice starts from the colours in front of the operator. A new --mx-cur token carries the current-entry ring: it follows --warning by default, so it stays theme-correct on all twelve, but can be recoloured without dragging every other warning in the app along. The legend under the matrix and its cell tooltips were hardcoded English. They now go through t() with the same keys as the pickers, so the grid and the settings cannot disagree about which green is which.
67 lines
3.1 KiB
TypeScript
67 lines
3.1 KiB
TypeScript
// Operator overrides for the band/mode matrix palette.
|
|
//
|
|
// Applied as inline custom properties on <html>, which is what lets them be
|
|
// OVERRIDES rather than a palette: the twelve themes each define their own
|
|
// --mx-* ramp in style.css, an inline value wins over all of them, and removing
|
|
// it hands the colour straight back to the theme. Nothing has to know which
|
|
// theme is active, and switching theme with overrides off is a clean revert.
|
|
|
|
export type MatrixColors = {
|
|
enabled: boolean;
|
|
call_confirmed: string;
|
|
call_worked: string;
|
|
entity_confirmed: string;
|
|
entity_worked: string;
|
|
not_worked: string;
|
|
current_entry: string;
|
|
};
|
|
|
|
// The six settings fields and the CSS custom property each one drives. Also the
|
|
// display order — the same order the legend under the matrix reads in, so the
|
|
// settings panel and the grid can never disagree about which green is which.
|
|
export const MATRIX_VARS: { key: keyof Omit<MatrixColors, 'enabled'>; cssVar: string; label: string }[] = [
|
|
{ key: 'call_confirmed', cssVar: '--mx-call-conf', label: 'mx.callConf' },
|
|
{ key: 'call_worked', cssVar: '--mx-call-work', label: 'mx.callWork' },
|
|
{ key: 'entity_confirmed', cssVar: '--mx-dx-conf', label: 'mx.dxConf' },
|
|
{ key: 'entity_worked', cssVar: '--mx-dx-work', label: 'mx.dxWork' },
|
|
{ key: 'not_worked', cssVar: '--mx-none', label: 'mx.none' },
|
|
{ key: 'current_entry', cssVar: '--mx-cur', label: 'mx.current' },
|
|
];
|
|
|
|
export const emptyMatrixColors = (): MatrixColors => ({
|
|
enabled: false,
|
|
call_confirmed: '', call_worked: '', entity_confirmed: '',
|
|
entity_worked: '', not_worked: '', current_entry: '',
|
|
});
|
|
|
|
// applyMatrixColors stamps (or clears) the overrides on <html>. Safe to call as
|
|
// often as you like — it is the whole rendering path, so the settings panel uses
|
|
// it for a live preview and the app uses it once at startup.
|
|
export function applyMatrixColors(c?: MatrixColors | null): void {
|
|
const root = document.documentElement;
|
|
for (const { key, cssVar } of MATRIX_VARS) {
|
|
const v = c?.enabled ? String(c[key] ?? '').trim() : '';
|
|
if (v) root.style.setProperty(cssVar, v);
|
|
else root.style.removeProperty(cssVar);
|
|
}
|
|
}
|
|
|
|
// effectiveMatrixColor reads what the matrix is ACTUALLY painting right now —
|
|
// the override if there is one, else the active theme's value. It is what seeds
|
|
// the colour pickers, so the operator starts from the colours in front of them
|
|
// instead of from a hardcoded palette that may belong to a different theme.
|
|
//
|
|
// A custom property's computed value has its var() references substituted, so
|
|
// --mx-cur resolves to the theme's --warning rather than to the literal text.
|
|
export function effectiveMatrixColor(cssVar: string): string {
|
|
try {
|
|
const v = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
|
|
// <input type="color"> only accepts #rrggbb. Anything else (a theme that
|
|
// ever moves to oklch, an empty read during boot) falls back to mid grey
|
|
// rather than silently resetting the picker to black.
|
|
return /^#[0-9a-f]{6}$/i.test(v) ? v.toLowerCase() : '#808080';
|
|
} catch {
|
|
return '#808080';
|
|
}
|
|
}
|