export interface HSLColor { h: number; s: number; l: number; } export interface RGBColor { r: number; g: number; b: number; } export function hexToRgb(hex: string): RGBColor { if (hex.length === 4) { hex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; } const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return { r, g, b }; } export function rgbToHex(r: number, g: number, b: number): string { return ( '#' + [r, g, b] .map((x) => { const hex = Math.round(Math.max(0, Math.min(255, x))).toString(16); return hex.length === 1 ? '0' + hex : hex; }) .join('') ); } export function hexToHsl(hex: string): HSLColor { const { r, g, b } = hexToRgb(hex); const rNorm = r / 255; const gNorm = g / 255; const bNorm = b / 255; const max = Math.max(rNorm, gNorm, bNorm); const min = Math.min(rNorm, gNorm, bNorm); let h = 0; let s = 0; const l = (max + min) / 2; if (max !== min) { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case rNorm: h = ((gNorm - bNorm) / d + (gNorm < bNorm ? 6 : 0)) / 6; break; case gNorm: h = ((bNorm - rNorm) / d + 2) / 6; break; case bNorm: h = ((rNorm - gNorm) / d + 4) / 6; break; } } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100), }; } export function hslToRgb(h: number, s: number, l: number): RGBColor { const sNorm = s / 100; const lNorm = l / 100; const a = sNorm * Math.min(lNorm, 1 - lNorm); const f = (n: number) => { const k = (n + h / 30) % 12; const color = lNorm - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return Math.round(255 * color); }; return { r: f(0), g: f(8), b: f(4) }; } export function hslToHex(h: number, s: number, l: number): string { const { r, g, b } = hslToRgb(h, s, l); return rgbToHex(r, g, b); } export function isValidHex(hex: string): boolean { return /^#[0-9A-Fa-f]{6}$/.test(hex); } export function normalizeHex(hex: string): string { if (!hex.startsWith('#')) { hex = '#' + hex; } if (hex.length === 4) { hex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; } return hex.toLowerCase(); }