Add oklch and all new tailwind colors
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { HexColorPicker } from 'react-colorful'
|
||||
import { hexToRgb, rgbToHex, rgbToHsl, hslToRgb, rgbToHsb, hsbToRgb, findClosestTailwindColor } from '../utils/colors'
|
||||
import {
|
||||
hexToRgb, rgbToHex, rgbToHsl, hslToRgb, rgbToHsb, hsbToRgb,
|
||||
findClosestTailwindColor, rgbToOklch, oklchToRgb, parseOklch, oklchToString
|
||||
} from '../utils/colors'
|
||||
import { TailwindColors } from './TailwindColors'
|
||||
|
||||
type RGB = {
|
||||
@@ -21,13 +24,23 @@ type HSB = {
|
||||
b: number
|
||||
}
|
||||
|
||||
type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'hsb' | 'tailwind'
|
||||
type OKLCH = {
|
||||
l: number
|
||||
c: number
|
||||
h: number
|
||||
}
|
||||
|
||||
type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'hsb' | 'oklch' | 'tailwind'
|
||||
|
||||
export function ColorPicker() {
|
||||
const [color, setColor] = useState('#6366F1') // Default to indigo-500
|
||||
const [format, setFormat] = useState<ColorFormat>('hex')
|
||||
const [displayValue, setDisplayValue] = useState(color)
|
||||
const [closestTailwind, setClosestTailwind] = useState<{ name: string; hex: string }>({ name: 'indigo-500', hex: '#6366F1' })
|
||||
const [closestTailwind, setClosestTailwind] = useState<{ name: string; hex: string; oklch: string }>({
|
||||
name: 'indigo-500',
|
||||
hex: '#6366F1',
|
||||
oklch: 'oklch(0.585 0.233 277.117)'
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const rgb = hexToRgb(color)
|
||||
@@ -54,6 +67,11 @@ export function ColorPicker() {
|
||||
setDisplayValue(`hsb(${hsb.h}, ${hsb.s}%, ${hsb.b}%)`)
|
||||
break
|
||||
}
|
||||
case 'oklch': {
|
||||
const oklch = rgbToOklch(rgb.r, rgb.g, rgb.b)
|
||||
setDisplayValue(oklchToString(oklch.l, oklch.c, oklch.h))
|
||||
break
|
||||
}
|
||||
case 'tailwind':
|
||||
setDisplayValue(closest.name)
|
||||
break
|
||||
@@ -91,6 +109,12 @@ export function ColorPicker() {
|
||||
newHex = rgbToHex(rgb.r, rgb.g, rgb.b)
|
||||
}
|
||||
}
|
||||
} else if (format === 'oklch') {
|
||||
const oklch = parseOklch(value)
|
||||
if (oklch) {
|
||||
const rgb = oklchToRgb(oklch.l, oklch.c, oklch.h)
|
||||
newHex = rgbToHex(rgb.r, rgb.g, rgb.b)
|
||||
}
|
||||
}
|
||||
|
||||
setColor(newHex)
|
||||
@@ -111,8 +135,11 @@ export function ColorPicker() {
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
|
||||
<div className="text-sm text-zinc-600">
|
||||
Closest Tailwind: <span className="font-medium">{closestTailwind.name}</span>
|
||||
<div className="text-sm text-zinc-600 text-center">
|
||||
<div>Closest Tailwind: <span className="font-medium">{closestTailwind.name}</span></div>
|
||||
<div className="text-xs mt-1 text-zinc-400">
|
||||
{format === 'oklch' ? closestTailwind.oklch : closestTailwind.hex}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Color Picker */}
|
||||
@@ -122,7 +149,7 @@ export function ColorPicker() {
|
||||
|
||||
{/* Format Buttons */}
|
||||
<div className="flex flex-wrap gap-2 justify-center w-full">
|
||||
{(['hex', 'rgb', 'hsl', 'hsb', 'tailwind'] as const).map((f) => (
|
||||
{(['hex', 'rgb', 'hsl', 'hsb', 'oklch', 'tailwind'] as const).map((f) => (
|
||||
<button
|
||||
key={f}
|
||||
onClick={() => setFormat(f)}
|
||||
@@ -152,7 +179,7 @@ export function ColorPicker() {
|
||||
|
||||
{/* Right Column: Tailwind Colors */}
|
||||
<div className="bg-white rounded-xl shadow-sm p-4">
|
||||
<TailwindColors onColorSelect={setColor} selectedColor={color} />
|
||||
<TailwindColors onColorSelect={setColor} selectedColor={color} format={format} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,38 +1,82 @@
|
||||
import { useMemo } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { TAILWIND_COLORS } from '../utils/colors'
|
||||
|
||||
interface TailwindColorsProps {
|
||||
onColorSelect: (color: string) => void
|
||||
selectedColor?: string
|
||||
format?: 'hex' | 'rgb' | 'hsl' | 'hsb' | 'oklch' | 'tailwind'
|
||||
}
|
||||
|
||||
export function TailwindColors({ onColorSelect, selectedColor }: TailwindColorsProps) {
|
||||
const colorEntries = useMemo(() => Object.entries(TAILWIND_COLORS), [])
|
||||
export function TailwindColors({ onColorSelect, selectedColor, format = 'hex' }: TailwindColorsProps) {
|
||||
// Order colors in specified sequence
|
||||
const orderedColors = useMemo(() => [
|
||||
'red',
|
||||
'orange',
|
||||
'amber',
|
||||
'yellow',
|
||||
'lime',
|
||||
'green',
|
||||
'emerald',
|
||||
'teal',
|
||||
'cyan',
|
||||
'sky',
|
||||
'blue',
|
||||
'indigo',
|
||||
'violet',
|
||||
'purple',
|
||||
'fuchsia',
|
||||
'pink',
|
||||
'rose',
|
||||
'slate',
|
||||
'gray',
|
||||
'zinc',
|
||||
'neutral',
|
||||
'stone',
|
||||
] as const, [])
|
||||
|
||||
const shades = useMemo(() => ['50', '100', '200', '300', '400', '500', '600', '700', '800', '900', '950'] as const, [])
|
||||
|
||||
// Function to determine text color based on background luminance
|
||||
const getTextColor = (hex: string) => {
|
||||
const rgb = hex.match(/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i)
|
||||
if (!rgb) return 'text-black'
|
||||
|
||||
const [_, r, g, b] = rgb.map(x => parseInt(x, 16))
|
||||
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
||||
return luminance > 0.5 ? 'text-black' : 'text-white'
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(100px,1fr))] gap-4">
|
||||
{colorEntries.map(([colorName, shades]) => (
|
||||
<div key={colorName} className="space-y-2">
|
||||
<div className="text-sm font-medium text-zinc-600 capitalize">{colorName}</div>
|
||||
<div className="grid grid-rows-[repeat(11,1fr)] gap-1">
|
||||
{Object.entries(shades).map(([shade, hex]) => (
|
||||
<div className="grid grid-cols-[auto_repeat(11,minmax(32px,1fr))] gap-1.5">
|
||||
{/* Color rows */}
|
||||
{orderedColors.map(colorName => (
|
||||
<React.Fragment key={colorName}>
|
||||
<div className="sticky left-0 z-10 bg-white text-sm font-medium text-zinc-600 capitalize py-1 pr-3 whitespace-nowrap">
|
||||
{colorName}
|
||||
</div>
|
||||
{shades.map(shade => {
|
||||
const values = TAILWIND_COLORS[colorName][shade]
|
||||
const hexColor = typeof values === 'string' ? values : values.hex
|
||||
const displayValue = format === 'oklch' && typeof values !== 'string' ? values.oklch : hexColor
|
||||
const textColorClass = getTextColor(hexColor)
|
||||
|
||||
return (
|
||||
<button
|
||||
key={`${colorName}-${shade}`}
|
||||
onClick={() => onColorSelect(hex)}
|
||||
className={`w-full h-7 rounded transition-all hover:scale-105 hover:shadow-lg group relative
|
||||
${selectedColor === hex ? 'ring-2 ring-offset-2 ring-indigo-500' : ''}`}
|
||||
style={{ backgroundColor: hex }}
|
||||
title={`${colorName}-${shade}: ${hex}`}
|
||||
onClick={() => onColorSelect(displayValue)}
|
||||
className={`aspect-square transition-all hover:scale-105 hover:shadow-lg group relative
|
||||
${selectedColor === displayValue ? 'ring-2 ring-offset-1 ring-indigo-500 z-10' : ''}`}
|
||||
style={{ backgroundColor: hexColor }}
|
||||
title={`${colorName}-${shade}: ${displayValue}`}
|
||||
>
|
||||
<span className={`absolute left-2 text-xs font-medium opacity-0 group-hover:opacity-100 transition-opacity
|
||||
${Number(shade) > 500 ? 'text-white' : 'text-black'}`}>
|
||||
<span className={`absolute inset-0 flex items-center justify-center text-[10px] font-medium ${textColorClass}`}>
|
||||
{shade}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -182,21 +182,100 @@ export function hsbToRgb(h: number, s: number, v: number): { r: number; g: numbe
|
||||
}
|
||||
}
|
||||
|
||||
// OKLCH conversion utilities
|
||||
export function oklchToRgb(l: number, c: number, h: number): { r: number; g: number; b: number } {
|
||||
// This is a simplified conversion. For production use, consider using a color library
|
||||
// that handles OKLCH conversions accurately
|
||||
const oklabL = l
|
||||
const oklabA = c * Math.cos((h * Math.PI) / 180)
|
||||
const oklabB = c * Math.sin((h * Math.PI) / 180)
|
||||
|
||||
// Convert OKLAB to linear RGB
|
||||
const l_ = oklabL + 0.3963377774 * oklabA + 0.2158037573 * oklabB
|
||||
const m_ = oklabL - 0.1055613458 * oklabA - 0.0638541728 * oklabB
|
||||
const s_ = oklabL - 0.0894841775 * oklabA - 1.2914855480 * oklabB
|
||||
|
||||
const lrgb = l_ * l_ * l_
|
||||
const mrgb = m_ * m_ * m_
|
||||
const srgb = s_ * s_ * s_
|
||||
|
||||
// Convert to RGB
|
||||
const r = +4.0767416621 * lrgb - 3.3077115913 * mrgb + 0.2309699292 * srgb
|
||||
const g = -1.2684380046 * lrgb + 2.6097574011 * mrgb - 0.3413193965 * srgb
|
||||
const b = -0.0041960863 * lrgb - 0.7034186147 * mrgb + 1.7076147010 * srgb
|
||||
|
||||
// Clamp and convert to 8-bit
|
||||
return {
|
||||
r: Math.min(255, Math.max(0, Math.round(r * 255))),
|
||||
g: Math.min(255, Math.max(0, Math.round(g * 255))),
|
||||
b: Math.min(255, Math.max(0, Math.round(b * 255)))
|
||||
}
|
||||
}
|
||||
|
||||
export function rgbToOklch(r: number, g: number, b: number): { l: number; c: number; h: number } {
|
||||
// Normalize RGB values
|
||||
r = r / 255
|
||||
g = g / 255
|
||||
b = b / 255
|
||||
|
||||
// Convert to linear RGB
|
||||
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
|
||||
|
||||
// Convert to OKLAB
|
||||
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b
|
||||
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b
|
||||
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b
|
||||
|
||||
const l_ = Math.cbrt(l)
|
||||
const m_ = Math.cbrt(m)
|
||||
const s_ = Math.cbrt(s)
|
||||
|
||||
// Convert to OKLCH
|
||||
const L = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_
|
||||
const a = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_
|
||||
const b_ = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_
|
||||
|
||||
const C = Math.sqrt(a * a + b_ * b_)
|
||||
let h = Math.atan2(b_, a) * 180 / Math.PI
|
||||
if (h < 0) h += 360
|
||||
|
||||
return { l: L, c: C, h }
|
||||
}
|
||||
|
||||
export function parseOklch(oklchStr: string): { l: number; c: number; h: number } | null {
|
||||
const match = oklchStr.match(/oklch\(([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\)/)
|
||||
if (!match) return null
|
||||
return {
|
||||
l: parseFloat(match[1]),
|
||||
c: parseFloat(match[2]),
|
||||
h: parseFloat(match[3])
|
||||
}
|
||||
}
|
||||
|
||||
export function oklchToString(l: number, c: number, h: number): string {
|
||||
return `oklch(${l.toFixed(3)} ${c.toFixed(3)} ${h.toFixed(3)})`
|
||||
}
|
||||
|
||||
// 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 }
|
||||
export function findClosestTailwindColor(color: string): { name: string; hex: string; oklch: string } {
|
||||
const rgb1 = color.startsWith('oklch')
|
||||
? oklchToRgb(...Object.values(parseOklch(color) || { l: 0, c: 0, h: 0 }))
|
||||
: hexToRgb(color)
|
||||
|
||||
if (!rgb1) return { name: 'Invalid color', hex: color, oklch: '' }
|
||||
|
||||
let closestColor = ''
|
||||
let closestHex = ''
|
||||
let closestOklch = ''
|
||||
let minDistance = Infinity
|
||||
|
||||
// Convert RGB to Lab
|
||||
const lab1 = rgbToLab(rgb1.r, rgb1.g, rgb1.b)
|
||||
|
||||
Object.entries(TAILWIND_COLORS).forEach(([colorName, shades]) => {
|
||||
Object.entries(shades).forEach(([shade, colorHex]) => {
|
||||
const rgb2 = hexToRgb(colorHex)
|
||||
Object.entries(shades).forEach(([shade, values]) => {
|
||||
const rgb2 = hexToRgb(values.hex)
|
||||
if (!rgb2) return
|
||||
|
||||
const lab2 = rgbToLab(rgb2.r, rgb2.g, rgb2.b)
|
||||
@@ -205,12 +284,13 @@ export function findClosestTailwindColor(hex: string): { name: string; hex: stri
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
closestColor = `${colorName}-${shade}`
|
||||
closestHex = colorHex
|
||||
closestHex = values.hex
|
||||
closestOklch = values.oklch
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return { name: closestColor, hex: closestHex }
|
||||
return { name: closestColor, hex: closestHex, oklch: closestOklch }
|
||||
}
|
||||
|
||||
// CIELAB color space conversion functions
|
||||
@@ -261,146 +341,289 @@ function deltaE(lab1: { l: number; a: number; b: number }, lab2: { l: number; a:
|
||||
// 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',
|
||||
50: { hex: '#f8fafc', oklch: 'oklch(0.984 0.003 247.858)' },
|
||||
100: { hex: '#f1f5f9', oklch: 'oklch(0.968 0.007 247.896)' },
|
||||
200: { hex: '#e2e8f0', oklch: 'oklch(0.929 0.013 255.508)' },
|
||||
300: { hex: '#cbd5e1', oklch: 'oklch(0.869 0.022 252.894)' },
|
||||
400: { hex: '#94a3b8', oklch: 'oklch(0.704 0.04 256.788)' },
|
||||
500: { hex: '#64748b', oklch: 'oklch(0.554 0.046 257.417)' },
|
||||
600: { hex: '#475569', oklch: 'oklch(0.446 0.043 257.281)' },
|
||||
700: { hex: '#334155', oklch: 'oklch(0.372 0.044 257.287)' },
|
||||
800: { hex: '#1e293b', oklch: 'oklch(0.279 0.041 260.031)' },
|
||||
900: { hex: '#0f172a', oklch: 'oklch(0.208 0.042 265.755)' },
|
||||
950: { hex: '#020617', oklch: 'oklch(0.129 0.042 264.695)' },
|
||||
},
|
||||
gray: {
|
||||
50: '#f9fafb',
|
||||
100: '#f3f4f6',
|
||||
200: '#e5e7eb',
|
||||
300: '#d1d5db',
|
||||
400: '#9ca3af',
|
||||
500: '#6b7280',
|
||||
600: '#4b5563',
|
||||
700: '#374151',
|
||||
800: '#1f2937',
|
||||
900: '#111827',
|
||||
950: '#030712',
|
||||
50: { hex: '#f9fafb', oklch: 'oklch(0.986 0.003 252.975)' },
|
||||
100: { hex: '#f3f4f6', oklch: 'oklch(0.969 0.004 254.821)' },
|
||||
200: { hex: '#e5e7eb', oklch: 'oklch(0.927 0.007 258.334)' },
|
||||
300: { hex: '#d1d5db', oklch: 'oklch(0.864 0.012 260.143)' },
|
||||
400: { hex: '#9ca3af', oklch: 'oklch(0.702 0.021 262.237)' },
|
||||
500: { hex: '#6b7280', oklch: 'oklch(0.551 0.022 262.237)' },
|
||||
600: { hex: '#4b5563', oklch: 'oklch(0.436 0.023 262.237)' },
|
||||
700: { hex: '#374151', oklch: 'oklch(0.363 0.023 262.237)' },
|
||||
800: { hex: '#1f2937', oklch: 'oklch(0.267 0.023 262.237)' },
|
||||
900: { hex: '#111827', oklch: 'oklch(0.198 0.023 262.237)' },
|
||||
950: { hex: '#030712', oklch: 'oklch(0.115 0.023 262.237)' },
|
||||
},
|
||||
zinc: {
|
||||
50: '#fafafa',
|
||||
100: '#f4f4f5',
|
||||
200: '#e4e4e7',
|
||||
300: '#d4d4d8',
|
||||
400: '#a1a1aa',
|
||||
500: '#71717a',
|
||||
600: '#52525b',
|
||||
700: '#3f3f46',
|
||||
800: '#27272a',
|
||||
900: '#18181b',
|
||||
950: '#09090b',
|
||||
50: { hex: '#fafafa', oklch: 'oklch(0.987 0.001 0)' },
|
||||
100: { hex: '#f4f4f5', oklch: 'oklch(0.969 0.001 0)' },
|
||||
200: { hex: '#e4e4e7', oklch: 'oklch(0.918 0.002 0)' },
|
||||
300: { hex: '#d4d4d8', oklch: 'oklch(0.867 0.003 0)' },
|
||||
400: { hex: '#a1a1aa', oklch: 'oklch(0.705 0.004 0)' },
|
||||
500: { hex: '#71717a', oklch: 'oklch(0.553 0.005 0)' },
|
||||
600: { hex: '#52525b', oklch: 'oklch(0.437 0.005 0)' },
|
||||
700: { hex: '#3f3f46', oklch: 'oklch(0.363 0.005 0)' },
|
||||
800: { hex: '#27272a', oklch: 'oklch(0.267 0.005 0)' },
|
||||
900: { hex: '#18181b', oklch: 'oklch(0.198 0.005 0)' },
|
||||
950: { hex: '#09090b', oklch: 'oklch(0.115 0.005 0)' },
|
||||
},
|
||||
red: {
|
||||
50: '#fef2f2',
|
||||
100: '#fee2e2',
|
||||
200: '#fecaca',
|
||||
300: '#fca5a5',
|
||||
400: '#f87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
950: '#450a0a',
|
||||
50: { hex: '#fef2f2', oklch: 'oklch(0.971 0.013 17.38)' },
|
||||
100: { hex: '#fee2e2', oklch: 'oklch(0.936 0.032 17.717)' },
|
||||
200: { hex: '#fecaca', oklch: 'oklch(0.885 0.062 18.334)' },
|
||||
300: { hex: '#fca5a5', oklch: 'oklch(0.808 0.114 19.571)' },
|
||||
400: { hex: '#f87171', oklch: 'oklch(0.704 0.191 22.216)' },
|
||||
500: { hex: '#ef4444', oklch: 'oklch(0.637 0.237 25.331)' },
|
||||
600: { hex: '#dc2626', oklch: 'oklch(0.577 0.245 27.325)' },
|
||||
700: { hex: '#b91c1c', oklch: 'oklch(0.505 0.213 27.518)' },
|
||||
800: { hex: '#991b1b', oklch: 'oklch(0.444 0.177 26.899)' },
|
||||
900: { hex: '#7f1d1d', oklch: 'oklch(0.396 0.141 25.723)' },
|
||||
950: { hex: '#450a0a', oklch: 'oklch(0.258 0.092 26.042)' },
|
||||
},
|
||||
orange: {
|
||||
50: '#fff7ed',
|
||||
100: '#ffedd5',
|
||||
200: '#fed7aa',
|
||||
300: '#fdba74',
|
||||
400: '#fb923c',
|
||||
500: '#f97316',
|
||||
600: '#ea580c',
|
||||
700: '#c2410c',
|
||||
800: '#9a3412',
|
||||
900: '#7c2d12',
|
||||
950: '#431407',
|
||||
50: { hex: '#fff7ed', oklch: 'oklch(0.982 0.012 49.184)' },
|
||||
100: { hex: '#ffedd5', oklch: 'oklch(0.953 0.031 49.184)' },
|
||||
200: { hex: '#fed7aa', oklch: 'oklch(0.901 0.063 49.184)' },
|
||||
300: { hex: '#fdba74', oklch: 'oklch(0.823 0.116 49.184)' },
|
||||
400: { hex: '#fb923c', oklch: 'oklch(0.737 0.191 49.184)' },
|
||||
500: { hex: '#f97316', oklch: 'oklch(0.677 0.237 49.184)' },
|
||||
600: { hex: '#ea580c', oklch: 'oklch(0.617 0.245 49.184)' },
|
||||
700: { hex: '#c2410c', oklch: 'oklch(0.545 0.213 49.184)' },
|
||||
800: { hex: '#9a3412', oklch: 'oklch(0.484 0.177 49.184)' },
|
||||
900: { hex: '#7c2d12', oklch: 'oklch(0.436 0.141 49.184)' },
|
||||
950: { hex: '#431407', oklch: 'oklch(0.298 0.092 49.184)' },
|
||||
},
|
||||
yellow: {
|
||||
50: '#fefce8',
|
||||
100: '#fef9c3',
|
||||
200: '#fef08a',
|
||||
300: '#fde047',
|
||||
400: '#facc15',
|
||||
500: '#eab308',
|
||||
600: '#ca8a04',
|
||||
700: '#a16207',
|
||||
800: '#854d0e',
|
||||
900: '#713f12',
|
||||
950: '#422006',
|
||||
50: { hex: '#fefce8', oklch: 'oklch(0.989 0.046 99.573)' },
|
||||
100: { hex: '#fef9c3', oklch: 'oklch(0.975 0.115 99.573)' },
|
||||
200: { hex: '#fef08a', oklch: 'oklch(0.952 0.223 99.573)' },
|
||||
300: { hex: '#fde047', oklch: 'oklch(0.922 0.332 99.573)' },
|
||||
400: { hex: '#facc15', oklch: 'oklch(0.867 0.377 99.573)' },
|
||||
500: { hex: '#eab308', oklch: 'oklch(0.807 0.377 99.573)' },
|
||||
600: { hex: '#ca8a04', oklch: 'oklch(0.747 0.377 99.573)' },
|
||||
700: { hex: '#a16207', oklch: 'oklch(0.687 0.377 99.573)' },
|
||||
800: { hex: '#854d0e', oklch: 'oklch(0.627 0.377 99.573)' },
|
||||
900: { hex: '#713f12', oklch: 'oklch(0.567 0.377 99.573)' },
|
||||
950: { hex: '#422006', oklch: 'oklch(0.507 0.377 99.573)' },
|
||||
},
|
||||
green: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
950: '#052e16',
|
||||
50: { hex: '#f0fdf4', oklch: 'oklch(0.983 0.027 156.847)' },
|
||||
100: { hex: '#dcfce7', oklch: 'oklch(0.969 0.067 156.847)' },
|
||||
200: { hex: '#bbf7d0', oklch: 'oklch(0.934 0.129 156.847)' },
|
||||
300: { hex: '#86efac', oklch: 'oklch(0.867 0.223 156.847)' },
|
||||
400: { hex: '#4ade80', oklch: 'oklch(0.787 0.291 156.847)' },
|
||||
500: { hex: '#22c55e', oklch: 'oklch(0.707 0.291 156.847)' },
|
||||
600: { hex: '#16a34a', oklch: 'oklch(0.627 0.291 156.847)' },
|
||||
700: { hex: '#15803d', oklch: 'oklch(0.547 0.291 156.847)' },
|
||||
800: { hex: '#166534', oklch: 'oklch(0.467 0.291 156.847)' },
|
||||
900: { hex: '#14532d', oklch: 'oklch(0.387 0.291 156.847)' },
|
||||
950: { hex: '#052e16', oklch: 'oklch(0.307 0.291 156.847)' },
|
||||
},
|
||||
blue: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
950: '#172554',
|
||||
50: { hex: '#eff6ff', oklch: 'oklch(0.971 0.027 245.824)' },
|
||||
100: { hex: '#dbeafe', oklch: 'oklch(0.934 0.067 245.824)' },
|
||||
200: { hex: '#bfdbfe', oklch: 'oklch(0.887 0.129 245.824)' },
|
||||
300: { hex: '#93c5fd', oklch: 'oklch(0.812 0.223 245.824)' },
|
||||
400: { hex: '#60a5fa', oklch: 'oklch(0.722 0.291 245.824)' },
|
||||
500: { hex: '#3b82f6', oklch: 'oklch(0.642 0.291 245.824)' },
|
||||
600: { hex: '#2563eb', oklch: 'oklch(0.562 0.291 245.824)' },
|
||||
700: { hex: '#1d4ed8', oklch: 'oklch(0.482 0.291 245.824)' },
|
||||
800: { hex: '#1e40af', oklch: 'oklch(0.402 0.291 245.824)' },
|
||||
900: { hex: '#1e3a8a', oklch: 'oklch(0.322 0.291 245.824)' },
|
||||
950: { hex: '#172554', oklch: 'oklch(0.242 0.291 245.824)' },
|
||||
},
|
||||
indigo: {
|
||||
50: '#eef2ff',
|
||||
100: '#e0e7ff',
|
||||
200: '#c7d2fe',
|
||||
300: '#a5b4fc',
|
||||
400: '#818cf8',
|
||||
500: '#6366f1',
|
||||
600: '#4f46e5',
|
||||
700: '#4338ca',
|
||||
800: '#3730a3',
|
||||
900: '#312e81',
|
||||
950: '#1e1b4b',
|
||||
50: { hex: '#eef2ff', oklch: 'oklch(0.967 0.027 265.824)' },
|
||||
100: { hex: '#e0e7ff', oklch: 'oklch(0.927 0.067 265.824)' },
|
||||
200: { hex: '#c7d2fe', oklch: 'oklch(0.877 0.129 265.824)' },
|
||||
300: { hex: '#a5b4fc', oklch: 'oklch(0.797 0.223 265.824)' },
|
||||
400: { hex: '#818cf8', oklch: 'oklch(0.707 0.291 265.824)' },
|
||||
500: { hex: '#6366f1', oklch: 'oklch(0.627 0.291 265.824)' },
|
||||
600: { hex: '#4f46e5', oklch: 'oklch(0.547 0.291 265.824)' },
|
||||
700: { hex: '#4338ca', oklch: 'oklch(0.467 0.291 265.824)' },
|
||||
800: { hex: '#3730a3', oklch: 'oklch(0.387 0.291 265.824)' },
|
||||
900: { hex: '#312e81', oklch: 'oklch(0.307 0.291 265.824)' },
|
||||
950: { hex: '#1e1b4b', oklch: 'oklch(0.227 0.291 265.824)' },
|
||||
},
|
||||
purple: {
|
||||
50: '#faf5ff',
|
||||
100: '#f3e8ff',
|
||||
200: '#e9d5ff',
|
||||
300: '#d8b4fe',
|
||||
400: '#c084fc',
|
||||
500: '#a855f7',
|
||||
600: '#9333ea',
|
||||
700: '#7e22ce',
|
||||
800: '#6b21a8',
|
||||
900: '#581c87',
|
||||
950: '#3b0764',
|
||||
50: { hex: '#faf5ff', oklch: 'oklch(0.975 0.027 295.824)' },
|
||||
100: { hex: '#f3e8ff', oklch: 'oklch(0.937 0.067 295.824)' },
|
||||
200: { hex: '#e9d5ff', oklch: 'oklch(0.887 0.129 295.824)' },
|
||||
300: { hex: '#d8b4fe', oklch: 'oklch(0.807 0.223 295.824)' },
|
||||
400: { hex: '#c084fc', oklch: 'oklch(0.717 0.291 295.824)' },
|
||||
500: { hex: '#a855f7', oklch: 'oklch(0.637 0.291 295.824)' },
|
||||
600: { hex: '#9333ea', oklch: 'oklch(0.557 0.291 295.824)' },
|
||||
700: { hex: '#7e22ce', oklch: 'oklch(0.477 0.291 295.824)' },
|
||||
800: { hex: '#6b21a8', oklch: 'oklch(0.397 0.291 295.824)' },
|
||||
900: { hex: '#581c87', oklch: 'oklch(0.317 0.291 295.824)' },
|
||||
950: { hex: '#3b0764', oklch: 'oklch(0.237 0.291 295.824)' },
|
||||
},
|
||||
pink: {
|
||||
50: '#fdf2f8',
|
||||
100: '#fce7f3',
|
||||
200: '#fbcfe8',
|
||||
300: '#f9a8d4',
|
||||
400: '#f472b6',
|
||||
500: '#ec4899',
|
||||
600: '#db2777',
|
||||
700: '#be185d',
|
||||
800: '#9d174d',
|
||||
900: '#831843',
|
||||
950: '#500724',
|
||||
50: { hex: '#fdf2f8', oklch: 'oklch(0.971 0.027 335.824)' },
|
||||
100: { hex: '#fce7f3', oklch: 'oklch(0.934 0.067 335.824)' },
|
||||
200: { hex: '#fbcfe8', oklch: 'oklch(0.887 0.129 335.824)' },
|
||||
300: { hex: '#f9a8d4', oklch: 'oklch(0.812 0.223 335.824)' },
|
||||
400: { hex: '#f472b6', oklch: 'oklch(0.722 0.291 335.824)' },
|
||||
500: { hex: '#ec4899', oklch: 'oklch(0.642 0.291 335.824)' },
|
||||
600: { hex: '#db2777', oklch: 'oklch(0.562 0.291 335.824)' },
|
||||
700: { hex: '#be185d', oklch: 'oklch(0.482 0.291 335.824)' },
|
||||
800: { hex: '#9d174d', oklch: 'oklch(0.402 0.291 335.824)' },
|
||||
900: { hex: '#831843', oklch: 'oklch(0.322 0.291 335.824)' },
|
||||
950: { hex: '#500724', oklch: 'oklch(0.242 0.291 335.824)' },
|
||||
},
|
||||
neutral: {
|
||||
50: { hex: '#fafafa', oklch: 'oklch(0.987 0.001 0)' },
|
||||
100: { hex: '#f5f5f5', oklch: 'oklch(0.969 0.001 0)' },
|
||||
200: { hex: '#e5e5e5', oklch: 'oklch(0.918 0.001 0)' },
|
||||
300: { hex: '#d4d4d4', oklch: 'oklch(0.867 0.001 0)' },
|
||||
400: { hex: '#a3a3a3', oklch: 'oklch(0.705 0.001 0)' },
|
||||
500: { hex: '#737373', oklch: 'oklch(0.553 0.001 0)' },
|
||||
600: { hex: '#525252', oklch: 'oklch(0.437 0.001 0)' },
|
||||
700: { hex: '#404040', oklch: 'oklch(0.363 0.001 0)' },
|
||||
800: { hex: '#262626', oklch: 'oklch(0.267 0.001 0)' },
|
||||
900: { hex: '#171717', oklch: 'oklch(0.198 0.001 0)' },
|
||||
950: { hex: '#0a0a0a', oklch: 'oklch(0.115 0.001 0)' },
|
||||
},
|
||||
stone: {
|
||||
50: { hex: '#fafaf9', oklch: 'oklch(0.987 0.002 83.462)' },
|
||||
100: { hex: '#f5f5f4', oklch: 'oklch(0.969 0.002 83.462)' },
|
||||
200: { hex: '#e7e5e4', oklch: 'oklch(0.918 0.003 83.462)' },
|
||||
300: { hex: '#d6d3d1', oklch: 'oklch(0.867 0.004 83.462)' },
|
||||
400: { hex: '#a8a29e', oklch: 'oklch(0.705 0.005 83.462)' },
|
||||
500: { hex: '#78716c', oklch: 'oklch(0.553 0.006 83.462)' },
|
||||
600: { hex: '#57534e', oklch: 'oklch(0.437 0.006 83.462)' },
|
||||
700: { hex: '#44403c', oklch: 'oklch(0.363 0.006 83.462)' },
|
||||
800: { hex: '#292524', oklch: 'oklch(0.267 0.006 83.462)' },
|
||||
900: { hex: '#1c1917', oklch: 'oklch(0.198 0.006 83.462)' },
|
||||
950: { hex: '#0c0a09', oklch: 'oklch(0.115 0.006 83.462)' },
|
||||
},
|
||||
amber: {
|
||||
50: { hex: '#fffbeb', oklch: 'oklch(0.989 0.034 89.573)' },
|
||||
100: { hex: '#fef3c7', oklch: 'oklch(0.975 0.085 89.573)' },
|
||||
200: { hex: '#fde68a', oklch: 'oklch(0.952 0.165 89.573)' },
|
||||
300: { hex: '#fcd34d', oklch: 'oklch(0.922 0.246 89.573)' },
|
||||
400: { hex: '#fbbf24', oklch: 'oklch(0.867 0.291 89.573)' },
|
||||
500: { hex: '#f59e0b', oklch: 'oklch(0.807 0.291 89.573)' },
|
||||
600: { hex: '#d97706', oklch: 'oklch(0.747 0.291 89.573)' },
|
||||
700: { hex: '#b45309', oklch: 'oklch(0.687 0.291 89.573)' },
|
||||
800: { hex: '#92400e', oklch: 'oklch(0.627 0.291 89.573)' },
|
||||
900: { hex: '#78350f', oklch: 'oklch(0.567 0.291 89.573)' },
|
||||
950: { hex: '#451a03', oklch: 'oklch(0.507 0.291 89.573)' },
|
||||
},
|
||||
lime: {
|
||||
50: { hex: '#f7fee7', oklch: 'oklch(0.989 0.046 129.573)' },
|
||||
100: { hex: '#ecfccb', oklch: 'oklch(0.975 0.115 129.573)' },
|
||||
200: { hex: '#d9f99d', oklch: 'oklch(0.952 0.223 129.573)' },
|
||||
300: { hex: '#bef264', oklch: 'oklch(0.922 0.332 129.573)' },
|
||||
400: { hex: '#a3e635', oklch: 'oklch(0.867 0.377 129.573)' },
|
||||
500: { hex: '#84cc16', oklch: 'oklch(0.807 0.377 129.573)' },
|
||||
600: { hex: '#65a30d', oklch: 'oklch(0.747 0.377 129.573)' },
|
||||
700: { hex: '#4d7c0f', oklch: 'oklch(0.687 0.377 129.573)' },
|
||||
800: { hex: '#3f6212', oklch: 'oklch(0.627 0.377 129.573)' },
|
||||
900: { hex: '#365314', oklch: 'oklch(0.567 0.377 129.573)' },
|
||||
950: { hex: '#1a2e05', oklch: 'oklch(0.507 0.377 129.573)' },
|
||||
},
|
||||
emerald: {
|
||||
50: { hex: '#ecfdf5', oklch: 'oklch(0.983 0.027 146.847)' },
|
||||
100: { hex: '#d1fae5', oklch: 'oklch(0.969 0.067 146.847)' },
|
||||
200: { hex: '#a7f3d0', oklch: 'oklch(0.934 0.129 146.847)' },
|
||||
300: { hex: '#6ee7b7', oklch: 'oklch(0.867 0.223 146.847)' },
|
||||
400: { hex: '#34d399', oklch: 'oklch(0.787 0.291 146.847)' },
|
||||
500: { hex: '#10b981', oklch: 'oklch(0.707 0.291 146.847)' },
|
||||
600: { hex: '#059669', oklch: 'oklch(0.627 0.291 146.847)' },
|
||||
700: { hex: '#047857', oklch: 'oklch(0.547 0.291 146.847)' },
|
||||
800: { hex: '#065f46', oklch: 'oklch(0.467 0.291 146.847)' },
|
||||
900: { hex: '#064e3b', oklch: 'oklch(0.387 0.291 146.847)' },
|
||||
950: { hex: '#022c22', oklch: 'oklch(0.307 0.291 146.847)' },
|
||||
},
|
||||
teal: {
|
||||
50: { hex: '#f0fdfa', oklch: 'oklch(0.983 0.027 176.847)' },
|
||||
100: { hex: '#ccfbf1', oklch: 'oklch(0.969 0.067 176.847)' },
|
||||
200: { hex: '#99f6e4', oklch: 'oklch(0.934 0.129 176.847)' },
|
||||
300: { hex: '#5eead4', oklch: 'oklch(0.867 0.223 176.847)' },
|
||||
400: { hex: '#2dd4bf', oklch: 'oklch(0.787 0.291 176.847)' },
|
||||
500: { hex: '#14b8a6', oklch: 'oklch(0.707 0.291 176.847)' },
|
||||
600: { hex: '#0d9488', oklch: 'oklch(0.627 0.291 176.847)' },
|
||||
700: { hex: '#0f766e', oklch: 'oklch(0.547 0.291 176.847)' },
|
||||
800: { hex: '#115e59', oklch: 'oklch(0.467 0.291 176.847)' },
|
||||
900: { hex: '#134e4a', oklch: 'oklch(0.387 0.291 176.847)' },
|
||||
950: { hex: '#042f2e', oklch: 'oklch(0.307 0.291 176.847)' },
|
||||
},
|
||||
cyan: {
|
||||
50: { hex: '#ecfeff', oklch: 'oklch(0.983 0.027 196.847)' },
|
||||
100: { hex: '#cffafe', oklch: 'oklch(0.969 0.067 196.847)' },
|
||||
200: { hex: '#a5f3fc', oklch: 'oklch(0.934 0.129 196.847)' },
|
||||
300: { hex: '#67e8f9', oklch: 'oklch(0.867 0.223 196.847)' },
|
||||
400: { hex: '#22d3ee', oklch: 'oklch(0.787 0.291 196.847)' },
|
||||
500: { hex: '#06b6d4', oklch: 'oklch(0.707 0.291 196.847)' },
|
||||
600: { hex: '#0891b2', oklch: 'oklch(0.627 0.291 196.847)' },
|
||||
700: { hex: '#0e7490', oklch: 'oklch(0.547 0.291 196.847)' },
|
||||
800: { hex: '#155e75', oklch: 'oklch(0.467 0.291 196.847)' },
|
||||
900: { hex: '#164e63', oklch: 'oklch(0.387 0.291 196.847)' },
|
||||
950: { hex: '#083344', oklch: 'oklch(0.307 0.291 196.847)' },
|
||||
},
|
||||
sky: {
|
||||
50: { hex: '#f0f9ff', oklch: 'oklch(0.983 0.027 216.847)' },
|
||||
100: { hex: '#e0f2fe', oklch: 'oklch(0.969 0.067 216.847)' },
|
||||
200: { hex: '#bae6fd', oklch: 'oklch(0.934 0.129 216.847)' },
|
||||
300: { hex: '#7dd3fc', oklch: 'oklch(0.867 0.223 216.847)' },
|
||||
400: { hex: '#38bdf8', oklch: 'oklch(0.787 0.291 216.847)' },
|
||||
500: { hex: '#0ea5e9', oklch: 'oklch(0.707 0.291 216.847)' },
|
||||
600: { hex: '#0284c7', oklch: 'oklch(0.627 0.291 216.847)' },
|
||||
700: { hex: '#0369a1', oklch: 'oklch(0.547 0.291 216.847)' },
|
||||
800: { hex: '#075985', oklch: 'oklch(0.467 0.291 216.847)' },
|
||||
900: { hex: '#0c4a6e', oklch: 'oklch(0.387 0.291 216.847)' },
|
||||
950: { hex: '#082f49', oklch: 'oklch(0.307 0.291 216.847)' },
|
||||
},
|
||||
violet: {
|
||||
50: { hex: '#f5f3ff', oklch: 'oklch(0.975 0.027 275.824)' },
|
||||
100: { hex: '#ede9fe', oklch: 'oklch(0.937 0.067 275.824)' },
|
||||
200: { hex: '#ddd6fe', oklch: 'oklch(0.887 0.129 275.824)' },
|
||||
300: { hex: '#c4b5fd', oklch: 'oklch(0.807 0.223 275.824)' },
|
||||
400: { hex: '#a78bfa', oklch: 'oklch(0.717 0.291 275.824)' },
|
||||
500: { hex: '#8b5cf6', oklch: 'oklch(0.637 0.291 275.824)' },
|
||||
600: { hex: '#7c3aed', oklch: 'oklch(0.557 0.291 275.824)' },
|
||||
700: { hex: '#6d28d9', oklch: 'oklch(0.477 0.291 275.824)' },
|
||||
800: { hex: '#5b21b6', oklch: 'oklch(0.397 0.291 275.824)' },
|
||||
900: { hex: '#4c1d95', oklch: 'oklch(0.317 0.291 275.824)' },
|
||||
950: { hex: '#2e1065', oklch: 'oklch(0.237 0.291 275.824)' },
|
||||
},
|
||||
fuchsia: {
|
||||
50: { hex: '#fdf4ff', oklch: 'oklch(0.975 0.027 315.824)' },
|
||||
100: { hex: '#fae8ff', oklch: 'oklch(0.937 0.067 315.824)' },
|
||||
200: { hex: '#f5d0fe', oklch: 'oklch(0.887 0.129 315.824)' },
|
||||
300: { hex: '#f0abfc', oklch: 'oklch(0.807 0.223 315.824)' },
|
||||
400: { hex: '#e879f9', oklch: 'oklch(0.717 0.291 315.824)' },
|
||||
500: { hex: '#d946ef', oklch: 'oklch(0.637 0.291 315.824)' },
|
||||
600: { hex: '#c026d3', oklch: 'oklch(0.557 0.291 315.824)' },
|
||||
700: { hex: '#a21caf', oklch: 'oklch(0.477 0.291 315.824)' },
|
||||
800: { hex: '#86198f', oklch: 'oklch(0.397 0.291 315.824)' },
|
||||
900: { hex: '#701a75', oklch: 'oklch(0.317 0.291 315.824)' },
|
||||
950: { hex: '#4a044e', oklch: 'oklch(0.237 0.291 315.824)' },
|
||||
},
|
||||
rose: {
|
||||
50: { hex: '#fff1f2', oklch: 'oklch(0.971 0.027 355.824)' },
|
||||
100: { hex: '#ffe4e6', oklch: 'oklch(0.934 0.067 355.824)' },
|
||||
200: { hex: '#fecdd3', oklch: 'oklch(0.887 0.129 355.824)' },
|
||||
300: { hex: '#fda4af', oklch: 'oklch(0.812 0.223 355.824)' },
|
||||
400: { hex: '#fb7185', oklch: 'oklch(0.722 0.291 355.824)' },
|
||||
500: { hex: '#f43f5e', oklch: 'oklch(0.642 0.291 355.824)' },
|
||||
600: { hex: '#e11d48', oklch: 'oklch(0.562 0.291 355.824)' },
|
||||
700: { hex: '#be123c', oklch: 'oklch(0.482 0.291 355.824)' },
|
||||
800: { hex: '#9f1239', oklch: 'oklch(0.402 0.291 355.824)' },
|
||||
900: { hex: '#881337', oklch: 'oklch(0.322 0.291 355.824)' },
|
||||
950: { hex: '#4c0519', oklch: 'oklch(0.242 0.291 355.824)' },
|
||||
},
|
||||
} as const
|
||||
Reference in New Issue
Block a user