feat: dynamic menu item support
parent
5a5e3c00f3
commit
a425c78bdf
|
@ -1,9 +1,10 @@
|
|||
import { Sheet, SheetContent, SheetTrigger } from "@/Components/ui/sheet";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Home, Menu } from "lucide-react";
|
||||
import { AlignJustifyIcon, Menu } from "lucide-react";
|
||||
import { Link } from "@inertiajs/react";
|
||||
import { MenuItemProp } from "@/types";
|
||||
import ApplicationLogo from "@/Components/ApplicationLogo";
|
||||
import { DropdownMenuSeparator } from "./ui/dropdown-menu";
|
||||
|
||||
const MobileMenu = ({ links }: { links: MenuItemProp[] }) => {
|
||||
return (
|
||||
|
@ -19,31 +20,41 @@ const MobileMenu = ({ links }: { links: MenuItemProp[] }) => {
|
|||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="flex flex-col">
|
||||
<nav className="grid gap-2 text-lg font-medium">
|
||||
<nav className="text-lg font-medium">
|
||||
<Link
|
||||
href="#"
|
||||
className="flex items-center gap-2 text-lg font-semibold"
|
||||
className="flex items-center gap-2 text-lg font-semibold mb-4"
|
||||
>
|
||||
<ApplicationLogo className="h-8 w-8 fill-current text-gray-500" />
|
||||
|
||||
<span>Acme Inc</span>
|
||||
</Link>
|
||||
{links.map((link, index) => {
|
||||
return (
|
||||
<Link
|
||||
key={index}
|
||||
href={link.href}
|
||||
className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Home className="h-5 w-5" />
|
||||
{link.title}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<div className="space-y-2">
|
||||
{links.map((link, index) => (
|
||||
<MobileMenuItem key={index} link={link} />
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
};
|
||||
|
||||
const MobileMenuItem = ({ link }: { link: MenuItemProp }) => {
|
||||
const Icon = (link.icon ?? AlignJustifyIcon) as React.ElementType;
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={link.href}
|
||||
className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<Icon className="h-5 w-5" />
|
||||
{link.title}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileMenu;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Link, usePage } from "@inertiajs/react";
|
||||
import { Home } from "lucide-react";
|
||||
import { AlignJustifyIcon, Home, Icon } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/Components/ui/button";
|
||||
import {
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
} from "@/Components/ui/tooltip";
|
||||
import { MenuItemProp } from "@/types";
|
||||
import ApplicationLogo from "@/Components/ApplicationLogo";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
type Props = {
|
||||
links: MenuItemProp[];
|
||||
|
@ -22,6 +23,8 @@ type MenuItemProps = {
|
|||
};
|
||||
|
||||
const CollapsedMenuItem = ({ link, isActive }: MenuItemProps) => {
|
||||
const Icon = (link.icon ?? AlignJustifyIcon) as React.ElementType;
|
||||
|
||||
return (
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
|
@ -37,7 +40,7 @@ const CollapsedMenuItem = ({ link, isActive }: MenuItemProps) => {
|
|||
"dark:bg-muted dark:text-muted-foreground dark:hover:bg-muted dark:hover:text-white"
|
||||
)}
|
||||
>
|
||||
<Home className="h-4 w-4" />
|
||||
{<Icon className="h-4 w-4" />}
|
||||
<span className="sr-only">{link.title}</span>
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
|
@ -49,6 +52,8 @@ const CollapsedMenuItem = ({ link, isActive }: MenuItemProps) => {
|
|||
};
|
||||
|
||||
const ExpandedMenuItem = ({ link, isActive }: MenuItemProps) => {
|
||||
const Icon = (link.icon ?? AlignJustifyIcon) as React.ElementType;
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={link.href}
|
||||
|
@ -57,14 +62,14 @@ const ExpandedMenuItem = ({ link, isActive }: MenuItemProps) => {
|
|||
"justify-start"
|
||||
)}
|
||||
>
|
||||
<Home className="mr-2 h-4 w-4" />
|
||||
{<Icon className="mr-2 h-4 w-4" />}
|
||||
{link.title}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const Sidebar = ({ links, isCollapsed }: Props) => {
|
||||
const { url, component } = usePage();
|
||||
const { url } = usePage();
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { PropsWithChildren, ReactNode, useState } from "react";
|
||||
import { Link } from "@inertiajs/react";
|
||||
import { MenuItemProp, User } from "@/types";
|
||||
import { CircleUser, Search } from "lucide-react";
|
||||
import { CircleUser, Search, UserIcon } from "lucide-react";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
|
@ -33,6 +33,7 @@ const links: MenuItemProp[] = [
|
|||
title: "Profile",
|
||||
href: route("profile.edit"),
|
||||
variant: "ghost",
|
||||
icon: UserIcon,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { LucideProps } from "lucide-react";
|
||||
import { ForwardRefExoticComponent, ReactNode, RefAttributes } from "react";
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
|
@ -16,6 +19,11 @@ export type PageProps<
|
|||
export type MenuItemProp = {
|
||||
title: string;
|
||||
href: string;
|
||||
icon?:
|
||||
| ForwardRefExoticComponent<
|
||||
Omit<LucideProps, "ref"> & RefAttributes<SVGSVGElement>
|
||||
>
|
||||
| ReactNode;
|
||||
variant:
|
||||
| "link"
|
||||
| "default"
|
||||
|
|
Loading…
Reference in New Issue