Add initial app
This commit is contained in:
222
src/utils/colors.ts
Normal file
222
src/utils/colors.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
// Color conversion utilities
|
||||
export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16),
|
||||
}
|
||||
: null
|
||||
}
|
||||
|
||||
export function rgbToHex(r: number, g: number, b: number): string {
|
||||
return '#' + [r, g, b].map(x => {
|
||||
const hex = x.toString(16)
|
||||
return hex.length === 1 ? '0' + hex : hex
|
||||
}).join('')
|
||||
}
|
||||
|
||||
export function rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } {
|
||||
r /= 255
|
||||
g /= 255
|
||||
b /= 255
|
||||
|
||||
const max = Math.max(r, g, b)
|
||||
const min = Math.min(r, g, b)
|
||||
let h = 0
|
||||
let s
|
||||
const l = (max + min) / 2
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0
|
||||
} else {
|
||||
const d = max - min
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
||||
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0)
|
||||
break
|
||||
case g:
|
||||
h = (b - r) / d + 2
|
||||
break
|
||||
case b:
|
||||
h = (r - g) / d + 4
|
||||
break
|
||||
}
|
||||
|
||||
h /= 6
|
||||
}
|
||||
|
||||
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): { r: number; g: number; b: number } {
|
||||
h /= 360
|
||||
s /= 100
|
||||
l /= 100
|
||||
|
||||
let r: number
|
||||
let g: number
|
||||
let b: number
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = l
|
||||
} else {
|
||||
const hue2rgb = (p: number, q: number, t: number) => {
|
||||
if (t < 0) t += 1
|
||||
if (t > 1) t -= 1
|
||||
if (t < 1/6) return p + (q - p) * 6 * t
|
||||
if (t < 1/2) return q
|
||||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6
|
||||
return p
|
||||
}
|
||||
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
||||
const p = 2 * l - q
|
||||
|
||||
r = hue2rgb(p, q, h + 1/3)
|
||||
g = hue2rgb(p, q, h)
|
||||
b = hue2rgb(p, q, h - 1/3)
|
||||
}
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255),
|
||||
}
|
||||
}
|
||||
|
||||
export function rgbToHsb(r: number, g: number, b: number): { h: number; s: number; b: number } {
|
||||
r /= 255
|
||||
g /= 255
|
||||
b /= 255
|
||||
|
||||
const max = Math.max(r, g, b)
|
||||
const min = Math.min(r, g, b)
|
||||
let h = 0
|
||||
const s = max === 0 ? 0 : (max - min) / max
|
||||
const v = max
|
||||
|
||||
if (max !== min) {
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / (max - min) + (g < b ? 6 : 0)
|
||||
break
|
||||
case g:
|
||||
h = (b - r) / (max - min) + 2
|
||||
break
|
||||
case b:
|
||||
h = (r - g) / (max - min) + 4
|
||||
break
|
||||
}
|
||||
h /= 6
|
||||
}
|
||||
|
||||
return {
|
||||
h: Math.round(h * 360),
|
||||
s: Math.round(s * 100),
|
||||
b: Math.round(v * 100),
|
||||
}
|
||||
}
|
||||
|
||||
export function hsbToRgb(h: number, s: number, v: number): { r: number; g: number; b: number } {
|
||||
h /= 360
|
||||
s /= 100
|
||||
v /= 100
|
||||
|
||||
let r: number
|
||||
let g: number
|
||||
let b: number
|
||||
|
||||
const i = Math.floor(h * 6)
|
||||
const f = h * 6 - i
|
||||
const p = v * (1 - s)
|
||||
const q = v * (1 - f * s)
|
||||
const t = v * (1 - (1 - f) * s)
|
||||
|
||||
switch (i % 6) {
|
||||
case 0:
|
||||
r = v
|
||||
g = t
|
||||
b = p
|
||||
break
|
||||
case 1:
|
||||
r = q
|
||||
g = v
|
||||
b = p
|
||||
break
|
||||
case 2:
|
||||
r = p
|
||||
g = v
|
||||
b = t
|
||||
break
|
||||
case 3:
|
||||
r = p
|
||||
g = q
|
||||
b = v
|
||||
break
|
||||
case 4:
|
||||
r = t
|
||||
g = p
|
||||
b = v
|
||||
break
|
||||
case 5:
|
||||
r = v
|
||||
g = p
|
||||
b = q
|
||||
break
|
||||
default:
|
||||
r = g = b = 0
|
||||
}
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255),
|
||||
}
|
||||
}
|
||||
|
||||
// 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'
|
||||
|
||||
let closestColor = ''
|
||||
let minDistance = Infinity
|
||||
|
||||
Object.entries(tailwindColors).forEach(([name, colorHex]) => {
|
||||
const currentRgb = hexToRgb(colorHex)
|
||||
if (!currentRgb) return
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
closestColor = name
|
||||
}
|
||||
})
|
||||
|
||||
return closestColor
|
||||
}
|
||||
Reference in New Issue
Block a user