- Run record
- loading
Loading this Run…
Loading the Revisions of this Run…
A published source file of Revision 0 of Boardly — Website Relaunch 1.1.0, shown as text in the browser.
import type { Member } from "../types";
import { IconPerson } from "../icons";
const MEMBER_COLORS: Record<string, { bg: string; fg: string }> = {
maya: { bg: "#d9efed", fg: "#0b5f5a" },
tomas: { bg: "#dfe7fd", fg: "#2b459c" },
aiko: { bg: "#fbe0ec", fg: "#9c1b56" },
jonah: { bg: "#fbead2", fg: "#8a5200" },
priya: { bg: "#e8e0fb", fg: "#5b2bb8" },
};
const FALLBACK_COLORS = [
{ bg: "#d9efed", fg: "#0b5f5a" },
{ bg: "#dfe7fd", fg: "#2b459c" },
{ bg: "#fbe0ec", fg: "#9c1b56" },
{ bg: "#fbead2", fg: "#8a5200" },
{ bg: "#e8e0fb", fg: "#5b2bb8" },
];
export function memberColor(id: string, index = 0) {
return MEMBER_COLORS[id] ?? FALLBACK_COLORS[index % FALLBACK_COLORS.length];
}
export function initials(name: string): string {
const parts = name.trim().split(/\s+/).filter(Boolean);
if (parts.length === 0) return "?";
const first = parts[0][0] ?? "";
const last = parts.length > 1 ? (parts[parts.length - 1][0] ?? "") : "";
return (first + last).toUpperCase();
}
interface AvatarProps {
member: Member | null;
index?: number;
size?: number;
className?: string;
}
export function Avatar({ member, index = 0, size = 22, className }: AvatarProps) {
if (!member) {
return (
<span
className={`avatar avatar-empty ${className ?? ""}`}
style={{ width: size, height: size }}
aria-hidden="true"
>
<IconPerson size={Math.round(size * 0.6)} />
</span>
);
}
const color = memberColor(member.id, index);
return (
<span
className={`avatar ${className ?? ""}`}
style={{
width: size,
height: size,
background: color.bg,
color: color.fg,
fontSize: Math.max(8, Math.round(size * 0.42)),
}}
aria-hidden="true"
>
{initials(member.name)}
</span>
);
}Source is browser-viewable only. There is no download or archive endpoint, and no additional license is granted beyond inspection and research.