Skip to content

Commit 2daad95

Browse files
added kromatika color palette on color picker
1 parent ddd0018 commit 2daad95

5 files changed

Lines changed: 782 additions & 230 deletions

File tree

src/components/tools/ColorPalette.tsx

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import React, { useEffect, useMemo, useRef, useState } from 'react';
22

33
const families = [
4-
'slate','gray','zinc','neutral','stone',
5-
'red','orange','amber','yellow','lime','green','emerald','teal','cyan','sky','blue','indigo','violet','purple','fuchsia','pink','rose',
4+
'charcoal','metal','haiti','purple','blueBerry','blue','sky','turquoise',
5+
'persianGreen','pastelGreen','grass','carrot','orange','red','raspberry','fuchsia',
66
];
7-
const shades = [50,100,200,300,400,500,600,700,800,900,950] as const;
7+
const shades = [50,100,200,300,400,500,600,700,800,900] as const;
88

9-
function className(family: string, shade: number) {
10-
return `bg-${family}-${shade}`;
9+
function cssVariableName(family: string, shade: number) {
10+
return `--color-${family}-${shade}`;
1111
}
1212

13-
type Format = 'class' | 'hex' | 'rgb' | 'hsl' | 'oklch' | 'var';
13+
type Format = 'var' | 'hex' | 'rgb' | 'hsl' | 'oklch';
1414

1515
export default function ColorPalette() {
1616
const [query, setQuery] = useState('');
17-
const [ setCopied] = useState<string>('');
17+
const [, setCopied] = useState<string>('');
1818
const [copiedKey, setCopiedKey] = useState<string>('');
19-
const [format, setFormat] = useState<Format>('class');
19+
const [format, setFormat] = useState<Format>('var');
2020
const [open, setOpen] = useState(false);
2121
const cacheRef = useRef<Record<string, string>>({});
2222
const dropdownRef = useRef<HTMLDivElement | null>(null);
@@ -36,20 +36,20 @@ export default function ColorPalette() {
3636
} catch {}
3737
}
3838

39-
function getComputedBg(cls: string): string | null {
40-
if (cacheRef.current[cls]) return cacheRef.current[cls];
39+
function getComputedBg(variable: string): string | null {
40+
if (cacheRef.current[variable]) return cacheRef.current[variable];
4141
try {
4242
const el = document.createElement('div');
43-
el.className = `${cls}`;
4443
el.style.position = 'absolute';
4544
el.style.left = '-9999px';
4645
el.style.top = '-9999px';
4746
el.style.width = '1px';
4847
el.style.height = '1px';
48+
el.style.backgroundColor = `var(${variable})`;
4949
document.body.appendChild(el);
5050
const color = getComputedStyle(el).backgroundColor || '';
5151
document.body.removeChild(el);
52-
cacheRef.current[cls] = color;
52+
cacheRef.current[variable] = color;
5353
return color;
5454
} catch {
5555
return null;
@@ -154,34 +154,12 @@ export default function ColorPalette() {
154154
return [+(L).toFixed(2), +C.toFixed(2), +H.toFixed(0)];
155155
}
156156

157-
function formatValue(family: string, shade: number): string {
158-
const cls = className(family, shade);
159-
const varName = `--color-${family}-${shade}`;
160-
if (format === 'class') return `bg-${family}-${shade}`;
161-
if (format === 'var') return varName;
162-
const bg = getComputedBg(cls);
163-
const rgb = bg ? rgbFromCss(bg) : null;
164-
if (!rgb) return `bg-${family}-${shade}`;
165-
if (format === 'hex') return toHex(rgb).toLowerCase();
166-
if (format === 'rgb') return `${rgb[0]} ${rgb[1]} ${rgb[2]}`;
167-
if (format === 'hsl') {
168-
const [h, s, l] = toHsl(rgb);
169-
return `${h} ${s}% ${l}%`;
170-
}
171-
if (format === 'oklch') {
172-
const [L, C, H] = toOKLCH(rgb);
173-
return `oklch(${L} ${C} ${H})`;
174-
}
175-
return `bg-${family}-${shade}`;
176-
}
177-
178157
function formatValueFromEl(el: HTMLElement, family: string, shade: number): string {
179-
const cls = className(family, shade);
180-
if (format === 'class') return `bg-${family}-${shade}`;
181-
if (format === 'var') return `--color-${family}-${shade}`;
182-
const bg = getComputedStyle(el).backgroundColor || getComputedBg(cls);
158+
const variable = cssVariableName(family, shade);
159+
if (format === 'var') return variable;
160+
const bg = getComputedStyle(el).backgroundColor || getComputedBg(variable);
183161
const rgb = bg ? rgbFromCss(bg) : null;
184-
if (!rgb) return `bg-${family}-${shade}`;
162+
if (!rgb) return variable;
185163
if (format === 'hex') return toHex(rgb).toLowerCase();
186164
if (format === 'rgb') return `${rgb[0]} ${rgb[1]} ${rgb[2]}`;
187165
if (format === 'hsl') {
@@ -192,7 +170,7 @@ export default function ColorPalette() {
192170
const [L, C, H] = toOKLCH(rgb);
193171
return `oklch(${L} ${C} ${H})`;
194172
}
195-
return `bg-${family}-${shade}`;
173+
return variable;
196174
}
197175

198176
useEffect(() => {
@@ -241,7 +219,7 @@ export default function ColorPalette() {
241219
className="absolute left-0 top-full z-50 mt-2 w-52 origin-top-left rounded-xl outline outline-zinc-100 shadow bg-white text-[13px] text-zinc-600 divide-y divide-zinc-100"
242220
>
243221
<div className="py-2">
244-
{(['class','hex','rgb','hsl','oklch','var'] as Format[]).map((opt) => (
222+
{(['var','hex','rgb','hsl','oklch'] as Format[]).map((opt) => (
245223
<button
246224
key={opt}
247225
role="menuitem"
@@ -265,7 +243,7 @@ export default function ColorPalette() {
265243
</div>
266244
<input
267245
type="text"
268-
placeholder="Filter colors (e.g., blue, gray)"
246+
placeholder="Filter colors (e.g., charcoal, sky)"
269247
value={query}
270248
onChange={(e) => setQuery(e.target.value)}
271249
className="flex-1 px-3 py-2 text-sm text-zinc-900 placeholder:text-zinc-400 bg-white border rounded-md outline-none border-zinc-200 focus:border-zinc-300 h-[38px]"
@@ -275,9 +253,9 @@ export default function ColorPalette() {
275253
{list.map((family) => (
276254
<section key={family}>
277255
<div className="mb-2 text-sm font-medium capitalize text-zinc-700">{family}</div>
278-
<div className="color-grid">
256+
<div className="grid gap-2 grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-10">
279257
{shades.map((shade) => {
280-
const cls = className(family, shade);
258+
const variable = cssVariableName(family, shade);
281259
const label = `${family}-${shade}`;
282260
const key = label;
283261
return (
@@ -287,8 +265,9 @@ export default function ColorPalette() {
287265
const value = formatValueFromEl(e.currentTarget as HTMLElement, family, shade);
288266
copy(value, key);
289267
}}
290-
title={`Click to copy`}
291-
className={`relative h-14 rounded-md ${cls}`}
268+
title={`Click to copy ${variable}`}
269+
className="relative h-14 rounded-md transition focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500"
270+
style={{ backgroundColor: `var(${variable})` }}
292271
>
293272
{copiedKey === key && (
294273
<span className="absolute inset-0 grid text-[0.70rem] font-mono place-items-center rounded-md bg-black/40 text-white">Copied</span>
@@ -302,29 +281,6 @@ export default function ColorPalette() {
302281
</section>
303282
))}
304283
</div>
305-
306-
<style jsx>{`
307-
.color-grid {
308-
display: grid;
309-
grid-template-columns: repeat(2, minmax(0, 1fr));
310-
gap: 0.5rem;
311-
}
312-
@media (min-width: 640px) {
313-
.color-grid {
314-
grid-template-columns: repeat(3, minmax(0, 1fr));
315-
}
316-
}
317-
@media (min-width: 768px) {
318-
.color-grid {
319-
grid-template-columns: repeat(6, minmax(0, 1fr));
320-
}
321-
}
322-
@media (min-width: 1024px) {
323-
.color-grid {
324-
grid-template-columns: repeat(11, minmax(0, 1fr));
325-
}
326-
}
327-
`}</style>
328284
</div>
329285
);
330286
}

src/content/documentation/base-components/buttons.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ These buttons are built using React HTML Tailwind CSS.
4141
</div>
4242
</TabPanel>
4343

44-
<TabPanel slot="content" tab="code">
44+
<TabPanel slot="content" tab="code">
4545
```astro
4646
<Button>Default</Button>
4747
<Button variant="accent">Accent</Button>

0 commit comments

Comments
 (0)