|
| 1 | +"use client"; |
| 2 | + |
| 3 | +import { useEffect, useRef, useState } from "react"; |
| 4 | +import clsx from "clsx"; |
| 5 | +import { Button, Tooltip, TooltipPanel, TooltipTrigger } from "@headlessui/react"; |
| 6 | + |
| 7 | +const hexColors = { |
| 8 | + slate: { |
| 9 | + 50: "#f8fafc", |
| 10 | + 100: "#f1f5f9", |
| 11 | + 200: "#e2e8f0", |
| 12 | + 300: "#cbd5e1", |
| 13 | + 400: "#94a3b8", |
| 14 | + 500: "#64748b", |
| 15 | + 600: "#475569", |
| 16 | + 700: "#334155", |
| 17 | + 800: "#1e293b", |
| 18 | + 900: "#0f172a", |
| 19 | + 950: "#020617", |
| 20 | + }, |
| 21 | + gray: { |
| 22 | + 50: "#f9fafb", |
| 23 | + 100: "#f3f4f6", |
| 24 | + 200: "#e5e7eb", |
| 25 | + 300: "#d1d5db", |
| 26 | + 400: "#9ca3af", |
| 27 | + 500: "#6b7280", |
| 28 | + 600: "#4b5563", |
| 29 | + 700: "#374151", |
| 30 | + 800: "#1f2937", |
| 31 | + 900: "#111827", |
| 32 | + 950: "#030712", |
| 33 | + }, |
| 34 | + zinc: { |
| 35 | + 50: "#fafafa", |
| 36 | + 100: "#f4f4f5", |
| 37 | + 200: "#e4e4e7", |
| 38 | + 300: "#d4d4d8", |
| 39 | + 400: "#a1a1aa", |
| 40 | + 500: "#71717a", |
| 41 | + 600: "#52525b", |
| 42 | + 700: "#3f3f46", |
| 43 | + 800: "#27272a", |
| 44 | + 900: "#18181b", |
| 45 | + 950: "#09090b", |
| 46 | + }, |
| 47 | + neutral: { |
| 48 | + 50: "#fafafa", |
| 49 | + 100: "#f5f5f5", |
| 50 | + 200: "#e5e5e5", |
| 51 | + 300: "#d4d4d4", |
| 52 | + 400: "#a3a3a3", |
| 53 | + 500: "#737373", |
| 54 | + 600: "#525252", |
| 55 | + 700: "#404040", |
| 56 | + 800: "#262626", |
| 57 | + 900: "#171717", |
| 58 | + 950: "#0a0a0a", |
| 59 | + }, |
| 60 | + stone: { |
| 61 | + 50: "#fafaf9", |
| 62 | + 100: "#f5f5f4", |
| 63 | + 200: "#e7e5e4", |
| 64 | + 300: "#d6d3d1", |
| 65 | + 400: "#a8a29e", |
| 66 | + 500: "#78716c", |
| 67 | + 600: "#57534e", |
| 68 | + 700: "#44403c", |
| 69 | + 800: "#292524", |
| 70 | + 900: "#1c1917", |
| 71 | + 950: "#0c0a09", |
| 72 | + }, |
| 73 | + red: { |
| 74 | + 50: "#fef2f2", |
| 75 | + 100: "#fee2e2", |
| 76 | + 200: "#fecaca", |
| 77 | + 300: "#fca5a5", |
| 78 | + 400: "#f87171", |
| 79 | + 500: "#ef4444", |
| 80 | + 600: "#dc2626", |
| 81 | + 700: "#b91c1c", |
| 82 | + 800: "#991b1b", |
| 83 | + 900: "#7f1d1d", |
| 84 | + 950: "#450a0a", |
| 85 | + }, |
| 86 | + orange: { |
| 87 | + 50: "#fff7ed", |
| 88 | + 100: "#ffedd5", |
| 89 | + 200: "#fed7aa", |
| 90 | + 300: "#fdba74", |
| 91 | + 400: "#fb923c", |
| 92 | + 500: "#f97316", |
| 93 | + 600: "#ea580c", |
| 94 | + 700: "#c2410c", |
| 95 | + 800: "#9a3412", |
| 96 | + 900: "#7c2d12", |
| 97 | + 950: "#431407", |
| 98 | + }, |
| 99 | + amber: { |
| 100 | + 50: "#fffbeb", |
| 101 | + 100: "#fef3c7", |
| 102 | + 200: "#fde68a", |
| 103 | + 300: "#fcd34d", |
| 104 | + 400: "#fbbf24", |
| 105 | + 500: "#f59e0b", |
| 106 | + 600: "#d97706", |
| 107 | + 700: "#b45309", |
| 108 | + 800: "#92400e", |
| 109 | + 900: "#78350f", |
| 110 | + 950: "#451a03", |
| 111 | + }, |
| 112 | + yellow: { |
| 113 | + 50: "#fefce8", |
| 114 | + 100: "#fef9c3", |
| 115 | + 200: "#fef08a", |
| 116 | + 300: "#fde047", |
| 117 | + 400: "#facc15", |
| 118 | + 500: "#eab308", |
| 119 | + 600: "#ca8a04", |
| 120 | + 700: "#a16207", |
| 121 | + 800: "#854d0e", |
| 122 | + 900: "#713f12", |
| 123 | + 950: "#422006", |
| 124 | + }, |
| 125 | + lime: { |
| 126 | + 50: "#f7fee7", |
| 127 | + 100: "#ecfccb", |
| 128 | + 200: "#d9f99d", |
| 129 | + 300: "#bef264", |
| 130 | + 400: "#a3e635", |
| 131 | + 500: "#84cc16", |
| 132 | + 600: "#65a30d", |
| 133 | + 700: "#4d7c0f", |
| 134 | + 800: "#3f6212", |
| 135 | + 900: "#365314", |
| 136 | + 950: "#1a2e05", |
| 137 | + }, |
| 138 | + green: { |
| 139 | + 50: "#f0fdf4", |
| 140 | + 100: "#dcfce7", |
| 141 | + 200: "#bbf7d0", |
| 142 | + 300: "#86efac", |
| 143 | + 400: "#4ade80", |
| 144 | + 500: "#22c55e", |
| 145 | + 600: "#16a34a", |
| 146 | + 700: "#15803d", |
| 147 | + 800: "#166534", |
| 148 | + 900: "#14532d", |
| 149 | + 950: "#052e16", |
| 150 | + }, |
| 151 | + emerald: { |
| 152 | + 50: "#ecfdf5", |
| 153 | + 100: "#d1fae5", |
| 154 | + 200: "#a7f3d0", |
| 155 | + 300: "#6ee7b7", |
| 156 | + 400: "#34d399", |
| 157 | + 500: "#10b981", |
| 158 | + 600: "#059669", |
| 159 | + 700: "#047857", |
| 160 | + 800: "#065f46", |
| 161 | + 900: "#064e3b", |
| 162 | + 950: "#022c22", |
| 163 | + }, |
| 164 | + teal: { |
| 165 | + 50: "#f0fdfa", |
| 166 | + 100: "#ccfbf1", |
| 167 | + 200: "#99f6e4", |
| 168 | + 300: "#5eead4", |
| 169 | + 400: "#2dd4bf", |
| 170 | + 500: "#14b8a6", |
| 171 | + 600: "#0d9488", |
| 172 | + 700: "#0f766e", |
| 173 | + 800: "#115e59", |
| 174 | + 900: "#134e4a", |
| 175 | + 950: "#042f2e", |
| 176 | + }, |
| 177 | + cyan: { |
| 178 | + 50: "#ecfeff", |
| 179 | + 100: "#cffafe", |
| 180 | + 200: "#a5f3fc", |
| 181 | + 300: "#67e8f9", |
| 182 | + 400: "#22d3ee", |
| 183 | + 500: "#06b6d4", |
| 184 | + 600: "#0891b2", |
| 185 | + 700: "#0e7490", |
| 186 | + 800: "#155e75", |
| 187 | + 900: "#164e63", |
| 188 | + 950: "#083344", |
| 189 | + }, |
| 190 | + sky: { |
| 191 | + 50: "#f0f9ff", |
| 192 | + 100: "#e0f2fe", |
| 193 | + 200: "#bae6fd", |
| 194 | + 300: "#7dd3fc", |
| 195 | + 400: "#38bdf8", |
| 196 | + 500: "#0ea5e9", |
| 197 | + 600: "#0284c7", |
| 198 | + 700: "#0369a1", |
| 199 | + 800: "#075985", |
| 200 | + 900: "#0c4a6e", |
| 201 | + 950: "#082f49", |
| 202 | + }, |
| 203 | + blue: { |
| 204 | + 50: "#eff6ff", |
| 205 | + 100: "#dbeafe", |
| 206 | + 200: "#bfdbfe", |
| 207 | + 300: "#93c5fd", |
| 208 | + 400: "#60a5fa", |
| 209 | + 500: "#3b82f6", |
| 210 | + 600: "#2563eb", |
| 211 | + 700: "#1d4ed8", |
| 212 | + 800: "#1e40af", |
| 213 | + 900: "#1e3a8a", |
| 214 | + 950: "#172554", |
| 215 | + }, |
| 216 | + indigo: { |
| 217 | + 50: "#eef2ff", |
| 218 | + 100: "#e0e7ff", |
| 219 | + 200: "#c7d2fe", |
| 220 | + 300: "#a5b4fc", |
| 221 | + 400: "#818cf8", |
| 222 | + 500: "#6366f1", |
| 223 | + 600: "#4f46e5", |
| 224 | + 700: "#4338ca", |
| 225 | + 800: "#3730a3", |
| 226 | + 900: "#312e81", |
| 227 | + 950: "#1e1b4b", |
| 228 | + }, |
| 229 | + violet: { |
| 230 | + 50: "#f5f3ff", |
| 231 | + 100: "#ede9fe", |
| 232 | + 200: "#ddd6fe", |
| 233 | + 300: "#c4b5fd", |
| 234 | + 400: "#a78bfa", |
| 235 | + 500: "#8b5cf6", |
| 236 | + 600: "#7c3aed", |
| 237 | + 700: "#6d28d9", |
| 238 | + 800: "#5b21b6", |
| 239 | + 900: "#4c1d95", |
| 240 | + 950: "#2e1065", |
| 241 | + }, |
| 242 | + purple: { |
| 243 | + 50: "#faf5ff", |
| 244 | + 100: "#f3e8ff", |
| 245 | + 200: "#e9d5ff", |
| 246 | + 300: "#d8b4fe", |
| 247 | + 400: "#c084fc", |
| 248 | + 500: "#a855f7", |
| 249 | + 600: "#9333ea", |
| 250 | + 700: "#7e22ce", |
| 251 | + 800: "#6b21a8", |
| 252 | + 900: "#581c87", |
| 253 | + 950: "#3b0764", |
| 254 | + }, |
| 255 | + fuchsia: { |
| 256 | + 50: "#fdf4ff", |
| 257 | + 100: "#fae8ff", |
| 258 | + 200: "#f5d0fe", |
| 259 | + 300: "#f0abfc", |
| 260 | + 400: "#e879f9", |
| 261 | + 500: "#d946ef", |
| 262 | + 600: "#c026d3", |
| 263 | + 700: "#a21caf", |
| 264 | + 800: "#86198f", |
| 265 | + 900: "#701a75", |
| 266 | + 950: "#4a044e", |
| 267 | + }, |
| 268 | + pink: { |
| 269 | + 50: "#fdf2f8", |
| 270 | + 100: "#fce7f3", |
| 271 | + 200: "#fbcfe8", |
| 272 | + 300: "#f9a8d4", |
| 273 | + 400: "#f472b6", |
| 274 | + 500: "#ec4899", |
| 275 | + 600: "#db2777", |
| 276 | + 700: "#be185d", |
| 277 | + 800: "#9d174d", |
| 278 | + 900: "#831843", |
| 279 | + 950: "#500724", |
| 280 | + }, |
| 281 | + rose: { |
| 282 | + 50: "#fff1f2", |
| 283 | + 100: "#ffe4e6", |
| 284 | + 200: "#fecdd3", |
| 285 | + 300: "#fda4af", |
| 286 | + 400: "#fb7185", |
| 287 | + 500: "#f43f5e", |
| 288 | + 600: "#e11d48", |
| 289 | + 700: "#be123c", |
| 290 | + 800: "#9f1239", |
| 291 | + 900: "#881337", |
| 292 | + 950: "#4c0519", |
| 293 | + }, |
| 294 | +} as any; |
| 295 | + |
| 296 | +export function Color({ name, shade, value }: { name: string; shade: string; value: string }) { |
| 297 | + let useShift = useShiftKey(); |
| 298 | + let panelRef = useRef<HTMLElement>(null); |
| 299 | + |
| 300 | + let colorVariableName = `--color-${name}-${shade}`; |
| 301 | + let hexValue = hexColors[name]?.[shade]; |
| 302 | + |
| 303 | + function copyHexToClipboard(e: React.MouseEvent) { |
| 304 | + e.preventDefault(); |
| 305 | + e.stopPropagation(); |
| 306 | + |
| 307 | + let panel = panelRef.current; |
| 308 | + if (!panel) return; |
| 309 | + |
| 310 | + let prevValue = panel.innerHTML; |
| 311 | + if (e.shiftKey) { |
| 312 | + navigator.clipboard.writeText(hexColors[name][shade]); |
| 313 | + panel.innerHTML = "Copied hex value!"; |
| 314 | + } else { |
| 315 | + navigator.clipboard.writeText(value); |
| 316 | + panel.innerHTML = "Copied to clipboard!"; |
| 317 | + } |
| 318 | + setTimeout(() => { |
| 319 | + panel.innerHTML = prevValue; |
| 320 | + }, 1300); |
| 321 | + } |
| 322 | + |
| 323 | + return ( |
| 324 | + <Tooltip as="div" showDelayMs={100} hideDelayMs={0} className="contents"> |
| 325 | + <TooltipTrigger> |
| 326 | + <Button |
| 327 | + type="button" |
| 328 | + onClick={copyHexToClipboard} |
| 329 | + style={{ backgroundColor: `var(${colorVariableName})` }} |
| 330 | + className={clsx( |
| 331 | + "aspect-1/1 w-full rounded-sm outline -outline-offset-1 outline-black/10 sm:rounded-md dark:outline-white/10", |
| 332 | + )} |
| 333 | + /> |
| 334 | + </TooltipTrigger> |
| 335 | + <TooltipPanel |
| 336 | + as="div" |
| 337 | + anchor="top" |
| 338 | + className="pointer-events-none z-10 flex translate-y-2 items-center gap-1 rounded-full border border-gray-950 bg-gray-950/90 py-0.5 pr-2 pb-1 pl-3 text-center font-mono text-xs/6 font-medium whitespace-nowrap text-white opacity-100 inset-ring inset-ring-white/10 transition-[opacity] starting:opacity-0" |
| 339 | + > |
| 340 | + <span |
| 341 | + ref={(panel) => { |
| 342 | + if (panel) panelRef.current = panel; |
| 343 | + }} |
| 344 | + > |
| 345 | + {useShift && hexValue ? hexValue : value} |
| 346 | + </span> |
| 347 | + </TooltipPanel> |
| 348 | + </Tooltip> |
| 349 | + ); |
| 350 | +} |
| 351 | + |
| 352 | +function useShiftKey(): boolean { |
| 353 | + let [isShiftPressed, setIsShiftPressed] = useState(false); |
| 354 | + |
| 355 | + useEffect(() => { |
| 356 | + let handleKeyDown = (event: KeyboardEvent) => { |
| 357 | + if (event.key === "Shift") { |
| 358 | + setIsShiftPressed(true); |
| 359 | + } |
| 360 | + }; |
| 361 | + |
| 362 | + let handleKeyUp = (event: KeyboardEvent) => { |
| 363 | + if (event.key === "Shift") { |
| 364 | + setIsShiftPressed(false); |
| 365 | + } |
| 366 | + }; |
| 367 | + |
| 368 | + window.addEventListener("keydown", handleKeyDown); |
| 369 | + window.addEventListener("keyup", handleKeyUp); |
| 370 | + |
| 371 | + return () => { |
| 372 | + window.removeEventListener("keydown", handleKeyDown); |
| 373 | + window.removeEventListener("keyup", handleKeyUp); |
| 374 | + }; |
| 375 | + }, []); |
| 376 | + |
| 377 | + return isShiftPressed; |
| 378 | +} |
0 commit comments