{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-community-user-presence-avatar",
  "title": "User Presence Avatar",
  "description": "A compact avatar group for showing online and offline users, with smooth animated transitions when presence changes.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "@animate-ui/components-animate-tooltip"
  ],
  "files": [
    {
      "path": "registry/components/community/user-presence-avatar/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { motion, LayoutGroup } from 'motion/react';\n\nimport {\n  Avatar,\n  AvatarFallback,\n  AvatarImage,\n} from '@/components/ui/avatar';\nimport {\n  TooltipProvider,\n  Tooltip,\n  TooltipContent,\n  TooltipTrigger,\n} from '@/components/animate-ui/components/animate/tooltip';\nimport { cn } from '@/lib/utils';\n\nconst USERS = [\n  {\n    id: 1,\n    src: 'https://pbs.twimg.com/profile_images/1897311929028255744/otxpL-ke_400x400.jpg',\n    fallback: 'AK',\n    tooltip: 'Arhamkhnz',\n    online: true,\n  },\n  {\n    id: 2,\n    src: 'https://pbs.twimg.com/profile_images/1948770261848756224/oPwqXMD6_400x400.jpg',\n    fallback: 'SK',\n    tooltip: 'Skyleen',\n    online: true,\n  },\n  {\n    id: 3,\n    src: 'https://pbs.twimg.com/profile_images/1593304942210478080/TUYae5z7_400x400.jpg',\n    fallback: 'CN',\n    tooltip: 'Shadcn',\n    online: true,\n  },\n  {\n    id: 4,\n    src: 'https://pbs.twimg.com/profile_images/1677042510839857154/Kq4tpySA_400x400.jpg',\n    fallback: 'AW',\n    tooltip: 'Adam Wathan',\n    online: false,\n  },\n  {\n    id: 5,\n    src: 'https://pbs.twimg.com/profile_images/1783856060249595904/8TfcCN0r_400x400.jpg',\n    fallback: 'GR',\n    tooltip: 'Guillermo Rauch',\n    online: false,\n  },\n  {\n    id: 6,\n    src: 'https://pbs.twimg.com/profile_images/1534700564810018816/anAuSfkp_400x400.jpg',\n    fallback: 'JH',\n    tooltip: 'Jhey',\n    online: false,\n  },\n];\n\nconst AVATAR_MOTION_TRANSITION = {\n  type: 'spring',\n  stiffness: 200,\n  damping: 25,\n} as const;\n\nconst GROUP_CONTAINER_TRANSITION = {\n  type: 'spring',\n  stiffness: 150,\n  damping: 20,\n} as const;\n\nfunction UserPresenceAvatar() {\n  const [users, setUsers] = React.useState(USERS);\n  const [togglingGroup, setTogglingGroup] = React.useState<\n    'online' | 'offline' | null\n  >(null);\n\n  const online = users.filter((u) => u.online);\n  const offline = users.filter((u) => !u.online);\n\n  const toggleStatus = (id: number) => {\n    const user = users.find((u) => u.id === id);\n    if (!user) return;\n\n    setTogglingGroup(user.online ? 'online' : 'offline');\n    setUsers((prev) => {\n      const idx = prev.findIndex((u) => u.id === id);\n      if (idx === -1) return prev;\n      const updated = [...prev];\n      const target = updated[idx];\n      if (!target) return prev;\n      updated.splice(idx, 1);\n      updated.push({ ...target, online: !target.online });\n      return updated;\n    });\n    // Reset group z-index after the animation duration (keep in sync with animation timing)\n    setTimeout(() => setTogglingGroup(null), 500);\n  };\n\n  return (\n    <div className=\"flex items-center gap-5\">\n      <LayoutGroup>\n        <TooltipProvider>\n          {online.length > 0 && (\n            <motion.div\n              layout\n              className={cn(\n                'bg-neutral-300 dark:bg-neutral-700 p-0.5 rounded-full',\n                togglingGroup === 'online' ? 'z-5' : 'z-10',\n              )}\n              transition={GROUP_CONTAINER_TRANSITION}\n            >\n              <div\n                key={online.map((u) => u.id).join('_') + '-online'}\n                className=\"flex items-center h-12 -space-x-3\"\n              >\n                {online.map((user) => (\n                  <Tooltip key={user.id}>\n                    <TooltipTrigger asChild>\n                      <motion.div\n                        layoutId={`avatar-${user.id}`}\n                        className=\"cursor-pointer\"\n                        onClick={() => toggleStatus(user.id)}\n                        animate={{\n                          filter: 'grayscale(0)',\n                          scale: 1,\n                        }}\n                        transition={AVATAR_MOTION_TRANSITION}\n                        title=\"Click to go offline\"\n                        initial={false}\n                      >\n                        <Avatar className=\"size-12 border-3 border-neutral-300 dark:border-neutral-700\">\n                          <AvatarImage src={user.src} />\n                          <AvatarFallback>{user.fallback}</AvatarFallback>\n                          <TooltipContent>\n                            <p>{user.tooltip}</p>\n                          </TooltipContent>\n                        </Avatar>\n                      </motion.div>\n                    </TooltipTrigger>\n                  </Tooltip>\n                ))}\n              </div>\n            </motion.div>\n          )}\n\n          {offline.length > 0 && (\n            <motion.div\n              layout\n              className={cn(\n                'bg-neutral-300 dark:bg-neutral-700 p-0.5 rounded-full',\n                togglingGroup === 'offline' ? 'z-5' : 'z-10',\n              )}\n              transition={GROUP_CONTAINER_TRANSITION}\n            >\n              <div\n                key={offline.map((u) => u.id).join('_') + '-offline'}\n                className=\"flex items-center h-12 -space-x-3\"\n              >\n                {offline.map((user) => (\n                  <Tooltip key={user.id}>\n                    <TooltipTrigger asChild>\n                      <motion.div\n                        layoutId={`avatar-${user.id}`}\n                        className=\"cursor-pointer\"\n                        onClick={() => toggleStatus(user.id)}\n                        animate={{\n                          filter: 'grayscale(1)',\n                          scale: 1,\n                        }}\n                        transition={AVATAR_MOTION_TRANSITION}\n                        title=\"Click to go online\"\n                        initial={false}\n                      >\n                        <Avatar className=\"size-12 border-3 border-neutral-300 dark:border-neutral-700\">\n                          <AvatarImage src={user.src} />\n                          <AvatarFallback>{user.fallback}</AvatarFallback>\n                          <TooltipContent>\n                            <p>{user.tooltip}</p>\n                          </TooltipContent>\n                        </Avatar>\n                      </motion.div>\n                    </TooltipTrigger>\n                  </Tooltip>\n                ))}\n              </div>\n            </motion.div>\n          )}\n        </TooltipProvider>\n      </LayoutGroup>\n    </div>\n  );\n}\n\nexport { UserPresenceAvatar };\n",
      "type": "registry:ui",
      "target": "components/animate-ui/components/community/user-presence-avatar.tsx"
    }
  ],
  "type": "registry:ui"
}