{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"list-02","type":"registry:component","title":"Project Updates Feed","description":"Project updates feed displaying various activity types with status indicators, metadata, and interactive elements. Features type-based icons, author information, timestamps, and customizable display options for project management dashboards.","dependencies":["lucide-react"],"registryDependencies":["avatar","badge","button","card","separator"],"files":[{"path":"src/registry/blocks/application/data-display/lists/list-02.tsx","content":"\"use client\";\n\nimport {\n  AlertCircle,\n  Calendar,\n  CheckCircle2,\n  Clock,\n  ExternalLink,\n  FileText,\n  GitCommit,\n  Info,\n  type LucideIcon,\n  MessageSquare,\n  Zap,\n} from \"lucide-react\";\nimport { cn } from \"@/registry/lib/utils\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/registry/ui/avatar\";\nimport { Badge } from \"@/registry/ui/badge\";\nimport { Button } from \"@/registry/ui/button\";\nimport { Card, CardContent } from \"@/registry/ui/card\";\nimport { Separator } from \"@/registry/ui/separator\";\n\ninterface ProjectUpdate {\n  id: number;\n  type:\n    | \"deployment\"\n    | \"comment\"\n    | \"milestone\"\n    | \"issue\"\n    | \"release\"\n    | \"meeting\";\n  title: string;\n  description: string;\n  author: {\n    name: string;\n    avatar: string;\n  };\n  timestamp: string;\n  project: string;\n  status: \"success\" | \"info\" | \"warning\" | \"error\";\n  metadata: Record<string, string | number>;\n}\n\nexport interface List02Props {\n  className?: string;\n}\n\nconst content: {\n  projectUpdates: ProjectUpdate[];\n  emptyState: { message: string; icon: LucideIcon };\n} = {\n  projectUpdates: [\n    {\n      id: 1,\n      type: \"deployment\" as const,\n      title: \"Production deployment successful\",\n      description:\n        \"Version 2.1.4 has been deployed to production environment with new user authentication features.\",\n      author: {\n        name: \"DevOps Bot\",\n        avatar: \"https://randomuser.me/api/portraits/men/1.jpg\",\n      },\n      timestamp: \"2 minutes ago\",\n      project: \"E-commerce Platform\",\n      status: \"success\",\n      metadata: {\n        version: \"v2.1.4\",\n        environment: \"Production\",\n        duration: \"3m 24s\",\n      },\n    },\n    {\n      id: 2,\n      type: \"comment\" as const,\n      title: \"New feedback on user interface\",\n      description:\n        \"Sarah provided detailed feedback on the checkout flow improvements and suggested additional optimizations.\",\n      author: {\n        name: \"Sarah Johnson\",\n        avatar: \"https://randomuser.me/api/portraits/women/2.jpg\",\n      },\n      timestamp: \"15 minutes ago\",\n      project: \"Mobile App\",\n      status: \"warning\",\n      metadata: {\n        comments: 3,\n        mentions: 2,\n      },\n    },\n    {\n      id: 3,\n      type: \"milestone\" as const,\n      title: \"Sprint 12 completed\",\n      description:\n        \"All planned features for Sprint 12 have been completed ahead of schedule. Ready for QA testing phase.\",\n      author: {\n        name: \"Michael Chen\",\n        avatar: \"https://randomuser.me/api/portraits/men/3.jpg\",\n      },\n      timestamp: \"1 hour ago\",\n      project: \"Analytics Dashboard\",\n      status: \"success\",\n      metadata: {\n        tasks: \"18/18\",\n        completion: \"100%\",\n      },\n    },\n    {\n      id: 4,\n      type: \"issue\" as const,\n      title: \"Critical bug reported in payment system\",\n      description:\n        \"Users experiencing timeout errors during payment processing. Investigation in progress.\",\n      author: {\n        name: \"Emily Rodriguez\",\n        avatar: \"https://randomuser.me/api/portraits/women/4.jpg\",\n      },\n      timestamp: \"2 hours ago\",\n      project: \"E-commerce Platform\",\n      status: \"error\",\n      metadata: {\n        priority: \"High\",\n        affected: \"12 users\",\n      },\n    },\n    {\n      id: 5,\n      type: \"release\" as const,\n      title: \"Feature release: Advanced analytics\",\n      description:\n        \"New analytics dashboard with real-time metrics and custom reporting capabilities is now live.\",\n      author: {\n        name: \"David Park\",\n        avatar: \"https://randomuser.me/api/portraits/men/5.jpg\",\n      },\n      timestamp: \"4 hours ago\",\n      project: \"Analytics Dashboard\",\n      status: \"success\",\n      metadata: {\n        features: 5,\n        version: \"v1.3.0\",\n      },\n    },\n    {\n      id: 6,\n      type: \"meeting\" as const,\n      title: \"Weekly team sync scheduled\",\n      description:\n        \"Review project progress, discuss blockers, and plan upcoming sprint activities.\",\n      author: {\n        name: \"Lisa Thompson\",\n        avatar: \"https://randomuser.me/api/portraits/women/6.jpg\",\n      },\n      timestamp: \"6 hours ago\",\n      project: \"Team Management\",\n      status: \"info\",\n      metadata: {\n        attendees: 8,\n        duration: \"1 hour\",\n      },\n    },\n  ],\n  emptyState: {\n    message: \"No updates found\",\n    icon: FileText,\n  },\n};\n\nfunction getTypeIcon(type: ProjectUpdate[\"type\"]): LucideIcon {\n  switch (type) {\n    case \"deployment\":\n      return Zap;\n    case \"comment\":\n      return MessageSquare;\n    case \"milestone\":\n      return CheckCircle2;\n    case \"issue\":\n      return AlertCircle;\n    case \"release\":\n      return GitCommit;\n    case \"meeting\":\n      return Calendar;\n    default:\n      return Info;\n  }\n}\n\nfunction getStatusColor(status: ProjectUpdate[\"status\"]): string {\n  switch (status) {\n    case \"success\":\n      return \"text-green-600 bg-green-100 dark:bg-green-900/20\";\n    case \"warning\":\n      return \"text-yellow-600 bg-yellow-100 dark:bg-yellow-900/20\";\n    case \"error\":\n      return \"text-red-600 bg-red-100 dark:bg-red-900/20\";\n    default:\n      return \"text-blue-600 bg-blue-100 dark:bg-blue-900/20\";\n  }\n}\n\nfunction getTypeColor(type: ProjectUpdate[\"type\"]): string {\n  switch (type) {\n    case \"deployment\":\n      return \"text-purple-600 bg-purple-100 dark:bg-purple-900/20\";\n    case \"comment\":\n      return \"text-blue-600 bg-blue-100 dark:bg-blue-900/20\";\n    case \"milestone\":\n      return \"text-green-600 bg-green-100 dark:bg-green-900/20\";\n    case \"issue\":\n      return \"text-red-600 bg-red-100 dark:bg-red-900/20\";\n    case \"release\":\n      return \"text-indigo-600 bg-indigo-100 dark:bg-indigo-900/20\";\n    case \"meeting\":\n      return \"text-orange-600 bg-orange-100 dark:bg-orange-900/20\";\n    default:\n      return \"text-gray-600 bg-gray-100 dark:bg-gray-900/20\";\n  }\n}\n\nexport function List02({ className }: List02Props) {\n  const handleViewClick = (update: ProjectUpdate, e: React.MouseEvent) => {\n    e.stopPropagation();\n    console.log(\"View clicked:\", update);\n  };\n\n  const handleAuthorClick = (\n    author: ProjectUpdate[\"author\"],\n    e: React.MouseEvent,\n  ) => {\n    e.stopPropagation();\n    console.log(\"Author clicked:\", author);\n  };\n\n  return (\n    <Card className={cn(\"w-full max-w-4xl mx-auto\", className)}>\n      <CardContent className=\"p-0\">\n        <div className=\"flex flex-col divide-y divide-border/50\">\n          {content.projectUpdates.map((update) => {\n            const TypeIcon = getTypeIcon(update.type);\n\n            return (\n              <div\n                key={update.id}\n                className=\"block px-4 py-6 hover:bg-muted/50 transition-colors\"\n                data-testid={`update-${update.id}`}\n              >\n                <div className=\"flex gap-4 items-start\">\n                  <div\n                    className={cn(\n                      \"p-2 rounded-full flex-shrink-0\",\n                      getTypeColor(update.type),\n                    )}\n                    data-testid={`type-icon-${update.id}`}\n                  >\n                    <TypeIcon className=\"h-4 w-4\" />\n                  </div>\n\n                  <div className=\"flex-1 min-w-0 space-y-2\">\n                    <div className=\"flex items-start justify-between space-x-2\">\n                      <div className=\"flex-1 min-w-0\">\n                        <h3 className=\"text-sm font-semibold text-foreground leading-tight\">\n                          {update.title}\n                        </h3>\n                        <p className=\"text-sm text-muted-foreground mt-1 leading-relaxed\">\n                          {update.description}\n                        </p>\n                      </div>\n                      <Badge\n                        className={cn(\n                          getStatusColor(update.status),\n                          \"text-xs flex-shrink-0\",\n                        )}\n                        variant=\"secondary\"\n                        data-testid={`status-badge-${update.id}`}\n                      >\n                        {update.status}\n                      </Badge>\n                    </div>\n\n                    <div\n                      className=\"flex flex-wrap gap-3 text-xs text-muted-foreground\"\n                      data-testid={`metadata-${update.id}`}\n                    >\n                      {Object.entries(update.metadata).map(([key, value]) => (\n                        <span key={key} className=\"flex items-center space-x-1\">\n                          <span className=\"font-medium\">{key}:</span>\n                          <span>{value}</span>\n                        </span>\n                      ))}\n                    </div>\n\n                    <div className=\"flex items-center justify-between pt-2\">\n                      <div className=\"flex items-center space-x-3\">\n                        <button\n                          type=\"button\"\n                          className=\"flex items-center space-x-2 cursor-pointer hover:bg-muted/50 rounded px-1 py-0.5 -mx-1 -my-0.5 transition-colors\"\n                          onClick={(e) => handleAuthorClick(update.author, e)}\n                          data-testid={`author-${update.id}`}\n                        >\n                          <Avatar className=\"h-6 w-6\">\n                            <AvatarImage\n                              src={update.author.avatar}\n                              alt={update.author.name}\n                            />\n                            <AvatarFallback className=\"text-xs\">\n                              {update.author.name\n                                .split(\" \")\n                                .map((n) => n[0])\n                                .join(\"\")}\n                            </AvatarFallback>\n                          </Avatar>\n                          <span className=\"text-xs text-muted-foreground\">\n                            {update.author.name}\n                          </span>\n                        </button>\n                        <Separator orientation=\"vertical\" className=\"h-4\" />\n                        <div\n                          className=\"flex items-center space-x-1\"\n                          data-testid={`timestamp-${update.id}`}\n                        >\n                          <Clock className=\"h-3 w-3\" />\n                          <span className=\"text-xs text-muted-foreground\">\n                            {update.timestamp}\n                          </span>\n                        </div>\n                        <Separator orientation=\"vertical\" className=\"h-4\" />\n                        <Badge variant=\"outline\" className=\"text-xs\">\n                          {update.project}\n                        </Badge>\n                      </div>\n                      <div>\n                        <Button\n                          variant=\"ghost\"\n                          size=\"sm\"\n                          className=\"h-6 text-xs\"\n                          onClick={(e) => handleViewClick(update, e)}\n                          data-testid={`view-button-${update.id}`}\n                        >\n                          <ExternalLink className=\"h-3 w-3 mr-1\" />\n                          View\n                        </Button>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              </div>\n            );\n          })}\n        </div>\n\n        {content.projectUpdates.length === 0 && (\n          <div className=\"p-8 text-center\" data-testid=\"empty-state\">\n            <content.emptyState.icon className=\"h-12 w-12 text-muted-foreground mx-auto mb-4\" />\n            <p className=\"text-muted-foreground\">\n              {content.emptyState.message}\n            </p>\n          </div>\n        )}\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"}]}