44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
/**
|
|
* 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];
|
|
}
|