feat(order-color): add FNV-1a hash helper for per-order color stripes

This commit is contained in:
SJCoetz 2026-07-10 02:05:45 +02:00
parent 4985b8c946
commit 6477ebafcc

44
src/lib/order-color.ts Normal file
View file

@ -0,0 +1,44 @@
/**
* 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<OrderColor> = [
{ 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];
}