├── .eslintrc.json ├── src ├── app │ ├── icon.ico │ ├── twitter-image.png │ ├── opengraph-image.png │ ├── (demo) │ │ ├── layout.tsx │ │ ├── tags │ │ │ └── page.tsx │ │ ├── users │ │ │ └── page.tsx │ │ ├── account │ │ │ └── page.tsx │ │ ├── posts │ │ │ ├── page.tsx │ │ │ └── new │ │ │ │ └── page.tsx │ │ ├── categories │ │ │ └── page.tsx │ │ └── dashboard │ │ │ └── page.tsx │ ├── layout.tsx │ ├── globals.css │ └── page.tsx ├── lib │ ├── utils.ts │ └── menu-list.ts ├── components │ ├── providers │ │ └── theme-provider.tsx │ ├── ui │ │ ├── collapsible.tsx │ │ ├── label.tsx │ │ ├── tooltip.tsx │ │ ├── switch.tsx │ │ ├── avatar.tsx │ │ ├── scroll-area.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── breadcrumb.tsx │ │ ├── sheet.tsx │ │ └── dropdown-menu.tsx │ ├── admin-panel │ │ ├── content-layout.tsx │ │ ├── sidebar-toggle.tsx │ │ ├── navbar.tsx │ │ ├── footer.tsx │ │ ├── admin-panel-layout.tsx │ │ ├── sheet-menu.tsx │ │ ├── sidebar.tsx │ │ ├── user-nav.tsx │ │ ├── menu.tsx │ │ └── collapse-menu-button.tsx │ ├── demo │ │ └── placeholder-content.tsx │ └── mode-toggle.tsx └── hooks │ ├── use-store.ts │ └── use-sidebar.ts ├── public ├── placeholder.png ├── demo-dark-min.png ├── demo-light-min.png ├── demo-mobile-dark-min.png ├── demo-mobile-light-min.png ├── vercel.svg ├── next.svg └── registry │ └── shadcn-sidebar.json ├── .vscode └── settings.json ├── next.config.mjs ├── screenshots ├── screenshot-1.png ├── screenshot-2.png ├── screenshot-3.png └── screenshot-4.png ├── registry ├── index.ts ├── registry-components.ts └── schema.ts ├── postcss.config.mjs ├── components.json ├── .gitignore ├── tsconfig.json ├── LICENSE ├── package.json ├── README.md ├── scripts └── build-registry.ts └── tailwind.config.ts /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/app/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/src/app/icon.ico -------------------------------------------------------------------------------- /public/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/public/placeholder.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.singleQuote": false, 3 | "prettier.trailingComma": "none" 4 | } 5 | -------------------------------------------------------------------------------- /public/demo-dark-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/public/demo-dark-min.png -------------------------------------------------------------------------------- /public/demo-light-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/public/demo-light-min.png -------------------------------------------------------------------------------- /src/app/twitter-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/src/app/twitter-image.png -------------------------------------------------------------------------------- /src/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/src/app/opengraph-image.png -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /screenshots/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/screenshots/screenshot-1.png -------------------------------------------------------------------------------- /screenshots/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/screenshots/screenshot-2.png -------------------------------------------------------------------------------- /screenshots/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/screenshots/screenshot-3.png -------------------------------------------------------------------------------- /screenshots/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/screenshots/screenshot-4.png -------------------------------------------------------------------------------- /public/demo-mobile-dark-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/public/demo-mobile-dark-min.png -------------------------------------------------------------------------------- /public/demo-mobile-light-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salimi-my/shadcn-ui-sidebar/HEAD/public/demo-mobile-light-min.png -------------------------------------------------------------------------------- /registry/index.ts: -------------------------------------------------------------------------------- 1 | import { ui } from "./registry-components" 2 | 3 | export const registryComponents = [ 4 | ...ui 5 | ] -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /src/app/(demo)/layout.tsx: -------------------------------------------------------------------------------- 1 | import AdminPanelLayout from "@/components/admin-panel/admin-panel-layout"; 2 | 3 | export default function DemoLayout({ 4 | children 5 | }: { 6 | children: React.ReactNode; 7 | }) { 8 | return {children}; 9 | } 10 | -------------------------------------------------------------------------------- /src/components/providers/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { 5 | ThemeProvider as NextThemesProvider, 6 | type ThemeProviderProps 7 | } from "next-themes"; 8 | 9 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 4 | 5 | const Collapsible = CollapsiblePrimitive.Root 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 12 | -------------------------------------------------------------------------------- /src/components/admin-panel/content-layout.tsx: -------------------------------------------------------------------------------- 1 | import { Navbar } from "@/components/admin-panel/navbar"; 2 | 3 | interface ContentLayoutProps { 4 | title: string; 5 | children: React.ReactNode; 6 | } 7 | 8 | export function ContentLayout({ title, children }: ContentLayoutProps) { 9 | return ( 10 |
11 | 12 |
{children}
13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/hooks/use-store.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | /** 3 | * This hook fix hydration when use persist to save hook data to localStorage 4 | */ 5 | export const useStore = ( 6 | store: (callback: (state: T) => unknown) => unknown, 7 | callback: (state: T) => F 8 | ) => { 9 | const result = store(callback) as F; 10 | const [data, setData] = useState(); 11 | 12 | useEffect(() => { 13 | setData(result); 14 | }, [result]); 15 | 16 | return data; 17 | }; 18 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/globals.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /src/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /src/components/admin-panel/sidebar-toggle.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronLeft } from "lucide-react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | import { Button } from "@/components/ui/button"; 5 | 6 | interface SidebarToggleProps { 7 | isOpen: boolean | undefined; 8 | setIsOpen?: () => void; 9 | } 10 | 11 | export function SidebarToggle({ isOpen, setIsOpen }: SidebarToggleProps) { 12 | return ( 13 |
14 | 27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src/components/admin-panel/navbar.tsx: -------------------------------------------------------------------------------- 1 | import { ModeToggle } from "@/components/mode-toggle"; 2 | import { UserNav } from "@/components/admin-panel/user-nav"; 3 | import { SheetMenu } from "@/components/admin-panel/sheet-menu"; 4 | 5 | interface NavbarProps { 6 | title: string; 7 | } 8 | 9 | export function Navbar({ title }: NavbarProps) { 10 | return ( 11 |
12 |
13 |
14 | 15 |

{title}

16 |
17 |
18 | 19 | 20 |
21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /src/components/admin-panel/footer.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export function Footer() { 4 | return ( 5 |
6 |
7 |

8 | Built on top of{" "} 9 | 15 | shadcn/ui 16 | 17 | . The source code is available on{" "} 18 | 24 | GitHub 25 | 26 | . 27 |

28 |
29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Salimi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/demo/placeholder-content.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import Image from "next/image"; 3 | 4 | import { Card, CardContent } from "@/components/ui/card"; 5 | 6 | export default function PlaceholderContent() { 7 | return ( 8 | 9 | 10 |
11 |
12 | Placeholder Image 19 |
20 | 26 | Designed by Freepik 27 | 28 |
29 |
30 |
31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/components/admin-panel/admin-panel-layout.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Footer } from "@/components/admin-panel/footer"; 4 | import { Sidebar } from "@/components/admin-panel/sidebar"; 5 | import { useSidebar } from "@/hooks/use-sidebar"; 6 | import { useStore } from "@/hooks/use-store"; 7 | import { cn } from "@/lib/utils"; 8 | 9 | export default function AdminPanelLayout({ 10 | children 11 | }: { 12 | children: React.ReactNode; 13 | }) { 14 | const sidebar = useStore(useSidebar, (x) => x); 15 | if (!sidebar) return null; 16 | const { getOpenState, settings } = sidebar; 17 | return ( 18 | <> 19 | 20 |
26 | {children} 27 |
28 |