{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-task",
  "type": "registry:item",
  "title": "Card Task",
  "description": "A task card component with badges, avatars, and action menu.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://roiui.com/r/alert-dialog.json",
    "https://roiui.com/r/avatar.json",
    "https://roiui.com/r/badge.json",
    "https://roiui.com/r/button.json",
    "https://roiui.com/r/card.json",
    "https://roiui.com/r/combobox.json",
    "https://roiui.com/r/dialog.json",
    "https://roiui.com/r/dropdown-menu.json",
    "https://roiui.com/r/tooltip.json"
  ],
  "files": [
    {
      "path": "registry/brook/blocks/card-task/components/card-task.tsx",
      "content": "import { Calendar, ListTodo, MessageCircleMore, MoreHorizontal, Trash, UserPlus, Users } from \"lucide-react\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/registry/brook/ui/avatar/avatar\";\nimport { Badge } from \"@/registry/brook/ui/badge/badge\";\nimport { Button } from \"@/registry/brook/ui/button/button\";\nimport {\n  Card,\n  CardAction,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/brook/ui/card/card\";\nimport {\n  DropdownMenu,\n  DropdownMenuItem,\n  DropdownMenuPopup,\n  DropdownMenuPortal,\n  DropdownMenuPositioner,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/registry/brook/ui/dropdown-menu/dropdown-menu\";\nimport {\n  Tooltip,\n  TooltipArrow,\n  TooltipPopup,\n  TooltipPortal,\n  TooltipPositioner,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/registry/brook/ui/tooltip/tooltip\";\nimport styles from \"./card-task.module.css\";\n\nexport type User = {\n  value: string;\n  label: string;\n  email: string;\n  avatar: string;\n};\n\ntype TaskCardProps = {\n  title: string;\n  description: string;\n  tags: Array<{\n    label: string;\n    variant?: \"default\" | \"destructive\";\n  }>;\n  collaborators: User[];\n  stats: {\n    comments: number;\n    subtasks: string;\n  };\n  dueDate: {\n    label: string;\n    variant?: \"default\" | \"warning\";\n  };\n  onAddCollaborator?: () => void;\n  onDeleteTask?: () => void;\n};\n\nfunction AvatarGroup({ users, maxDisplay = 3 }: { users: User[]; maxDisplay?: number }) {\n  const displayUsers = users.slice(0, maxDisplay);\n  const remainingCount = users.length - maxDisplay;\n\n  return (\n    <TooltipProvider>\n      <div style={{ display: \"flex\", alignItems: \"center\" }}>\n        {displayUsers.map((user, index) => (\n          <Tooltip key={user.value}>\n            <TooltipTrigger\n              render={\n                <div style={{ marginLeft: index > 0 ? \"-6px\" : \"0\" }}>\n                  <Avatar\n                    style={{\n                      width: \"24px\",\n                      height: \"24px\",\n                      border: \"2px solid var(--card)\",\n                    }}\n                  >\n                    <AvatarImage alt={`profile image for ${user.label}`} src={user.avatar} />\n                    <AvatarFallback>\n                      {user.label\n                        ?.split(\" \")\n                        .map((n: string) => n[0])\n                        .join(\"\") || \"??\"}\n                    </AvatarFallback>\n                  </Avatar>\n                </div>\n              }\n            />\n            <TooltipPortal>\n              <TooltipPositioner>\n                <TooltipPopup>\n                  <TooltipArrow />\n                  {user.label}\n                </TooltipPopup>\n              </TooltipPositioner>\n            </TooltipPortal>\n          </Tooltip>\n        ))}\n        {remainingCount > 0 && (\n          <div\n            style={{\n              width: \"24px\",\n              height: \"24px\",\n              borderRadius: \"50%\",\n              background: \"var(--muted)\",\n              color: \"var(--muted-foreground)\",\n              display: \"flex\",\n              alignItems: \"center\",\n              justifyContent: \"center\",\n              fontSize: \"0.625rem\",\n              fontWeight: 600,\n              marginLeft: \"-6px\",\n              border: \"2px solid var(--card)\",\n            }}\n          >\n            +{remainingCount}\n          </div>\n        )}\n      </div>\n    </TooltipProvider>\n  );\n}\n\nfunction TaskCardDropdownMenu({\n  onAddCollaborator,\n  onDeleteTask,\n}: {\n  onAddCollaborator?: () => void;\n  onDeleteTask?: () => void;\n}) {\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger\n        render={(props) => (\n          <Button {...props} aria-label=\"Task options\" size=\"icon\" variant=\"ghost\">\n            <MoreHorizontal\n              aria-hidden=\"true\"\n              size=\"16\"\n              style={{\n                color: \"oklch(from var(--muted-foreground) l c h / 0.8)\",\n              }}\n            />\n          </Button>\n        )}\n      />\n      <DropdownMenuPortal>\n        <DropdownMenuPositioner sideOffset={8}>\n          <DropdownMenuPopup render={<ul />} style={{ minWidth: \"160px\" }}>\n            <div style={{ height: \"4px\", width: \"100%\" }} />\n            <DropdownMenuItem icon={<UserPlus size=\"14\" />} onClick={onAddCollaborator} render={<li />}>\n              Add collaborator\n            </DropdownMenuItem>\n            <DropdownMenuItem icon={<Calendar size=\"14\" />} render={<li />}>\n              Change due date\n            </DropdownMenuItem>\n            <DropdownMenuSeparator />\n            <DropdownMenuItem icon={<Trash size=\"14\" />} onClick={onDeleteTask} render={<li />} variant=\"destructive\">\n              Delete task\n            </DropdownMenuItem>\n            <div style={{ height: \"4px\", width: \"100%\" }} />\n          </DropdownMenuPopup>\n        </DropdownMenuPositioner>\n      </DropdownMenuPortal>\n    </DropdownMenu>\n  );\n}\n\nexport function CardTask({\n  title,\n  description,\n  tags,\n  collaborators,\n  stats,\n  dueDate,\n  onAddCollaborator,\n  onDeleteTask,\n}: TaskCardProps) {\n  return (\n    <Card className={styles.taskCard}>\n      <CardHeader>\n        <CardTitle style={{ fontSize: \"1rem\" }}>{title}</CardTitle>\n        <CardDescription>{description}</CardDescription>\n        <CardAction>\n          <TaskCardDropdownMenu onAddCollaborator={onAddCollaborator} onDeleteTask={onDeleteTask} />\n        </CardAction>\n      </CardHeader>\n      <CardContent>\n        <div className={styles.contentContainer}>\n          <div className={styles.badgeContainer}>\n            {tags.map((tag) => (\n              <Badge key={tag.label} size=\"sm\" variant={tag.variant}>\n                <span>{tag.label}</span>\n              </Badge>\n            ))}\n          </div>\n          <AvatarGroup users={collaborators} />\n        </div>\n      </CardContent>\n\n      <CardFooter className={styles.taskFooter}>\n        <div className={styles.dividerWrapper}>\n          <div className={styles.divider} />\n        </div>\n        <div className={styles.footerContainer}>\n          <div className={styles.footerLeftGroup}>\n            <div aria-label={`${collaborators.length} collaborators`} className={styles.iconBubble} role=\"group\">\n              <Users aria-hidden=\"true\" size=\"14\" />\n              <span>{collaborators.length}</span>\n            </div>\n            <div aria-label={`${stats.comments} comments`} className={styles.iconBubble} role=\"group\">\n              <MessageCircleMore aria-hidden=\"true\" size=\"14\" />\n              <span>{stats.comments}</span>\n            </div>\n            <div aria-label={`${stats.subtasks} subtasks`} className={styles.iconBubble} role=\"group\">\n              <ListTodo aria-hidden=\"true\" size=\"14\" />\n              <span>{stats.subtasks}</span>\n            </div>\n          </div>\n          <div aria-label={`Due ${dueDate.label}`} className={styles.iconBubble} role=\"group\">\n            <Calendar aria-hidden=\"true\" size=\"14\" />\n            <span className={dueDate.variant === \"warning\" ? styles.tomorrowText : undefined}>{dueDate.label}</span>\n          </div>\n        </div>\n      </CardFooter>\n    </Card>\n  );\n}\n",
      "type": "registry:file",
      "target": "~/components/blocks/card-task/card-task.tsx"
    },
    {
      "path": "registry/brook/blocks/card-task/components/card-task.module.css",
      "content": ".taskCard[data-slot=\"card\"] {\n  width: 100%;\n  max-width: 300px;\n  gap: 1rem;\n  padding: 16px;\n}\n\n.contentContainer {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  width: 100%;\n}\n\n.badgeContainer {\n  display: flex;\n  gap: 0.5rem;\n  align-items: center;\n}\n\n.dividerWrapper {\n  padding: 5px 0;\n  width: calc(100% + 32px);\n  margin-left: -16px;\n  margin-right: -16px;\n}\n\n.divider {\n  height: 1px;\n  width: 100%;\n  border-bottom: 0.5px solid oklch(from var(--border) l c h / 0.6);\n}\n\n.footerContainer {\n  display: flex;\n  justify-content: space-between;\n  width: 100%;\n  color: oklch(from var(--muted-foreground) l c h / 0.6);\n  font-size: 12px;\n}\n\n.footerLeftGroup {\n  display: flex;\n  gap: 0.75rem;\n  align-items: center;\n}\n\n.iconBubble {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 4px;\n  padding: 4px 8px;\n  border-radius: 12px;\n  background-color: var(--mix-card-33-bg);\n  border: 0.5px solid oklch(from var(--border) l c h / 0.2);\n  transition: all 150ms ease;\n}\n\n.iconBubble:hover {\n  background-color: var(--mix-card-50-bg);\n  border-color: var(--border);\n}\n\n.tomorrowText {\n  color: var(--warning-foreground);\n}\n\n.taskFooter[data-slot=\"card-footer\"] {\n  margin-top: 0;\n  margin-bottom: 0;\n  display: flex;\n  flex-direction: column;\n  gap: 0.65rem;\n}\n\n@media (max-width: 1280px) {\n  .taskCard[data-slot=\"card\"] {\n    min-height: auto;\n  }\n}\n",
      "type": "registry:file",
      "target": "~/components/blocks/card-task/card-task.module.css"
    }
  ]
}