FrankWiles.com

Claude Created Color Copier

Today I’m working on a bunch of ReactJS frontend UI changes to a SaaS startup I’m working on named Gander in the Consumer Packaged Goods (CPG) space.

In previous coding sessions I had to keep opening up the Tailwind CSS file because while I love the names of these custom colors the designers gave us I haven’t quite memorized them yet. I know that fresh-hay is yellow-ish but I haven’t internalized if it’s the darker one or the lighter one quite yet.

Screenshot of the color Palette

Since I’m going to be doing a ton of color related stuff today I had Claude build me a little throw away tool to speed up the day.

So I fired up Claude Code CLI and asked it, typos and all!

In static/css/input.css I have a bunch of custom Tailwind CSS colors defined. I add a route to frontend/src/router.jsx that is /colors which has a simple page which just divides up the screen into evenly sized squares with the background set to one each of these colors. Please also make it display the CSS value (i.e. #xxxxxx) and the name minus the prefixing --color- so display goose-down rather than --color-goose-down and make it so when you hover over the color’s name it shows the “copy” icon and copies the name into the clipboard. This is only for local development speed up reasons and not for the actual users of this site.

I add a route? Apparently I need this second coffee. I actually hadn’t added the route and was wanting Claude to do it. Thankfully it understands my caffine deprived brain!

The React component it added isn’t bad:

jsx
import { useState } from "react"

const colors = [
  { name: "goose-down", value: "oklch(97.74% 0.02 97.52)" },
  { name: "dark-cream", value: "#f8eed2" },
  { name: "fresh-hay", value: "#e9e4a6" },
  { name: "chocolate", value: "#3b110c" },
  { name: "cocoa", value: "#5d3d3a" },
  { name: "lavender", value: "#bdb7fc" },
  { name: "coffee", value: "#a05f1a" },
  { name: "gander-red", value: "#da1c1c" },
  { name: "cinnamon", value: "#8b372b" },
  { name: "sunset-orange", value: "#dd5013" },
]

export const Colors = () => {
  const [copiedColor, setCopiedColor] = useState(null)

  const copyToClipboard = async (colorName) => {
    try {
      await navigator.clipboard.writeText(colorName)
      setCopiedColor(colorName)
      setTimeout(() => setCopiedColor(null), 2000)
    } catch (err) {
      console.error("Failed to copy text: ", err)
    }
  }

  return (
    <div className="p-8">
      <h1 className="text-3xl font-bold mb-8 text-chocolate">Color Palette</h1>
      <div className="grid grid-cols-5 gap-4 auto-rows-fr">
        {colors.map((color) => (
          <div
            key={color.name}
            className="aspect-square rounded-lg shadow-lg overflow-hidden border border-gray-200"
            style={{ backgroundColor: color.value }}
          >
            <div className="h-full flex flex-col justify-end">
              <div className="bg-white bg-opacity-90 p-3 backdrop-blur-sm">
                <div className="text-sm font-mono text-gray-600 mb-1">
                  {color.value}
                </div>
                <button
                  onClick={() => copyToClipboard(color.name)}
                  className="group flex items-center gap-2 text-sm font-medium text-gray-800 hover:text-blue-600 transition-colors"
                >
                  <span>{color.name}</span>
                  <svg
                    className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                  >
                    <path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth={2}
                      d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
                    />
                  </svg>
                  {copiedColor === color.name && (
                    <span className="text-green-600 text-xs">Copied!</span>
                  )}
                </button>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

The use of useState and the timeout to make the string Copied! disappear is a nice little bit of UI but definitely not needed for a silly little tool like this but it’s appreciated Claude.

Certainly adequate for a one shot prompt.

5 minutes and $0.22 USD later, while I got myself a coffee, for this tool is going to pay dividends all day. Sure it will save me some time and keystrokes, but it will MOSTLY keep me focused on what I’m trying to actually do and not get distracted or frustrated by the mechanics of it.

I intended this to be a throw away tool, but I think I’ll keep it!

P.S. Don’t ask why the first color uses oklch() and the others are all RGB hex values. I honestly don’t remember hah!

Headshot of Frank Wiles

Frank Wiles

Founder of REVSYS and former President of the Django Software Foundation . Expert in building, scaling and maintaining complex web applications. Want to reach out? Contact me here or use the social links below.