mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
237 lines
9.2 KiB
JavaScript
237 lines
9.2 KiB
JavaScript
/**
|
|
* Official Tailwind color palette for tier categories.
|
|
*
|
|
* Each key is stored in tier_categories.color (DB).
|
|
* badge — classes applied to <Badge> components
|
|
* panel — bg + border classes for upsell/info panels
|
|
* swatch — hex for the color picker dot in the admin UI
|
|
*/
|
|
export const TIER_COLOR_MAP = {
|
|
green: {
|
|
label: "Green",
|
|
swatch: "#22c55e",
|
|
badge: "bg-green-500 text-white border-0",
|
|
panel: { bg: "bg-green-50 dark:bg-green-950/30", border: "border-green-200 dark:border-green-800" },
|
|
},
|
|
purple: {
|
|
label: "Purple",
|
|
swatch: "#a855f7",
|
|
badge: "bg-gradient-to-r from-fuchsia-600 to-purple-600 text-white border-0",
|
|
panel: { bg: "bg-fuchsia-50 dark:bg-fuchsia-950/30", border: "border-fuchsia-200 dark:border-fuchsia-800" },
|
|
},
|
|
rose: {
|
|
label: "Rose",
|
|
swatch: "#f43f5e",
|
|
badge: "bg-gradient-to-r from-rose-500 to-red-600 text-white border-0",
|
|
panel: { bg: "bg-rose-50 dark:bg-rose-950/30", border: "border-rose-200 dark:border-rose-800" },
|
|
},
|
|
amber: {
|
|
label: "Amber",
|
|
swatch: "#f59e0b",
|
|
badge: "bg-gradient-to-r from-amber-400 to-orange-500 text-white border-0",
|
|
panel: { bg: "bg-amber-50 dark:bg-amber-950/30", border: "border-amber-200 dark:border-amber-800" },
|
|
},
|
|
sky: {
|
|
label: "Sky",
|
|
swatch: "#0ea5e9",
|
|
badge: "bg-gradient-to-r from-sky-500 to-blue-600 text-white border-0",
|
|
panel: { bg: "bg-sky-50 dark:bg-sky-950/30", border: "border-sky-200 dark:border-sky-800" },
|
|
},
|
|
indigo: {
|
|
label: "Indigo",
|
|
swatch: "#6366f1",
|
|
badge: "bg-gradient-to-r from-indigo-500 to-violet-600 text-white border-0",
|
|
panel: { bg: "bg-indigo-50 dark:bg-indigo-950/30", border: "border-indigo-200 dark:border-indigo-800" },
|
|
},
|
|
teal: {
|
|
label: "Teal",
|
|
swatch: "#14b8a6",
|
|
badge: "bg-gradient-to-r from-teal-500 to-emerald-600 text-white border-0",
|
|
panel: { bg: "bg-teal-50 dark:bg-teal-950/30", border: "border-teal-200 dark:border-teal-800" },
|
|
},
|
|
orange: {
|
|
label: "Orange",
|
|
swatch: "#f97316",
|
|
badge: "bg-gradient-to-r from-orange-500 to-red-500 text-white border-0",
|
|
panel: { bg: "bg-orange-50 dark:bg-orange-950/30", border: "border-orange-200 dark:border-orange-800" },
|
|
},
|
|
pink: {
|
|
label: "Pink",
|
|
swatch: "#ec4899",
|
|
badge: "bg-gradient-to-r from-pink-500 to-rose-500 text-white border-0",
|
|
panel: { bg: "bg-pink-50 dark:bg-pink-950/30", border: "border-pink-200 dark:border-pink-800" },
|
|
},
|
|
cyan: {
|
|
label: "Cyan",
|
|
swatch: "#06b6d4",
|
|
badge: "bg-gradient-to-r from-cyan-500 to-sky-500 text-white border-0",
|
|
panel: { bg: "bg-cyan-50 dark:bg-cyan-950/30", border: "border-cyan-200 dark:border-cyan-800" },
|
|
},
|
|
lime: {
|
|
label: "Lime",
|
|
swatch: "#84cc16",
|
|
badge: "bg-gradient-to-r from-lime-500 to-green-600 text-white border-0",
|
|
panel: { bg: "bg-lime-50 dark:bg-lime-950/30", border: "border-lime-200 dark:border-lime-800" },
|
|
},
|
|
slate: {
|
|
label: "Slate",
|
|
swatch: "#64748b",
|
|
badge: "bg-gradient-to-r from-slate-600 to-slate-800 text-white border-0",
|
|
panel: { bg: "bg-slate-50 dark:bg-slate-950/30", border: "border-slate-200 dark:border-slate-700" },
|
|
},
|
|
|
|
// ── Extended palette (18 more → 30 total) ───────────────────────────────────
|
|
red: {
|
|
label: "Red",
|
|
swatch: "#ef4444",
|
|
badge: "bg-gradient-to-r from-red-500 to-red-700 text-white border-0",
|
|
panel: { bg: "bg-red-50 dark:bg-red-950/30", border: "border-red-200 dark:border-red-800" },
|
|
},
|
|
yellow: {
|
|
label: "Yellow",
|
|
swatch: "#eab308",
|
|
badge: "bg-gradient-to-r from-yellow-400 to-yellow-600 text-white border-0",
|
|
panel: { bg: "bg-yellow-50 dark:bg-yellow-950/30", border: "border-yellow-200 dark:border-yellow-800" },
|
|
},
|
|
violet: {
|
|
label: "Violet",
|
|
swatch: "#7c3aed",
|
|
badge: "bg-gradient-to-r from-violet-500 to-purple-700 text-white border-0",
|
|
panel: { bg: "bg-violet-50 dark:bg-violet-950/30", border: "border-violet-200 dark:border-violet-800" },
|
|
},
|
|
fuchsia: {
|
|
label: "Fuchsia",
|
|
swatch: "#d946ef",
|
|
badge: "bg-gradient-to-r from-fuchsia-500 to-pink-700 text-white border-0",
|
|
panel: { bg: "bg-fuchsia-50 dark:bg-fuchsia-950/30", border: "border-fuchsia-200 dark:border-fuchsia-800" },
|
|
},
|
|
emerald: {
|
|
label: "Emerald",
|
|
swatch: "#10b981",
|
|
badge: "bg-gradient-to-r from-emerald-400 to-emerald-700 text-white border-0",
|
|
panel: { bg: "bg-emerald-50 dark:bg-emerald-950/30", border: "border-emerald-200 dark:border-emerald-800" },
|
|
},
|
|
blue: {
|
|
label: "Blue",
|
|
swatch: "#3b82f6",
|
|
badge: "bg-gradient-to-r from-blue-500 to-blue-700 text-white border-0",
|
|
panel: { bg: "bg-blue-50 dark:bg-blue-950/30", border: "border-blue-200 dark:border-blue-800" },
|
|
},
|
|
zinc: {
|
|
label: "Zinc",
|
|
swatch: "#71717a",
|
|
badge: "bg-gradient-to-r from-zinc-500 to-zinc-700 text-white border-0",
|
|
panel: { bg: "bg-zinc-50 dark:bg-zinc-950/30", border: "border-zinc-200 dark:border-zinc-800" },
|
|
},
|
|
stone: {
|
|
label: "Stone",
|
|
swatch: "#78716c",
|
|
badge: "bg-gradient-to-r from-stone-500 to-stone-700 text-white border-0",
|
|
panel: { bg: "bg-stone-50 dark:bg-stone-950/30", border: "border-stone-200 dark:border-stone-800" },
|
|
},
|
|
brown: {
|
|
label: "Brown",
|
|
swatch: "#a16207",
|
|
badge: "bg-gradient-to-r from-yellow-700 to-amber-900 text-white border-0",
|
|
panel: { bg: "bg-amber-50 dark:bg-amber-950/30", border: "border-amber-300 dark:border-amber-900" },
|
|
},
|
|
gold: {
|
|
label: "Gold",
|
|
swatch: "#ca8a04",
|
|
badge: "bg-gradient-to-r from-yellow-500 to-amber-700 text-white border-0",
|
|
panel: { bg: "bg-yellow-50 dark:bg-yellow-950/30", border: "border-yellow-300 dark:border-yellow-800" },
|
|
},
|
|
navy: {
|
|
label: "Navy",
|
|
swatch: "#1e40af",
|
|
badge: "bg-gradient-to-r from-blue-700 to-blue-900 text-white border-0",
|
|
panel: { bg: "bg-blue-50 dark:bg-blue-950/30", border: "border-blue-300 dark:border-blue-900" },
|
|
},
|
|
forest: {
|
|
label: "Forest",
|
|
swatch: "#166534",
|
|
badge: "bg-gradient-to-r from-green-700 to-green-900 text-white border-0",
|
|
panel: { bg: "bg-green-50 dark:bg-green-950/30", border: "border-green-300 dark:border-green-900" },
|
|
},
|
|
wine: {
|
|
label: "Wine",
|
|
swatch: "#9f1239",
|
|
badge: "bg-gradient-to-r from-rose-800 to-rose-950 text-white border-0",
|
|
panel: { bg: "bg-rose-50 dark:bg-rose-950/30", border: "border-rose-300 dark:border-rose-900" },
|
|
},
|
|
charcoal: {
|
|
label: "Charcoal",
|
|
swatch: "#374151",
|
|
badge: "bg-gradient-to-r from-gray-600 to-gray-900 text-white border-0",
|
|
panel: { bg: "bg-gray-50 dark:bg-gray-950/30", border: "border-gray-300 dark:border-gray-800" },
|
|
},
|
|
midnight: {
|
|
label: "Midnight",
|
|
swatch: "#312e81",
|
|
badge: "bg-gradient-to-r from-indigo-800 to-indigo-950 text-white border-0",
|
|
panel: { bg: "bg-indigo-50 dark:bg-indigo-950/30", border: "border-indigo-300 dark:border-indigo-900" },
|
|
},
|
|
lavender: {
|
|
label: "Lavender",
|
|
swatch: "#a78bfa",
|
|
badge: "bg-gradient-to-r from-violet-400 to-violet-600 text-white border-0",
|
|
panel: { bg: "bg-violet-50 dark:bg-violet-950/30", border: "border-violet-200 dark:border-violet-700" },
|
|
},
|
|
salmon: {
|
|
label: "Salmon",
|
|
swatch: "#fca5a5",
|
|
badge: "bg-gradient-to-r from-red-300 to-rose-600 text-white border-0",
|
|
panel: { bg: "bg-red-50 dark:bg-red-950/30", border: "border-red-200 dark:border-red-700" },
|
|
},
|
|
mint: {
|
|
label: "Mint",
|
|
swatch: "#6ee7b7",
|
|
badge: "bg-gradient-to-r from-emerald-300 to-teal-600 text-white border-0",
|
|
panel: { bg: "bg-emerald-50 dark:bg-emerald-950/30", border: "border-emerald-200 dark:border-emerald-700" },
|
|
},
|
|
};
|
|
|
|
/** Ordered list for the color picker UI. */
|
|
export const TIER_COLOR_OPTIONS = Object.entries(TIER_COLOR_MAP).map(([key, val]) => ({
|
|
key,
|
|
label: val.label,
|
|
swatch: val.swatch,
|
|
}));
|
|
|
|
/** Darkens (negative percent) or lightens (positive percent) a hex color. */
|
|
export function shadeColor(hex, percent) {
|
|
const num = parseInt(hex.replace("#", ""), 16);
|
|
const amt = Math.round(2.55 * percent);
|
|
const clamp = (v) => Math.max(0, Math.min(255, v));
|
|
const r = clamp((num >> 16) + amt);
|
|
const g = clamp(((num >> 8) & 0x00ff) + amt);
|
|
const b = clamp((num & 0x0000ff) + amt);
|
|
return "#" + (0x1000000 + r * 0x10000 + g * 0x100 + b).toString(16).slice(1);
|
|
}
|
|
|
|
// The perceived-brightness formula below underweights blue, so these read as
|
|
// "dark enough for white text" even though they're visually too light for it.
|
|
const FORCE_BLACK_TEXT = new Set(["sky", "blue", "cyan", "teal"]);
|
|
|
|
/** Returns "#000000" or "#ffffff", whichever reads better on top of the given hex color. */
|
|
export function getContrastText(hex, key) {
|
|
if (key && FORCE_BLACK_TEXT.has(key)) return "#000000";
|
|
const num = parseInt(hex.replace("#", ""), 16);
|
|
const r = (num >> 16) & 0xff;
|
|
const g = (num >> 8) & 0xff;
|
|
const b = num & 0xff;
|
|
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
return luminance > 0.6 ? "#000000" : "#ffffff";
|
|
}
|
|
|
|
/** Fallback when a stored color key is not in the map. */
|
|
const FALLBACK = TIER_COLOR_MAP.purple;
|
|
|
|
/**
|
|
* Returns the color definition for a stored color key.
|
|
* Falls back to purple for unknown keys.
|
|
*/
|
|
export function getTierColor(colorKey) {
|
|
return TIER_COLOR_MAP[colorKey] ?? FALLBACK;
|
|
}
|