diff --git a/package-lock.json b/package-lock.json index 8a722bc..e9bd56c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "react-shadcn-starter", "version": "0.1", "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", @@ -615,6 +616,37 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz", + "integrity": "sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collapsible": "1.0.3", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz", @@ -664,6 +696,36 @@ } } }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz", + "integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", @@ -3602,6 +3664,23 @@ "@babel/runtime": "^7.13.10" } }, + "@radix-ui/react-accordion": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz", + "integrity": "sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collapsible": "1.0.3", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1" + } + }, "@radix-ui/react-arrow": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz", @@ -3623,6 +3702,22 @@ "@radix-ui/react-use-layout-effect": "1.0.1" } }, + "@radix-ui/react-collapsible": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz", + "integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + } + }, "@radix-ui/react-collection": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", diff --git a/package.json b/package.json index 79e3099..7432d50 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", diff --git a/src/Router.tsx b/src/Router.tsx index a8c8798..c5fbfcb 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -1,9 +1,11 @@ import { createBrowserRouter } from "react-router-dom"; -import Applayout from "./components/layouts/AppLayout"; +import { Applayout } from "./components/layouts/AppLayout"; + import NoMatch from "./pages/NoMatch"; import Dashboard from "./pages/Dashboard"; import Empty from "./pages/Empty"; +import Sample from "./pages/Sample"; export const router = createBrowserRouter([ { @@ -14,6 +16,10 @@ export const router = createBrowserRouter([ path: "", element: , }, + { + path: "sample", + element: , + }, { path: "empty", element: , diff --git a/src/components/layouts/AppFooter.tsx b/src/components/layouts/AppFooter.tsx deleted file mode 100644 index 3062b70..0000000 --- a/src/components/layouts/AppFooter.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { ModeToggle } from "@/components/mode-toggle"; - -export default function Footer() { - return ( -
-

Built by shadcn. The source code is available on GitHub.

-
- -
-
- ) -} \ No newline at end of file diff --git a/src/components/layouts/AppHeader.tsx b/src/components/layouts/AppHeader.tsx deleted file mode 100644 index e43d7ed..0000000 --- a/src/components/layouts/AppHeader.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useState } from "react"; -import { NavLink } from "react-router-dom"; -import { cn } from "@/lib/utils"; -import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; -import { Icons } from "@/components/icons"; -import { appConfig } from "@/config/app"; -import { Button, buttonVariants } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger -} from "@/components/ui/dropdown-menu"; -import { Avatar, AvatarFallback } from "@/components/ui/avatar"; -import { mainMenu } from "@/config/menu"; -import { ViewVerticalIcon } from "@radix-ui/react-icons"; -import { ScrollArea } from "@radix-ui/react-scroll-area"; - -export default function Header() { - const [open, setOpen] = useState(false) - - return ( -
-
-
- - - {appConfig.name} - - - -
- {/* mobile */} - - - - - - setOpen(false)}> - - {appConfig.name} - - -
- {mainMenu.map((menu, index) => ( - cn( - "text-sm font-medium transition-colors hover:text-primary", - isActive ? "text-foreground" : "text-foreground/60" - )}> - {menu.title} - - ))} -
-
-
-
- - - {appConfig.name} - - {/* right */} -
-
- {/* */} -
- -
-
-
- ) -} \ No newline at end of file diff --git a/src/components/layouts/AppLayout.tsx b/src/components/layouts/AppLayout.tsx index fd169fb..08f4410 100644 --- a/src/components/layouts/AppLayout.tsx +++ b/src/components/layouts/AppLayout.tsx @@ -1,17 +1,19 @@ import { Outlet } from "react-router-dom"; -import AppHeader from "./AppHeader"; -import AppFooter from "./AppFooter"; +import { Header } from "./Header"; +import { Footer } from "./Footer"; -export default function Applayout() { +export function Applayout() { return ( <> - -
-
+
+
+
- +
+
+
) } diff --git a/src/components/layouts/Footer.tsx b/src/components/layouts/Footer.tsx new file mode 100644 index 0000000..da6b89d --- /dev/null +++ b/src/components/layouts/Footer.tsx @@ -0,0 +1,13 @@ +import { appConfig } from "@/config/app"; +import { ModeToggle } from "../mode-toggle"; + +export function Footer() { + return ( + + ) +} \ No newline at end of file diff --git a/src/components/layouts/Header.tsx b/src/components/layouts/Header.tsx new file mode 100644 index 0000000..6c55dad --- /dev/null +++ b/src/components/layouts/Header.tsx @@ -0,0 +1,212 @@ +import { useState } from "react"; +import { NavLink, useLocation } from "react-router-dom"; +import { cn } from "@/lib/utils"; +import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; +import { Icons } from "@/components/icons"; +import { appConfig } from "@/config/app"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu"; +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { mainMenu } from "@/config/menu"; +import { ChevronDownIcon, ViewVerticalIcon } from "@radix-ui/react-icons"; +import { ScrollArea } from "@radix-ui/react-scroll-area"; +import { Logo } from "../logo"; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; + +export function Header() { + const [open, setOpen] = useState(false) + const location = useLocation(); + + return ( +
+
+
+ + + + + +
+ {/* mobile */} + + + + + + setOpen(false)} + className="flex items-center space-x-2"> + + + + item.items !== undefined ? item.items.filter(subitem => subitem.to !== undefined).map(subitem => subitem.to).includes(location.pathname) : false)}> +
+ {mainMenu.map((menu, index) => + menu.items !== undefined ? ( + + subitem.to !== undefined).map(subitem => subitem.to)) + .includes(location.pathname) ? 'text-foreground' : 'text-foreground/60', + )}> +
{menu.title}
+
+ +
+ {menu.items.map((submenu, subindex) => ( + submenu.to !== undefined ? ( + setOpen(false)} + className={({ isActive }) => cn( + "block justify-start py-1 h-auto font-normal hover:text-primary", + isActive ? 'text-foreground' : 'text-foreground/60', + )}> + {submenu.title} + + ) : ( + submenu.label !== '' ? ( + null + ) : ( +
+ {/* */} +
+ ) + ) + ))} +
+
+
+ ) : ( + setOpen(false)} + className={({ isActive }) => cn( + "py-1 text-sm font-medium transition-colors hover:text-primary", + isActive ? "text-foreground" : "text-foreground/60" + )}> + {menu.title} + + ) + )} +
+
+
+
+
+ + + {appConfig.name} + + {/* right */} +
+
+ {/* */} +
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/logo.tsx b/src/components/logo.tsx new file mode 100644 index 0000000..01e89be --- /dev/null +++ b/src/components/logo.tsx @@ -0,0 +1,11 @@ +import { appConfig } from "@/config/app"; +import { Icons } from "./icons"; + +export function Logo() { + return ( + <> + + {appConfig.name} + + ) +} \ No newline at end of file diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx new file mode 100644 index 0000000..7e84c32 --- /dev/null +++ b/src/components/ui/accordion.tsx @@ -0,0 +1,55 @@ +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "@radix-ui/react-icons" + +import { cn } from "@/lib/utils" + +const Accordion = AccordionPrimitive.Root + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AccordionItem.displayName = "AccordionItem" + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index 0275a4e..7df0d9b 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -11,13 +11,7 @@ const SheetTrigger = SheetPrimitive.Trigger const SheetClose = SheetPrimitive.Close -const SheetPortal = ({ - className, - ...props -}: SheetPrimitive.DialogPortalProps) => ( - -) -SheetPortal.displayName = SheetPrimitive.Portal.displayName +const SheetPortal = SheetPrimitive.Portal const SheetOverlay = React.forwardRef< React.ElementRef, diff --git a/src/config/app.ts b/src/config/app.ts index 1b7ab3d..6ccc302 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -4,6 +4,10 @@ interface AppConfig { title: string, url: string }, + author: { + name: string, + url: string + }, } export const appConfig: AppConfig = { @@ -11,5 +15,9 @@ export const appConfig: AppConfig = { github: { title: "React Shadcn Starter", url: "https://github.com/hayyi2/react-shadcn-starter", + }, + author: { + name: "hayyi", + url: "https://github.com/hayyi2/", } } \ No newline at end of file diff --git a/src/config/menu.ts b/src/config/menu.ts index 7a6cbff..1f91a65 100644 --- a/src/config/menu.ts +++ b/src/config/menu.ts @@ -11,14 +11,27 @@ interface NavItem { } interface NavItemWithChildren extends NavItem { - items: NavItemWithChildren[] + items?: NavItemWithChildren[] } -export const mainMenu: NavItem[] = [ +export const mainMenu: NavItemWithChildren[] = [ { title: 'Dashboard', to: '', }, + { + title: 'Dropdown', + items: [ + { + title: 'Sample', + to: '/sample', + }, + { + title: 'Sample Dua', + to: '/#', + }, + ] + }, { title: 'Empty', to: 'empty', diff --git a/src/pages/NoMatch.tsx b/src/pages/NoMatch.tsx index 7bf7e34..8a64b79 100644 --- a/src/pages/NoMatch.tsx +++ b/src/pages/NoMatch.tsx @@ -1,12 +1,14 @@ import { buttonVariants } from "@/components/ui/button"; +import { NavLink } from "react-router-dom"; export default function NoMatch() { return (
-

404

-

Page Not Found

- Back to Home +

404

+

Oops! Page not found

+

We are sorry, but the page you requested was not found

+ Back to Home
) diff --git a/src/pages/Sample.tsx b/src/pages/Sample.tsx new file mode 100644 index 0000000..b1c09b2 --- /dev/null +++ b/src/pages/Sample.tsx @@ -0,0 +1,18 @@ +import { PageHeader, PageHeaderHeading } from "@/components/page-header"; +import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; + +export default function Sample() { + return ( + <> + + Sample Page + + + + Card Title + Card description. + + + + ) +}