/** * Maps a berth's mooring-letter prefix (A, B, C…) to a subtle visual * accent. Pontoons cluster physically - A row is one dock, B another * - so the berth grid reads at a glance when each pontoon's rows * share a colour cue. Earlier iteration tinted the entire row * background; that proved visually noisy. This version keeps rows * white and surfaces the colour as a coloured left border, plus a * matching dot the column factory uses inside the Mooring # cell. * * Cycle wraps at the 8th letter; ports with more pontoons get * repeats (fine in practice - they don't sit adjacent on the page). */ const BORDER_CYCLE = [ 'border-l-4 border-l-rose-400', 'border-l-4 border-l-amber-400', 'border-l-4 border-l-emerald-400', 'border-l-4 border-l-sky-400', 'border-l-4 border-l-violet-400', 'border-l-4 border-l-orange-400', 'border-l-4 border-l-teal-400', 'border-l-4 border-l-fuchsia-400', ] as const; const DOT_CYCLE = [ 'bg-rose-400', 'bg-amber-400', 'bg-emerald-400', 'bg-sky-400', 'bg-violet-400', 'bg-orange-400', 'bg-teal-400', 'bg-fuchsia-400', ] as const; function indexFor(mooringNumber: string | null | undefined): number | null { if (!mooringNumber) return null; const letter = mooringNumber.charAt(0).toUpperCase(); if (letter < 'A' || letter > 'Z') return null; return (letter.charCodeAt(0) - 'A'.charCodeAt(0)) % BORDER_CYCLE.length; } export function mooringLetterTone(mooringNumber: string | null | undefined): string | undefined { const i = indexFor(mooringNumber); return i === null ? undefined : BORDER_CYCLE[i]; } export function mooringLetterDot(mooringNumber: string | null | undefined): string | undefined { const i = indexFor(mooringNumber); return i === null ? undefined : DOT_CYCLE[i]; }