// Name: Replace Colors with Hex // Description: Finds colors in text (rgb, rgba, hsl, lab, lch, oklab, oklch, color(), hex) and replaces them with closest #RRGGBB. // Author: ScottGuthart // GitHub: ScottGuthart import "@johnlindquist/kit" import Color from "colorjs.io" const compositeOnWhite = (srgb: Color) => { // srgb coords in [0..1] const a = typeof srgb.alpha === "number" ? srgb.alpha : 1 const c = srgb.to("srgb").toGamut({ space: "srgb" }) const [r, g, b] = c.coords as [number, number, number] const blend = (v: number) => Math.max(0, Math.min(1, a * v + (1 - a) * 1)) const toHex = (v: number) => { const i = Math.round(blend(v) * 255) return i.toString(16).padStart(2, "0") } return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toLowerCase() } const tryToHex = (raw: string): string | null => { try { // Normalize common typo "okch(" -> "oklch(" const s = raw.replace(/\bokch\s*\(/i, "oklch(") const parsed = Color.parse(s) if (!parsed) return null // Convert to srgb and then composite any alpha over white const srgb = parsed.to("srgb") return compositeOnWhite(srgb) } catch { return null } } // Match common CSS color notations and hexes // Note: Simple, pragmatic matcher (not a full CSS parser) const colorRegex = /#[0-9a-fA-F]{3,8}\b|\b(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|okch|color)\((?:[^)(]|\((?:[^)(]|\([^)(]*\))*\))*\)/g let selected = "" try { selected = await getSelectedText() } catch {} /** * Get input text from selection or editor */ let input = selected?.trim() if (!input) { input = await editor({ value: "", language: "md", hint: "Paste text to convert colors to hex, then press Cmd+S or Enter", footer: "All detected colors will be converted to #RRGGBB (alpha composited over white)", }) } let count = 0 const output = input.replace(colorRegex, m => { const hex = tryToHex(m) if (hex) { count++ return hex } return m }) if (selected) { await setSelectedText(output) await toast(`Converted ${count} color${count === 1 ? "" : "s"} to hex`) } else { await editor({ value: output, language: "md", hint: `Converted ${count} color${count === 1 ? "" : "s"} to hex`, footer: "Result shown above. Copy/paste as needed.", }) }