// ~/src/siteplane/components/avatar/avatar.tsx "use client"; import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"; import type React from "react"; import { cn, type WithStringClassName } from "../../system/utils/cn"; import { slotClass } from "../../system/utils/slot-class"; export type AvatarStatus = "online" | "away" | "busy" | "offline"; export type AvatarProps = WithStringClassName & { /** Presence dot at the bottom-end corner of the avatar. */ status?: AvatarStatus | undefined; /** Accessible name of the dot; defaults to the English status name. */ statusLabel?: string | undefined; }; const avatarStatusLabels: Record = { away: "Away", busy: "Busy", offline: "Offline", online: "Online", }; const avatarStatusClassNames: Record = { away: "bg-warning", busy: "bg-destructive", offline: "bg-muted-foreground", online: "bg-success", }; export function Avatar({ className, status, statusLabel, ...props }: AvatarProps): React.ReactElement { const root = ( ); if (!status) return root; // The avatar clips its image to the circle, so the dot sits beside it in a // wrapper that takes the avatar's size. The dot is a quarter of the avatar, // so it scales with every avatar size: 8 px at 32 px, 9 px at 36 px, 10 px at // 40 px. A 1.5 px ring in the colour of the surface separates it from the // photo: it reads --sp-rw-surface-color, which Card, Dialog, Popover and the // other surfaces publish, and falls back to the page background. Set // --avatar-status-ring on a surface that does not publish its colour. return ( {root} ); } export function AvatarImage({ className, ...props }: WithStringClassName): React.ReactElement { return ( ); } export function AvatarFallback({ className, ...props }: WithStringClassName): React.ReactElement { return ( ); } export { AvatarPrimitive }; // ~/src/siteplane/components/avatar/index.ts export * from "./avatar";