AudienceAvatar.tsx1.7 KBView on GitHub import type { LucideIcon } from 'lucide-react';
import { personColor } from '@/components/ui/person-avatar';
import { cn } from '@/lib/utils';
/**
* A CROWD, as a round mark — the organisation, or everyone who holds one agent.
*
* The share panel's list is a list of subjects, and two of them are not people. Drawn
* with `PersonAvatar` they get initials, so "Everyone with this agent" arrives as a disc
* reading `EW` in a column of real faces — a person who does not exist, which is worse
* than an unlabelled mark because the reader tries to place them.
*
* It takes the SAME tint as a person's disc (`personColor`, hashed off the subject's id)
* and the same white foreground. A pale circle with a grey glyph beside a column of
* saturated discs is a different kind of mark, and the eye changes gear at exactly the
* row where nothing new is happening. The glyph is what says "this is not one person".
*
* `aria-hidden` because the row's own text already names the subject; the disc would
* otherwise be read out twice.
*/
export function AudienceAvatar({
/** What the tint is hashed off — the organisation's id, or the agent's. */
seed,
icon: Icon,
className,
}: {
seed: string;
icon: LucideIcon;
className?: string;
}) {
return (
<span
aria-hidden
className={cn(
'flex size-5 shrink-0 items-center justify-center rounded-full text-white',
className,
)}
// Inline because the tint is data, not a token — see `PersonAvatar`, which says
// why a class per palette entry cannot survive a production build.
style={{ backgroundColor: personColor(seed) }}
>
<Icon className="size-3" />
</span>
);
}