Add react color picker, show tailwind colors all the time

This commit is contained in:
2025-02-10 10:29:00 -05:00
parent db5fb7ca61
commit 1d03a56c70
5 changed files with 393 additions and 72 deletions

View File

@@ -182,41 +182,225 @@ export function hsbToRgb(h: number, s: number, v: number): { r: number; g: numbe
}
}
// Function to find the closest Tailwind color
export function findClosestTailwindColor(hex: string): string {
// This is a simplified version - we'll expand this with actual Tailwind colors
const tailwindColors = {
'red-500': '#EF4444',
'blue-500': '#3B82F6',
'green-500': '#22C55E',
'yellow-500': '#EAB308',
'purple-500': '#A855F7',
'pink-500': '#EC4899',
'indigo-500': '#6366F1',
// Add more colors as needed
}
const targetRgb = hexToRgb(hex)
if (!targetRgb) return 'Invalid color'
// Function to find the closest Tailwind color using CIELAB color space
export function findClosestTailwindColor(hex: string): { name: string; hex: string } {
const rgb1 = hexToRgb(hex)
if (!rgb1) return { name: 'Invalid color', hex }
let closestColor = ''
let closestHex = ''
let minDistance = Infinity
Object.entries(tailwindColors).forEach(([name, colorHex]) => {
const currentRgb = hexToRgb(colorHex)
if (!currentRgb) return
// Convert RGB to Lab
const lab1 = rgbToLab(rgb1.r, rgb1.g, rgb1.b)
const distance = Math.sqrt(
Math.pow(targetRgb.r - currentRgb.r, 2) +
Math.pow(targetRgb.g - currentRgb.g, 2) +
Math.pow(targetRgb.b - currentRgb.b, 2)
)
Object.entries(TAILWIND_COLORS).forEach(([colorName, shades]) => {
Object.entries(shades).forEach(([shade, colorHex]) => {
const rgb2 = hexToRgb(colorHex)
if (!rgb2) return
if (distance < minDistance) {
minDistance = distance
closestColor = name
}
const lab2 = rgbToLab(rgb2.r, rgb2.g, rgb2.b)
const distance = deltaE(lab1, lab2)
if (distance < minDistance) {
minDistance = distance
closestColor = `${colorName}-${shade}`
closestHex = colorHex
}
})
})
return closestColor
}
return { name: closestColor, hex: closestHex }
}
// CIELAB color space conversion functions
function rgbToLab(r: number, g: number, b: number) {
let x, y, z
r = r / 255
g = g / 255
b = b / 255
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92
x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047
y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000
z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883
x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + 16/116
y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + 16/116
z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + 16/116
return {
l: (116 * y) - 16,
a: 500 * (x - y),
b: 200 * (y - z)
}
}
// Calculate color difference using CIEDE2000
function deltaE(lab1: { l: number; a: number; b: number }, lab2: { l: number; a: number; b: number }) {
const deltaL = lab2.l - lab1.l
const deltaA = lab2.a - lab1.a
const deltaB = lab2.b - lab1.b
const c1 = Math.sqrt(lab1.a * lab1.a + lab1.b * lab1.b)
const c2 = Math.sqrt(lab2.a * lab2.a + lab2.b * lab2.b)
const deltaC = c2 - c1
let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC
deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH)
const sc = 1.0 + 0.045 * c1
const sh = 1.0 + 0.015 * c1
const deltaLKlsl = deltaL / (1.0)
const deltaCkcsc = deltaC / (sc)
const deltaHkhsh = deltaH / (sh)
return Math.sqrt(deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh)
}
// Export Tailwind colors for use in other components
export const TAILWIND_COLORS = {
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617',
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712',
},
zinc: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b',
},
red: {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d',
950: '#450a0a',
},
orange: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12',
950: '#431407',
},
yellow: {
50: '#fefce8',
100: '#fef9c3',
200: '#fef08a',
300: '#fde047',
400: '#facc15',
500: '#eab308',
600: '#ca8a04',
700: '#a16207',
800: '#854d0e',
900: '#713f12',
950: '#422006',
},
green: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
950: '#052e16',
},
blue: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554',
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
purple: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87',
950: '#3b0764',
},
pink: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843',
950: '#500724',
},
} as const