{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"cards-03","type":"registry:component","title":"Activity Feed Card","description":"Activity feed card with real-time updates, type-based icons, user avatars, and action buttons. Features activity timeline with timestamps, user attribution, and dropdown menus. Perfect for dashboards, admin panels, and user engagement tracking.","dependencies":["lucide-react"],"registryDependencies":["card","button","badge","avatar","separator","dropdown-menu"],"files":[{"path":"src/registry/blocks/application/data-display/cards/cards-03.tsx","content":"\"use client\";\n\nimport {\n  AlertCircle,\n  Calendar,\n  CheckCircle,\n  GitCommit,\n  MessageSquare,\n  MoreHorizontal,\n} from \"lucide-react\";\n\nimport { cn } from \"@/registry/lib/utils\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/registry/ui/avatar\";\nimport { Button } from \"@/registry/ui/button\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/ui/card\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/registry/ui/dropdown-menu\";\nimport { Separator } from \"@/registry/ui/separator\";\n\nexport interface Cards03Props {\n  className?: string;\n}\n\nconst content = {\n  header: {\n    title: \"Recent Activity\",\n    description: \"Latest updates and events\",\n  },\n  activities: [\n    {\n      id: 1,\n      type: \"success\" as const,\n      icon: CheckCircle,\n      title: \"Project deployment successful\",\n      description:\n        \"Your application has been deployed to production successfully.\",\n      timestamp: \"2 minutes ago\",\n      user: {\n        name: \"System\",\n        avatar: \"https://randomuser.me/api/portraits/men/6.jpg\",\n      },\n      actionable: true,\n    },\n    {\n      id: 2,\n      type: \"info\" as const,\n      icon: MessageSquare,\n      title: \"New comment on your post\",\n      description: \"Sarah Johnson commented on your project update.\",\n      timestamp: \"15 minutes ago\",\n      user: {\n        name: \"Sarah Johnson\",\n        avatar: \"https://randomuser.me/api/portraits/women/7.jpg\",\n      },\n      actionable: true,\n    },\n    {\n      id: 3,\n      type: \"warning\" as const,\n      icon: AlertCircle,\n      title: \"Server maintenance scheduled\",\n      description: \"Scheduled maintenance will begin at 2:00 AM UTC tomorrow.\",\n      timestamp: \"1 hour ago\",\n      user: {\n        name: \"DevOps Team\",\n        avatar: \"https://randomuser.me/api/portraits/men/7.jpg\",\n      },\n      actionable: false,\n    },\n    {\n      id: 4,\n      type: \"info\" as const,\n      icon: GitCommit,\n      title: \"Code review requested\",\n      description: \"Michael Chen requested a review for PR #234.\",\n      timestamp: \"2 hours ago\",\n      user: {\n        name: \"Michael Chen\",\n        avatar: \"https://randomuser.me/api/portraits/men/8.jpg\",\n      },\n      actionable: true,\n    },\n    {\n      id: 5,\n      type: \"info\" as const,\n      icon: Calendar,\n      title: \"Meeting reminder\",\n      description: \"Team standup meeting starts in 30 minutes.\",\n      timestamp: \"3 hours ago\",\n      user: {\n        name: \"Calendar\",\n        avatar: \"https://randomuser.me/api/portraits/women/8.jpg\",\n      },\n      actionable: false,\n    },\n  ],\n  buttons: {\n    viewAll: {\n      text: \"View All Activity\",\n      variant: \"outline\" as const,\n    },\n  },\n};\n\nexport function Cards03({ className }: Cards03Props) {\n  const getTypeColor = (type: string) => {\n    switch (type) {\n      case \"success\":\n        return \"text-green-600\";\n      case \"warning\":\n        return \"text-yellow-600\";\n      case \"error\":\n        return \"text-red-600\";\n      default:\n        return \"text-blue-600\";\n    }\n  };\n\n  const getTypeBg = (type: string) => {\n    switch (type) {\n      case \"success\":\n        return \"bg-green-100 dark:bg-green-900/20\";\n      case \"warning\":\n        return \"bg-yellow-100 dark:bg-yellow-900/20\";\n      case \"error\":\n        return \"bg-red-100 dark:bg-red-900/20\";\n      default:\n        return \"bg-blue-100 dark:bg-blue-900/20\";\n    }\n  };\n\n  const getInitials = (name: string) => {\n    return name\n      .split(\" \")\n      .map((n) => n[0])\n      .join(\"\")\n      .toUpperCase();\n  };\n\n  const handleDropdownAction = (action: string) => {\n    console.log(`${action} action performed`);\n  };\n\n  const handleView = (activity: (typeof content.activities)[0]) => {\n    console.log(\"View activity:\", activity.title);\n  };\n\n  const handleViewAll = () => {\n    console.log(\"View all activities\");\n  };\n\n  return (\n    <Card\n      className={cn(\"h-fit max-w-2xl\", className)}\n      data-testid=\"activity-card\"\n    >\n      <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-4\">\n        <div>\n          <CardTitle className=\"text-lg\">{content.header.title}</CardTitle>\n          <CardDescription>{content.header.description}</CardDescription>\n        </div>\n        <DropdownMenu>\n          <DropdownMenuTrigger asChild>\n            <Button\n              variant=\"ghost\"\n              size=\"icon\"\n              className=\"h-8 w-8\"\n              data-testid=\"activity-menu\"\n            >\n              <MoreHorizontal className=\"h-4 w-4\" />\n            </Button>\n          </DropdownMenuTrigger>\n          <DropdownMenuContent align=\"end\" data-testid=\"activity-menu-content\">\n            <DropdownMenuItem\n              onClick={() => handleDropdownAction(\"mark-all-read\")}\n              data-testid=\"mark-all-read\"\n            >\n              Mark all as read\n            </DropdownMenuItem>\n            <DropdownMenuItem\n              onClick={() => handleDropdownAction(\"filter\")}\n              data-testid=\"filter-activities\"\n            >\n              Filter activities\n            </DropdownMenuItem>\n            <DropdownMenuItem\n              onClick={() => handleDropdownAction(\"export\")}\n              data-testid=\"export-log\"\n            >\n              Export log\n            </DropdownMenuItem>\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </CardHeader>\n      <CardContent>\n        <div className=\"space-y-4\">\n          {content.activities.map((item, index) => {\n            const Icon = item.icon;\n            return (\n              <div key={item.id}>\n                <div\n                  className=\"flex items-start space-x-3\"\n                  data-testid={`activity-item-${item.id}`}\n                >\n                  <div className={cn(\"p-2 rounded-full\", getTypeBg(item.type))}>\n                    <Icon className={cn(\"h-4 w-4\", getTypeColor(item.type))} />\n                  </div>\n                  <div className=\"flex-1 min-w-0 space-y-1\">\n                    <div className=\"flex items-center justify-between\">\n                      <p className=\"text-sm font-medium text-foreground truncate\">\n                        {item.title}\n                      </p>\n                      <span\n                        className=\"text-xs text-muted-foreground whitespace-nowrap ml-2\"\n                        data-testid={`timestamp-${item.id}`}\n                      >\n                        {item.timestamp}\n                      </span>\n                    </div>\n                    <p\n                      className=\"text-sm text-muted-foreground leading-relaxed\"\n                      data-testid={`description-${item.id}`}\n                    >\n                      {item.description}\n                    </p>\n                    <div className=\"flex items-center justify-between pt-1\">\n                      <div className=\"flex items-center space-x-2\">\n                        <Avatar className=\"h-5 w-5\">\n                          <AvatarImage\n                            src={item.user.avatar}\n                            alt={item.user.name}\n                          />\n                          <AvatarFallback className=\"text-xs\">\n                            {getInitials(item.user.name)}\n                          </AvatarFallback>\n                        </Avatar>\n                        <span\n                          className=\"text-xs text-muted-foreground\"\n                          data-testid={`user-name-${item.id}`}\n                        >\n                          {item.user.name}\n                        </span>\n                      </div>\n                      {item.actionable && (\n                        <Button\n                          variant=\"ghost\"\n                          size=\"sm\"\n                          className=\"h-6 text-xs\"\n                          onClick={() => handleView(item)}\n                          data-testid={`view-button-${item.id}`}\n                        >\n                          View\n                        </Button>\n                      )}\n                    </div>\n                  </div>\n                </div>\n                {index < content.activities.length - 1 && (\n                  <Separator className=\"mt-4\" />\n                )}\n              </div>\n            );\n          })}\n        </div>\n        <div className=\"pt-4\">\n          <Button\n            variant={content.buttons.viewAll.variant}\n            className=\"w-full bg-transparent\"\n            size=\"sm\"\n            onClick={handleViewAll}\n            data-testid=\"view-all-button\"\n          >\n            {content.buttons.viewAll.text}\n          </Button>\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n","type":"registry:component"},{"path":"src/registry/lib/utils.ts","content":"import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n","type":"registry:lib"}]}