142 lines
4.6 KiB
TypeScript
142 lines
4.6 KiB
TypeScript
import { reactive } from "vue";
|
|
import type { DeviceColorEntry, DeviceColors } from "./types/evcc";
|
|
|
|
export function deviceColorMap(list: DeviceColorEntry[] | undefined): DeviceColors {
|
|
const m: DeviceColors = {};
|
|
for (const { title, color } of list ?? []) m[title] = color;
|
|
return m;
|
|
}
|
|
|
|
// alternatives
|
|
// const COLORS = [ "#40916C", "#52B788", "#74C69D", "#95D5B2", "#B7E4C7", "#D8F3DC", "#081C15", "#1B4332", "#2D6A4F"];
|
|
// const COLORS = ["#577590", "#43AA8B", "#90BE6D", "#F9C74F", "#F8961E", "#F3722C", "#F94144"];
|
|
// const COLORS = ["#0077b6", "#00b4d8", "#90e0ef", "#caf0f8", "#03045e"];
|
|
// const COLORS = [ "#0077B6FF", "#0096C7FF", "#00B4D8FF", "#48CAE4FF", "#90E0EFFF", "#ADE8F4FF", "#CAF0F8FF", "#03045EFF", "#023E8AFF",
|
|
// const COLORS = [ "#0077B6FF", "#00B4D8FF", "#90E0EFFF", "#40A578FF", "#9DDE8BFF", "#F8961EFF", "#F9C74FFF", "#E6FF94FF"];
|
|
|
|
const colors: {
|
|
text: string | null;
|
|
muted: string | null;
|
|
border: string | null;
|
|
self: string | null;
|
|
grid: string | null;
|
|
co2PerKWh: string | null;
|
|
pricePerKWh: string | null;
|
|
price: string | null;
|
|
co2: string | null;
|
|
export: string | null;
|
|
background: string | null;
|
|
light: string | null;
|
|
selfPalette: string[];
|
|
palette: string[];
|
|
} = reactive({
|
|
text: null,
|
|
muted: null,
|
|
border: null,
|
|
self: null,
|
|
grid: null,
|
|
co2PerKWh: null,
|
|
pricePerKWh: null,
|
|
price: null,
|
|
co2: null,
|
|
export: null,
|
|
background: null,
|
|
light: null,
|
|
selfPalette: ["#0FDE41", "#FFBD2F", "#FD6158", "#03C1EF", "#0F662D", "#FF922E"],
|
|
palette: [
|
|
// light
|
|
"#60A5FA", // blue
|
|
"#FBBF24", // amber
|
|
"#22D3EE", // cyan
|
|
"#F472B6", // pink
|
|
"#34D399", // green
|
|
"#A78BFA", // violet
|
|
"#94A3B8", // gray
|
|
// mid
|
|
"#2563EB", // blue
|
|
"#F59E0B", // amber
|
|
"#06B6D4", // cyan
|
|
"#EC4899", // pink
|
|
"#10B981", // green
|
|
"#8B5CF6", // violet
|
|
"#64748B", // gray
|
|
// dark
|
|
"#1E40AF", // blue
|
|
"#B45309", // amber
|
|
"#0E7490", // cyan
|
|
"#BE185D", // pink
|
|
"#047857", // green
|
|
"#6D28D9", // violet
|
|
"#334155", // gray
|
|
],
|
|
});
|
|
|
|
// normalize 6-digit hex to 8-digit, then replace alpha
|
|
const setAlpha = (color: string | null, alpha: string): string | undefined => {
|
|
if (!color) return undefined;
|
|
const c = color.trim().toLowerCase();
|
|
// #rrggbb → append alpha, #rrggbbaa → replace alpha
|
|
if (c.length === 7) return c + alpha;
|
|
if (c.length === 9) return c.slice(0, 7) + alpha;
|
|
return c;
|
|
};
|
|
|
|
// regex for raw hex (no leading #): 6 digits, used for input validation
|
|
export const HEX_RE = /^[0-9a-fA-F]{6}$/;
|
|
|
|
// normalize hex to uppercase 7-char #RRGGBB (strips alpha if present)
|
|
export const normalizeHex = (color?: string | null): string => {
|
|
if (!color) return "";
|
|
let c = color.trim().toUpperCase();
|
|
if (!c.startsWith("#")) c = "#" + c;
|
|
return c.slice(0, 7);
|
|
};
|
|
|
|
// override wins; rest get next free palette entry, wrap-around when exhausted
|
|
export function resolveColors(ids: string[], overrides: DeviceColors = {}): DeviceColors {
|
|
const taken = new Set(Object.values(overrides).map(normalizeHex));
|
|
const free = colors.palette.filter((c) => !taken.has(normalizeHex(c)));
|
|
const result: DeviceColors = {};
|
|
let idx = 0;
|
|
for (const id of ids) {
|
|
const ov = overrides[id];
|
|
if (ov) {
|
|
result[id] = ov;
|
|
} else if (free.length) {
|
|
result[id] = free[idx % free.length];
|
|
idx++;
|
|
} else {
|
|
result[id] = colors.palette[idx % colors.palette.length];
|
|
idx++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export const dimColor = (color: string | null) => setAlpha(color, "20");
|
|
|
|
export const lighterColor = (color: string | null) => setAlpha(color, "aa");
|
|
|
|
export const fullColor = (color: string | null) => setAlpha(color, "ff");
|
|
|
|
export function updateCssColors() {
|
|
const style = window.getComputedStyle(document.documentElement);
|
|
colors.text = style.getPropertyValue("--evcc-default-text");
|
|
colors.muted = style.getPropertyValue("--bs-gray-medium");
|
|
colors.border = style.getPropertyValue("--bs-border-color-translucent");
|
|
colors.self = style.getPropertyValue("--evcc-self");
|
|
colors.grid = style.getPropertyValue("--evcc-grid");
|
|
colors.price = style.getPropertyValue("--evcc-price");
|
|
colors.co2 = style.getPropertyValue("--evcc-co2");
|
|
colors.export = style.getPropertyValue("--evcc-export-contrast");
|
|
colors.background = style.getPropertyValue("--evcc-background");
|
|
colors.pricePerKWh = style.getPropertyValue("--bs-gray-medium");
|
|
colors.co2PerKWh = style.getPropertyValue("--bs-gray-medium");
|
|
colors.light = style.getPropertyValue("--bs-gray-light");
|
|
}
|
|
|
|
// initialize colors
|
|
updateCssColors();
|
|
window.requestAnimationFrame(updateCssColors);
|
|
|
|
export default colors;
|