import { COLOR_HUES, type ColorHueKey } from "@sanity/color"; // Gray reads as "disabled" in the UI, so it never comes up as an identity color. const POSSIBLE_HUES: ColorHueKey[] = COLOR_HUES.filter((hue) => hue !== "gray"); /** * Returns the text and color for an identity marker. Hashing the id keeps its * color stable across sessions and across every surface that draws it. * Initials are at most two upper-cased characters. Names carry punctuation and * digits ("7-Eleven", "0xHoldings"), which a plain whitespace split reduces to * "7" or to nothing at all. * @public */ export function getInitials({ id, name }: { id: string; name: string }): { initials: string; color: ColorHueKey; } { const hash = id.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0); const index = hash % POSSIBLE_HUES.length; return { initials: resolveInitials(name), color: POSSIBLE_HUES[index], }; } const SYMBOLS = /[^\p{Alpha}\p{N}\p{White_Space}]/gu; const WHITESPACE = /\p{White_Space}+/u; const ALPHANUMERIC_SEGMENTS = /(\p{N}+|\p{Alpha}+)/gu; const IS_NUMERIC = /^\p{N}+$/u; function resolveInitials(name: string): string { if (!name) return ""; const namesArray = name .replace(SYMBOLS, "") .split(WHITESPACE) .filter(Boolean); if (namesArray.length === 0) return ""; if (namesArray.length === 1) { const word = namesArray[0]; const segments = word.match(ALPHANUMERIC_SEGMENTS) || []; if (segments.length === 0) return ""; if (segments.length === 1) { if (word.length === 1) { return word.toUpperCase(); } if (IS_NUMERIC.test(word)) { return `${word.charAt(0)}${word.charAt(1)}`.toUpperCase(); } return word.charAt(0).toUpperCase(); } return `${segments[0]!.charAt(0)}${segments[1].charAt(0)}`.toUpperCase(); } return `${namesArray[0].charAt(0)}${namesArray[namesArray.length - 1].charAt(0)}`.toUpperCase(); }