← Optimotive UI/components/Agent Avatar
component

Agent Avatar

Circular avatar with colored status ring (online/busy/idle/offline), emoji or initials fallback.

Installation

npx shadcn@latest add https://optimotive-ui.dev.optimotive-tools.co.uk/registry.json agent-avatar

Preview

Source

components/agent-avatar.tsx
"use client"

import * as React from "react"
import { cn } from "@/lib/utils"

export type AgentStatus = "online" | "busy" | "offline" | "idle"

export interface AgentAvatarProps extends React.HTMLAttributes<HTMLDivElement> {
  name: string
  emoji?: string
  status?: AgentStatus
  size?: "sm" | "md" | "lg"
}

const sizeMap = {
  sm: { outer: "w-8 h-8", text: "text-xs", ring: "ring-2", dot: "w-2 h-2 border" },
  md: { outer: "w-10 h-10", text: "text-sm", ring: "ring-2", dot: "w-2.5 h-2.5 border-2" },
  lg: { outer: "w-14 h-14", text: "text-lg", ring: "ring-2", dot: "w-3.5 h-3.5 border-2" },
}

const statusRing: Record<AgentStatus, string> = {
  online: "ring-emerald-500",
  busy: "ring-amber-400",
  idle: "ring-blue-400",
  offline: "ring-slate-600",
}

const statusDot: Record<AgentStatus, string> = {
  online: "bg-emerald-500",
  busy: "bg-amber-400",
  idle: "bg-blue-400",
  offline: "bg-slate-600",
}

function getInitials(name: string) {
  return name
    .split(" ")
    .map((n) => n[0])
    .join("")
    .toUpperCase()
    .slice(0, 2)
}

export function AgentAvatar({ name, emoji, status = "offline", size = "md", className, ...props }: AgentAvatarProps) {
  const s = sizeMap[size]
  return (
    <div className={cn("relative inline-flex shrink-0", className)} {...props}>
      <div
        className={cn(
          "rounded-full flex items-center justify-center bg-slate-800 text-white font-semibold select-none",
          s.outer,
          s.text,
          s.ring,
          statusRing[status]
        )}
      >
        {emoji ?? getInitials(name)}
      </div>
      <span
        className={cn(
          "absolute bottom-0 right-0 rounded-full border-slate-950",
          s.dot,
          statusDot[status],
          status === "online" && "animate-pulse"
        )}
      />
    </div>
  )
}