/** * Per-order color helper. * * Hashes an order id into one of six curated Tailwind colours so each * order group renders with a stable, distinct accent on list pages * (Collection Confirm, Invoicing). The same id always picks the same * colour across every render and every page. * * FNV-1a gives an even distribution with no deps. Empty / null ids * fall back to the first palette entry so the helper is total. */ export type OrderColor = { /** Left-edge stripe class, e.g. `border-emerald-500/40`. */ borderClass: string; /** Faint body tint, e.g. `bg-emerald-500/8`. Available for callers * that want a coloured background; not used by the current pages. */ bgClass: string; }; export const ORDER_COLOR_PALETTE: ReadonlyArray = [ { borderClass: "border-emerald-500/40", bgClass: "bg-emerald-500/8" }, { borderClass: "border-sky-500/40", bgClass: "bg-sky-500/8" }, { borderClass: "border-amber-500/40", bgClass: "bg-amber-500/8" }, { borderClass: "border-rose-500/40", bgClass: "bg-rose-500/8" }, { borderClass: "border-violet-500/40", bgClass: "bg-violet-500/8" }, { borderClass: "border-teal-500/40", bgClass: "bg-teal-500/8" }, ]; const FNV_OFFSET = 0x811c9dc5; const FNV_PRIME = 0x01000193; const PALETTE_SIZE = ORDER_COLOR_PALETTE.length; export function colorForOrder(orderId: string | undefined | null): OrderColor { if (!orderId) return ORDER_COLOR_PALETTE[0]; let hash = FNV_OFFSET; for (let i = 0; i < orderId.length; i++) { hash ^= orderId.charCodeAt(i); // `>>> 0` keeps the value in the uint32 range so Math.imul // doesn't produce a negative result on overflow. hash = Math.imul(hash, FNV_PRIME) >>> 0; } return ORDER_COLOR_PALETTE[hash % PALETTE_SIZE]; }