{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "tasks-dropdown", "title": "Tasks Dropdown", "description": "Navbar dropdown for displaying task progress with progress bars.", "registryDependencies": [ "https://raw.githubusercontent.com/dnachavez/adminlte-next/master/public/r/adminlte-theme.json", "https://raw.githubusercontent.com/dnachavez/adminlte-next/master/public/r/adminlte-dropdown.json", "https://raw.githubusercontent.com/dnachavez/adminlte-next/master/public/r/adminlte-progress.json" ], "files": [ { "path": "registry/new-york/tasks-dropdown/components/tasks-dropdown.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/registry/new-york/adminlte-theme/lib/cn\"\n\ntype TaskColor =\n | \"aqua\"\n | \"red\"\n | \"green\"\n | \"yellow\"\n | \"blue\"\n | \"purple\"\n | \"light-blue\"\n | \"primary\"\n | \"success\"\n | \"info\"\n | \"warning\"\n | \"danger\"\n\nconst taskColorStyles: Record = {\n aqua: \"bg-[#00c0ef]\",\n red: \"bg-[#dd4b39]\",\n green: \"bg-[#00a65a]\",\n yellow: \"bg-[#f39c12]\",\n blue: \"bg-[#3c8dbc]\",\n purple: \"bg-[#605ca8]\",\n \"light-blue\": \"bg-[#3c8dbc]\",\n primary: \"bg-[#3c8dbc]\",\n success: \"bg-[#00a65a]\",\n info: \"bg-[#00c0ef]\",\n warning: \"bg-[#f39c12]\",\n danger: \"bg-[#dd4b39]\",\n}\n\ninterface Task {\n id: string | number\n name: string\n progress: number\n color: TaskColor\n}\n\ninterface TasksDropdownProps extends React.HTMLAttributes {\n tasks: Task[]\n count?: number\n onViewAll?: () => void\n}\n\nconst TasksDropdown = React.forwardRef(\n ({ className, tasks, count, onViewAll, ...props }, ref) => {\n const [isOpen, setIsOpen] = React.useState(false)\n const containerRef = React.useRef(null)\n\n const displayCount = count ?? tasks.length\n\n React.useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false)\n }\n }\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside)\n }\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside)\n }, [isOpen])\n\n return (\n {\n ;(\n containerRef as React.MutableRefObject\n ).current = node\n if (typeof ref === \"function\") ref(node)\n else if (ref) ref.current = node\n }}\n className={cn(\"relative inline-block\", className)}\n {...props}\n >\n setIsOpen(!isOpen)}\n className=\"relative flex items-center justify-center w-[50px] h-[50px] bg-transparent border-none text-[var(--adminlte-skin-navbar-color)] cursor-pointer hover:bg-black/10\"\n aria-label=\"Tasks\"\n >\n {/* Flag icon */}\n \n \n \n {displayCount > 0 && (\n \n {displayCount}\n \n )}\n \n\n {isOpen && (\n
    \n
  • \n You have {displayCount} tasks\n
  • \n {tasks.map((task) => {\n const clampedProgress = Math.max(0, Math.min(100, task.progress))\n return (\n \n
    \n \n {task.name}\n \n \n {clampedProgress}%\n \n
    \n
    \n \n
    \n \n )\n })}\n
  • \n {\n e.preventDefault()\n onViewAll?.()\n }}\n className=\"text-[14px] text-[#3c8dbc] no-underline hover:underline\"\n >\n View all tasks\n \n
  • \n
\n )}\n \n )\n }\n)\nTasksDropdown.displayName = \"TasksDropdown\"\n\nexport { TasksDropdown }\nexport type { TasksDropdownProps, Task, TaskColor }\n", "type": "registry:component" } ], "type": "registry:component" }