{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"dropdown-02","type":"registry:component","title":"Alert Notification Dropdown","description":"A sophisticated notification center component with dropdown interface for managing alerts and notifications. Features unread count badges, categorized notification types (info, success, warning, error), visual type indicators, and comprehensive action controls. Includes notification status management, timestamp display, and bulk actions like 'View all' and 'Mark all read'. Uses content structure pattern for simplified props interface. Perfect for application headers, dashboards, and user notification systems requiring real-time alert management.","dependencies":["lucide-react"],"registryDependencies":["badge","button","dropdown-menu"],"files":[{"path":"src/registry/blocks/application/interactive/dropdowns/dropdown-02.tsx","content":"\"use client\";\n\nimport { Bell } from \"lucide-react\";\n\nimport { cn } from \"@/registry/lib/utils\";\nimport { Badge } from \"@/registry/ui/badge\";\nimport { Button } from \"@/registry/ui/button\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"@/registry/ui/dropdown-menu\";\n\ninterface AlertNotification {\n  id: string;\n  title: string;\n  description: string;\n  timestamp: string;\n  type: \"info\" | \"success\" | \"warning\" | \"error\";\n  isRead: boolean;\n}\n\nexport interface Dropdown02Props {\n  className?: string;\n}\n\nconst content: {\n  notifications: AlertNotification[];\n  emptyMessage: string;\n  maxHeight: string;\n  features: {\n    unreadBadge: boolean;\n    actions: {\n      viewAll: boolean;\n      markAllRead: boolean;\n    };\n  };\n} = {\n  notifications: [\n    {\n      id: \"1\",\n      title: \"System Update Available\",\n      description:\n        \"Version 2.1.0 is ready to install with new features and security improvements\",\n      timestamp: \"2 minutes ago\",\n      type: \"info\",\n      isRead: false,\n    },\n    {\n      id: \"2\",\n      title: \"Backup Completed Successfully\",\n      description:\n        \"Daily backup finished successfully and stored securely in the cloud\",\n      timestamp: \"1 hour ago\",\n      type: \"success\",\n      isRead: false,\n    },\n    {\n      id: \"3\",\n      title: \"Low Storage Warning\",\n      description:\n        \"Your storage is 85% full. Please free up some space to avoid disruptions\",\n      timestamp: \"3 hours ago\",\n      type: \"warning\",\n      isRead: true,\n    },\n    {\n      id: \"4\",\n      title: \"Security Alert\",\n      description:\n        \"Multiple failed login attempts detected from an unrecognized location\",\n      timestamp: \"5 hours ago\",\n      type: \"error\",\n      isRead: false,\n    },\n    {\n      id: \"5\",\n      title: \"New Feature Released\",\n      description:\n        \"Advanced analytics dashboard is now available in your account settings\",\n      timestamp: \"1 day ago\",\n      type: \"info\",\n      isRead: true,\n    },\n    {\n      id: \"6\",\n      title: \"Payment Successful\",\n      description: \"Your monthly subscription has been processed successfully\",\n      timestamp: \"2 days ago\",\n      type: \"success\",\n      isRead: true,\n    },\n  ],\n  emptyMessage: \"No notifications\",\n  maxHeight: \"max-h-64\",\n  features: {\n    unreadBadge: true,\n    actions: {\n      viewAll: true,\n      markAllRead: true,\n    },\n  },\n};\n\nconst getTypeColor = (type: AlertNotification[\"type\"]) => {\n  switch (type) {\n    case \"success\":\n      return \"bg-green-500\";\n    case \"warning\":\n      return \"bg-yellow-500\";\n    case \"error\":\n      return \"bg-red-500\";\n    default:\n      return \"bg-blue-500\";\n  }\n};\n\nexport function Dropdown02({ className }: Dropdown02Props) {\n  // Calculate unread count\n  const unreadCount = content.notifications.filter((n) => !n.isRead).length;\n\n  const handleNotificationClick = (notification: AlertNotification) => {\n    console.log(\"Notification clicked:\", notification);\n  };\n\n  const handleViewAllClick = () => {\n    console.log(\"View all notifications clicked\");\n  };\n\n  const handleMarkAllReadClick = () => {\n    console.log(\"Mark all read clicked\");\n  };\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button\n          variant=\"ghost\"\n          size=\"icon\"\n          className={cn(\"relative h-9 w-9 sm:h-8 sm:w-8\", className)}\n          data-testid=\"notification-trigger\"\n        >\n          <Bell className=\"h-4 w-4\" />\n          {content.features.unreadBadge && unreadCount > 0 && (\n            <Badge\n              className=\"absolute -top-1 -right-1 h-5 w-5 rounded-full p-0 text-xs\"\n              data-testid=\"unread-badge\"\n            >\n              {unreadCount > 99 ? \"99+\" : unreadCount}\n            </Badge>\n          )}\n          <span className=\"sr-only\">Notifications</span>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent\n        className=\"w-80\"\n        align=\"end\"\n        data-testid=\"notification-dropdown\"\n      >\n        <DropdownMenuLabel\n          className=\"flex items-center justify-between\"\n          data-testid=\"notification-header\"\n        >\n          Notifications\n          {content.features.unreadBadge && unreadCount > 0 && (\n            <Badge variant=\"secondary\" data-testid=\"unread-count-badge\">\n              {unreadCount} new\n            </Badge>\n          )}\n        </DropdownMenuLabel>\n        <DropdownMenuSeparator />\n\n        {content.notifications.length === 0 ? (\n          <div\n            className=\"p-4 text-center text-sm text-muted-foreground\"\n            data-testid=\"empty-state\"\n          >\n            {content.emptyMessage}\n          </div>\n        ) : (\n          <div\n            className={cn(content.maxHeight, \"overflow-y-auto\")}\n            data-testid=\"notifications-list\"\n          >\n            <div className=\"space-y-1 p-1\">\n              {content.notifications.map((notification) => (\n                <button\n                  key={notification.id}\n                  type=\"button\"\n                  className={cn(\n                    \"flex items-start space-x-3 p-3 rounded-md cursor-pointer transition-colors w-full text-left\",\n                    !notification.isRead\n                      ? \"bg-accent/50 hover:bg-accent/70\"\n                      : \"hover:bg-accent/50\",\n                  )}\n                  onClick={() => handleNotificationClick(notification)}\n                  aria-label={`Notification: ${notification.title}`}\n                  data-testid={`notification-item-${notification.id}`}\n                >\n                  <div\n                    className={cn(\n                      \"h-2 w-2 rounded-full mt-2\",\n                      getTypeColor(notification.type),\n                    )}\n                    data-testid={`notification-type-indicator-${notification.type}`}\n                  />\n                  <div className=\"flex-1 space-y-1\">\n                    <p\n                      className=\"text-sm font-medium\"\n                      data-testid=\"notification-title\"\n                    >\n                      {notification.title}\n                    </p>\n                    <p\n                      className=\"text-xs text-muted-foreground\"\n                      data-testid=\"notification-description\"\n                    >\n                      {notification.description}\n                    </p>\n                    <p\n                      className=\"text-xs text-muted-foreground\"\n                      data-testid=\"notification-timestamp\"\n                    >\n                      {notification.timestamp}\n                    </p>\n                  </div>\n                  {!notification.isRead && (\n                    <div\n                      className=\"h-2 w-2 bg-primary rounded-full mt-2\"\n                      data-testid=\"unread-indicator\"\n                    />\n                  )}\n                </button>\n              ))}\n            </div>\n          </div>\n        )}\n\n        <DropdownMenuSeparator />\n        <div className=\"flex gap-1 p-1\" data-testid=\"notification-actions\">\n          {content.features.actions.viewAll && (\n            <DropdownMenuItem\n              className=\"flex-1 text-center justify-center cursor-pointer\"\n              onClick={handleViewAllClick}\n              data-testid=\"view-all-action\"\n            >\n              View all\n            </DropdownMenuItem>\n          )}\n          {content.features.actions.markAllRead && unreadCount > 0 && (\n            <DropdownMenuItem\n              className=\"flex-1 text-center justify-center cursor-pointer\"\n              onClick={handleMarkAllReadClick}\n              data-testid=\"mark-all-read-action\"\n            >\n              Mark all read\n            </DropdownMenuItem>\n          )}\n        </div>\n      </DropdownMenuContent>\n    </DropdownMenu>\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"}]}