/** Solid fills for initials avatars — one per conversation, picked deterministically. */ const AVATAR_COLORS = [ "#0f8f8f", "#3b5bdb", "#8b5cf6", "#c98a1a", "#2fbf6f", "#c0392b", "#5b6270", ]; const initialsOf = (name?: string) => (name || "?") .trim() .split(/\s+/) .slice(0, 2) .map((part) => part[0]) .join("") .toUpperCase() || "?"; /** Stable index so a conversation keeps the same color across renders. */ const colorFor = (seed: string) => { let hash = 0; for (let i = 0; i < seed.length; i++) hash = (hash * 31 + seed.charCodeAt(i)) | 0; return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length]; }; interface AvatarProps { name?: string; src?: string; /** Seed for the fallback color — use the conversation or user id. */ seed?: string; size?: number; isOnline?: boolean; /** Renders the online dot slot at all (dot itself is shown only when online). */ showStatus?: boolean; } const Avatar = ({ name, src, seed, size = 34, isOnline = false, showStatus = true, }: AvatarProps) => (