1
9import * as React from "react";
10import * as RadixAvatar from "@radix-ui/react-avatar";
11import { clsx } from "clsx";
12import { initials } from "../formatters.js";
13import { hashNameToHue } from "../color.js";
14
15export interface AvatarProps {
16 src?: string;
17
18 name: string;
19 size?: "sm" | "md" | "lg";
20 className?: string;
21}
22
23const SIZE: Record<NonNullable<AvatarProps["size"]>, string> = {
24 sm: "h-6 w-6 text-[10px]",
25 md: "h-8 w-8 text-xs",
26 lg: "h-12 w-12 text-base",
27};
28
29export function Avatar({ src, name, size = "md", className }: AvatarProps) {
30 const hue = hashNameToHue(name);
31 return (
32 <RadixAvatar.Root
33 className={clsx("relative flex shrink-0 overflow-hidden rounded-full", SIZE[size], className)}
34 >
35 {src !== undefined && <RadixAvatar.Image src={src} alt={name} />}
36 <RadixAvatar.Fallback
37 className="flex items-center justify-center font-medium"
38 style={{
39 backgroundColor: `hsl(${hue} 45% 88%)`,
40 color: `hsl(${hue} 55% 30%)`,
41 }}
42 aria-label={name}
43 >
44 {initials(name) || "?"}
45 </RadixAvatar.Fallback>
46 </RadixAvatar.Root>
47 );
48}
49