94 lines
1.7 KiB
TypeScript
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;
|
|
}
|