Files
2026-06-06 00:49:07 +08:00

94 lines
1.7 KiB
TypeScript

export type GalleryColorFamily =
| "black"
| "blue"
| "green"
| "light"
| "orange"
| "purple"
| "red"
| "yellow";
function hexToRgb(hex: string) {
const normalized = hex.trim().replace(/^#/, "");
if (!/^[0-9a-f]{6}$/i.test(normalized)) {
return null;
}
return {
r: parseInt(normalized.slice(0, 2), 16),
g: parseInt(normalized.slice(2, 4), 16),
b: parseInt(normalized.slice(4, 6), 16),
};
}
export function getGalleryColorFamily(
color: string | null | undefined,
): GalleryColorFamily | null {
if (!color) {
return null;
}
const rgb = hexToRgb(color);
if (!rgb) {
return null;
}
const { r, g, b } = rgb;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const lightness = (max + min) / 510;
if (lightness > 0.78) {
return "light";
}
if (lightness < 0.2) {
return "black";
}
const delta = max - min;
if (delta < 24) {
return lightness > 0.52 ? "light" : "black";
}
let hue = 0;
if (max === r) {
hue = ((g - b) / delta) % 6;
} else if (max === g) {
hue = (b - r) / delta + 2;
} else {
hue = (r - g) / delta + 4;
}
hue = Math.round(hue * 60);
if (hue < 0) {
hue += 360;
}
if (hue < 18 || hue >= 345) {
return "red";
}
if (hue < 45) {
return "orange";
}
if (hue < 70) {
return "yellow";
}
if (hue < 170) {
return "green";
}
if (hue < 255) {
return "blue";
}
if (hue < 345) {
return "purple";
}
return null;
}