{ "name": "shadcn-sidebar", "type": "registry:block", "registryDependencies": [ "avatar", "button", "card", "collapsible", "dropdown-menu", "scroll-area", "sheet", "tooltip" ], "dependencies": [ "immer", "zustand", "next-themes" ], "tailwind": { "config": { "theme": { "extend": { "keyframes": { "accordion-down": { "from": { "height": "0" }, "to": { "height": "var(--radix-accordion-content-height)" } }, "accordion-up": { "from": { "height": "var(--radix-accordion-content-height)" }, "to": { "height": "0" } }, "collapsible-down": { "from": { "height": "0" }, "to": { "height": "var(--radix-collapsible-content-height)" } }, "collapsible-up": { "from": { "height": "var(--radix-collapsible-content-height)" }, "to": { "height": "0" } } }, "animation": { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", "collapsible-down": "collapsible-down 0.2s ease-out", "collapsible-up": "collapsible-up 0.2s ease-out" } } } } }, "files": [ { "type": "registry:hook", "content": "import { create } from \"zustand\";\nimport { persist, createJSONStorage } from \"zustand/middleware\";\nimport { produce } from \"immer\";\n\ntype SidebarSettings = { disabled: boolean; isHoverOpen: boolean };\ntype SidebarStore = {\n isOpen: boolean;\n isHover: boolean;\n settings: SidebarSettings;\n toggleOpen: () => void;\n setIsOpen: (isOpen: boolean) => void;\n setIsHover: (isHover: boolean) => void;\n getOpenState: () => boolean;\n setSettings: (settings: Partial) => void;\n};\n\nexport const useSidebar = create(\n persist(\n (set, get) => ({\n isOpen: true,\n isHover: false,\n settings: { disabled: false, isHoverOpen: false },\n toggleOpen: () => {\n set({ isOpen: !get().isOpen });\n },\n setIsOpen: (isOpen: boolean) => {\n set({ isOpen });\n },\n setIsHover: (isHover: boolean) => {\n set({ isHover });\n },\n getOpenState: () => {\n const state = get();\n return state.isOpen || (state.settings.isHoverOpen && state.isHover);\n },\n setSettings: (settings: Partial) => {\n set(\n produce((state: SidebarStore) => {\n state.settings = { ...state.settings, ...settings };\n })\n );\n }\n }),\n {\n name: \"sidebar\",\n storage: createJSONStorage(() => localStorage)\n }\n )\n);\n", "path": "hooks/use-sidebar.ts", "target": "hooks/use-sidebar.ts" }, { "type": "registry:hook", "content": "import { useState, useEffect } from \"react\";\n/**\n * This hook fix hydration when use persist to save hook data to localStorage\n */\nexport const useStore = (\n store: (callback: (state: T) => unknown) => unknown,\n callback: (state: T) => F\n) => {\n const result = store(callback) as F;\n const [data, setData] = useState();\n\n useEffect(() => {\n setData(result);\n }, [result]);\n\n return data;\n};\n", "path": "hooks/use-store.ts", "target": "hooks/use-store.ts" }, { "type": "registry:component", "content": "\"use client\";\n\nimport { Footer } from \"@/components/admin-panel/footer\";\nimport { Sidebar } from \"@/components/admin-panel/sidebar\";\nimport { useSidebar } from \"@/hooks/use-sidebar\";\nimport { useStore } from \"@/hooks/use-store\";\nimport { cn } from \"@/lib/utils\";\n\nexport default function AdminPanelLayout({\n children\n}: {\n children: React.ReactNode;\n}) {\n const sidebar = useStore(useSidebar, (x) => x);\n if (!sidebar) return null;\n const { getOpenState, settings } = sidebar;\n return (\n <>\n \n \n {children}\n \n \n
\n
\n \n );\n}\n", "path": "components/admin-panel/admin-panel-layout.tsx", "target": "components/admin-panel/admin-panel-layout.tsx" }, { "type": "registry:component", "content": "\"use client\";\n\nimport Link from \"next/link\";\nimport { useState } from \"react\";\nimport { ChevronDown, Dot, LucideIcon } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { DropdownMenuArrow } from \"@radix-ui/react-dropdown-menu\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger\n} from \"@/components/ui/collapsible\";\nimport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n TooltipProvider\n} from \"@/components/ui/tooltip\";\nimport {\n DropdownMenu,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuSeparator\n} from \"@/components/ui/dropdown-menu\";\nimport { usePathname } from \"next/navigation\";\n\ntype Submenu = {\n href: string;\n label: string;\n active?: boolean;\n};\n\ninterface CollapseMenuButtonProps {\n icon: LucideIcon;\n label: string;\n active: boolean;\n submenus: Submenu[];\n isOpen: boolean | undefined;\n}\n\nexport function CollapseMenuButton({\n icon: Icon,\n label,\n active,\n submenus,\n isOpen\n}: CollapseMenuButtonProps) {\n const pathname = usePathname();\n const isSubmenuActive = submenus.some((submenu) =>\n submenu.active === undefined ? submenu.href === pathname : submenu.active\n );\n const [isCollapsed, setIsCollapsed] = useState(isSubmenuActive);\n\n return isOpen ? (\n \n div>div>svg]:rotate-180 mb-1\"\n asChild\n >\n \n
\n
\n \n \n \n \n {label}\n

\n
\n \n \n
\n \n \n \n \n {submenus.map(({ href, label, active }, index) => (\n \n \n \n \n \n \n {label}\n

\n \n \n ))}\n
\n \n ) : (\n \n \n \n \n \n \n
\n
\n \n \n \n \n {label}\n

\n
\n
\n \n
\n
\n \n {label}\n \n
\n
\n \n \n {label}\n \n \n {submenus.map(({ href, label, active }, index) => (\n \n \n

{label}

\n \n
\n ))}\n \n
\n
\n );\n}\n", "path": "components/admin-panel/collapse-menu-button.tsx", "target": "components/admin-panel/collapse-menu-button.tsx" }, { "type": "registry:component", "content": "import { Navbar } from \"@/components/admin-panel/navbar\";\n\ninterface ContentLayoutProps {\n title: string;\n children: React.ReactNode;\n}\n\nexport function ContentLayout({ title, children }: ContentLayoutProps) {\n return (\n
\n \n
{children}
\n
\n );\n}\n", "path": "components/admin-panel/content-layout.tsx", "target": "components/admin-panel/content-layout.tsx" }, { "type": "registry:component", "content": "import Link from \"next/link\";\n\nexport function Footer() {\n return (\n
\n
\n

\n Built on top of{\" \"}\n \n shadcn/ui\n \n . The source code is available on{\" \"}\n \n GitHub\n \n .\n

\n
\n
\n );\n}\n", "path": "components/admin-panel/footer.tsx", "target": "components/admin-panel/footer.tsx" }, { "type": "registry:component", "content": "\"use client\";\n\nimport Link from \"next/link\";\nimport { Ellipsis, LogOut } from \"lucide-react\";\nimport { usePathname } from \"next/navigation\";\n\nimport { cn } from \"@/lib/utils\";\nimport { getMenuList } from \"@/lib/menu-list\";\nimport { Button } from \"@/components/ui/button\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { CollapseMenuButton } from \"@/components/admin-panel/collapse-menu-button\";\nimport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n TooltipProvider\n} from \"@/components/ui/tooltip\";\n\ninterface MenuProps {\n isOpen: boolean | undefined;\n}\n\nexport function Menu({ isOpen }: MenuProps) {\n const pathname = usePathname();\n const menuList = getMenuList(pathname);\n\n return (\n div>div[style]]:!block\">\n \n \n );\n}\n", "path": "components/admin-panel/menu.tsx", "target": "components/admin-panel/menu.tsx" }, { "type": "registry:component", "content": "import { ModeToggle } from \"@/components/mode-toggle\";\nimport { UserNav } from \"@/components/admin-panel/user-nav\";\nimport { SheetMenu } from \"@/components/admin-panel/sheet-menu\";\n\ninterface NavbarProps {\n title: string;\n}\n\nexport function Navbar({ title }: NavbarProps) {\n return (\n
\n
\n
\n \n

{title}

\n
\n
\n \n \n
\n
\n
\n );\n}\n", "path": "components/admin-panel/navbar.tsx", "target": "components/admin-panel/navbar.tsx" }, { "type": "registry:component", "content": "import Link from \"next/link\";\nimport { MenuIcon, PanelsTopLeft } from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Menu } from \"@/components/admin-panel/menu\";\nimport {\n Sheet,\n SheetHeader,\n SheetContent,\n SheetTrigger,\n SheetTitle\n} from \"@/components/ui/sheet\";\n\nexport function SheetMenu() {\n return (\n \n \n \n \n \n \n \n \n \n Brand\n \n \n \n \n \n \n );\n}\n", "path": "components/admin-panel/sheet-menu.tsx", "target": "components/admin-panel/sheet-menu.tsx" }, { "type": "registry:component", "content": "import { ChevronLeft } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\ninterface SidebarToggleProps {\n isOpen: boolean | undefined;\n setIsOpen?: () => void;\n}\n\nexport function SidebarToggle({ isOpen, setIsOpen }: SidebarToggleProps) {\n return (\n
\n setIsOpen?.()}\n className=\"rounded-md w-8 h-8\"\n variant=\"outline\"\n size=\"icon\"\n >\n \n \n
\n );\n}\n", "path": "components/admin-panel/sidebar-toggle.tsx", "target": "components/admin-panel/sidebar-toggle.tsx" }, { "type": "registry:component", "content": "\"use client\";\nimport { Menu } from \"@/components/admin-panel/menu\";\nimport { SidebarToggle } from \"@/components/admin-panel/sidebar-toggle\";\nimport { Button } from \"@/components/ui/button\";\nimport { useSidebar } from \"@/hooks/use-sidebar\";\nimport { useStore } from \"@/hooks/use-store\";\nimport { cn } from \"@/lib/utils\";\nimport { PanelsTopLeft } from \"lucide-react\";\nimport Link from \"next/link\";\n\nexport function Sidebar() {\n const sidebar = useStore(useSidebar, (x) => x);\n if (!sidebar) return null;\n const { isOpen, toggleOpen, getOpenState, setIsHover, settings } = sidebar;\n return (\n \n \n setIsHover(true)}\n onMouseLeave={() => setIsHover(false)}\n className=\"relative h-full flex flex-col px-3 py-4 overflow-y-auto shadow-md dark:shadow-zinc-800\"\n >\n \n \n \n \n Brand\n \n \n \n \n \n \n );\n}\n", "path": "components/admin-panel/sidebar.tsx", "target": "components/admin-panel/sidebar.tsx" }, { "type": "registry:component", "content": "\"use client\";\n\nimport Link from \"next/link\";\nimport { LayoutGrid, LogOut, User } from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n TooltipProvider\n} from \"@/components/ui/tooltip\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from \"@/components/ui/dropdown-menu\";\n\nexport function UserNav() {\n return (\n \n \n \n \n \n \n \n \n JD\n \n \n \n \n Profile\n \n \n\n \n \n
\n

John Doe

\n

\n johndoe@example.com\n

\n
\n
\n \n \n \n \n \n Heap\n \n \n \n \n \n Account\n \n \n \n \n {}}>\n \n Sign out\n \n
\n
\n );\n}\n", "path": "components/admin-panel/user-nav.tsx", "target": "components/admin-panel/user-nav.tsx" }, { "type": "registry:component", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { useTheme } from \"next-themes\";\nimport { MoonIcon, SunIcon } from \"@radix-ui/react-icons\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n TooltipProvider\n} from \"@/components/ui/tooltip\";\n\nexport function ModeToggle() {\n const { setTheme, theme } = useTheme();\n\n return (\n \n \n \n setTheme(theme === \"dark\" ? \"light\" : \"dark\")}\n >\n \n \n Switch Theme\n \n \n Switch Theme\n \n \n );\n}\n", "path": "components/mode-toggle.tsx", "target": "components/mode-toggle.tsx" }, { "type": "registry:component", "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { ThemeProvider as NextThemesProvider } from \"next-themes\";\nimport { type ThemeProviderProps } from \"next-themes/dist/types\";\n\nexport function ThemeProvider({ children, ...props }: ThemeProviderProps) {\n return {children};\n}\n", "path": "components/providers/theme-provider.tsx", "target": "components/providers/theme-provider.tsx" }, { "type": "registry:lib", "content": "import {\n Tag,\n Users,\n Settings,\n Bookmark,\n SquarePen,\n LayoutGrid,\n LucideIcon\n} from \"lucide-react\";\n\ntype Submenu = {\n href: string;\n label: string;\n active?: boolean;\n};\n\ntype Menu = {\n href: string;\n label: string;\n active?: boolean;\n icon: LucideIcon;\n submenus?: Submenu[];\n};\n\ntype Group = {\n groupLabel: string;\n menus: Menu[];\n};\n\nexport function getMenuList(pathname: string): Group[] {\n return [\n {\n groupLabel: \"\",\n menus: [\n {\n href: \"/heap\",\n label: \"Heap\",\n icon: LayoutGrid,\n submenus: []\n }\n ]\n },\n {\n groupLabel: \"Contents\",\n menus: [\n {\n href: \"\",\n label: \"Posts\",\n icon: SquarePen,\n submenus: [\n {\n href: \"/posts\",\n label: \"All Posts\"\n },\n {\n href: \"/posts/new\",\n label: \"New Post\"\n }\n ]\n },\n {\n href: \"/categories\",\n label: \"Categories\",\n icon: Bookmark\n },\n {\n href: \"/tags\",\n label: \"Tags\",\n icon: Tag\n }\n ]\n },\n {\n groupLabel: \"Settings\",\n menus: [\n {\n href: \"/users\",\n label: \"Users\",\n icon: Users\n },\n {\n href: \"/account\",\n label: \"Account\",\n icon: Settings\n }\n ]\n }\n ];\n}\n", "path": "lib/menu-list.ts", "target": "lib/menu-list.ts" } ] }