1
2import { Link, useRouterState } from "@tanstack/react-router";
3import React, { FC } from 'react'
4import {
5 BreadcrumbPage,
6 Drawer,
7 DrawerClose,
8 DrawerContent,
9 DrawerDescription,
10 DrawerTrigger,
11 Breadcrumb,
12 BreadcrumbEllipsis,
13 BreadcrumbItem,
14 BreadcrumbLink,
15 BreadcrumbList,
16 BreadcrumbSeparator,
17 DrawerFooter,
18 DrawerHeader,
19 DrawerTitle,
20 DropdownMenu,
21 DropdownMenuContent,
22 DropdownMenuItem,
23 DropdownMenuTrigger,
24 Button,
25 SidebarObject,
26} from "@marzneshin/common/components"
27import { useScreenBreakpoint } from "@marzneshin/common/hooks";
28import { AppRouterPaths } from "@marzneshin/common/types";
29import i18n from "@marzneshin/features/i18n";
30
31interface Dir {
32 href: AppRouterPaths;
33 label: string;
34}
35
36interface NavigationDirectoryProps {
37 sidebar: SidebarObject;
38}
39
40
41function getPathDirs(currentPath: string, sidebar: SidebarObject): Dir[] {
42 const dirs: Dir[] = [];
43 const pathArray = currentPath.split('/').filter(Boolean); // Split path and remove empty strings
44 let fullPath = '/';
45 for (let i = 0; i < pathArray.length; i++) {
46 const dir = pathArray[i];
47 fullPath += `/${dir}`;
48 if (sidebar[dir]) {
49 dirs.push({ href: sidebar[dir][0].to, label: sidebar[dir][0].title });
50 } else {
51 dirs.push({ href: fullPath as AppRouterPaths, label: i18n.t(dir) });
52 }
53 }
54 return dirs;
55}
56
57const ITEMS_TO_DISPLAY = 3
58
59export const NavigationDirectory: FC<NavigationDirectoryProps> = ({ sidebar }) => {
60 const [open, setOpen] = React.useState(false)
61 const currentPath = useRouterState().location.pathname;
62 const items = getPathDirs(currentPath, sidebar);
63 const isDesktop = !useScreenBreakpoint("sm");
64 return (
65 <Breadcrumb>
66 <BreadcrumbList>
67 {items.length > ITEMS_TO_DISPLAY ? (
68 <>
69 <BreadcrumbItem>
70 {isDesktop ? (
71 <DropdownMenu open={open} onOpenChange={setOpen}>
72 <DropdownMenuTrigger
73 className="flex gap-1 items-center"
74 aria-label="Toggle menu"
75 >
76 <BreadcrumbEllipsis className="w-4 h-4" />
77 </DropdownMenuTrigger>
78 <DropdownMenuContent align="start">
79 {items.slice(1, -2).map((item, index) => (
80 <DropdownMenuItem key={index}>
81 <Link to={item.href} className="capitalize">
82 {item.label}
83 </Link>
84 </DropdownMenuItem>
85 ))}
86 </DropdownMenuContent>
87 </DropdownMenu>
88 ) : (
89 <Drawer open={open} onOpenChange={setOpen}>
90 <DrawerTrigger aria-label="Toggle Menu">
91 <BreadcrumbEllipsis className="w-4 h-4" />
92 </DrawerTrigger>
93 <DrawerContent>
94 <DrawerHeader className="text-left">
95 <DrawerTitle>Navigate to</DrawerTitle>
96 <DrawerDescription>
97 Select a page to navigate to.
98 </DrawerDescription>
99 </DrawerHeader>
100 <div className="grid gap-1 px-4">
101 {items.slice(1, -2).map((item, index) => (
102 <Link
103 key={index}
104 to="/"
105 className="py-1 text-sm"
106 >
107 {item.label}
108 </Link>
109 ))}
110 </div>
111 <DrawerFooter className="pt-4">
112 <DrawerClose asChild>
113 <Button variant="outline">Close</Button>
114 </DrawerClose>
115 </DrawerFooter>
116 </DrawerContent>
117 </Drawer>
118 )}
119 </BreadcrumbItem>
120 </>
121 ) : null}
122 {items.slice(-ITEMS_TO_DISPLAY + 1).map((item, index) => (
123 <BreadcrumbItem key={index}>
124 {item.href ? (
125 <>
126 <BreadcrumbLink
127 asChild
128 className="md:max-w-none max-w-20 truncate text-accent dark:text-accent-foreground hover:text-primary-foreground"
129 >
130 <Link to={item.href}>{item.label}</Link>
131 </BreadcrumbLink>
132 {index !== items.slice(-ITEMS_TO_DISPLAY + 1).length - 1 && <BreadcrumbSeparator />}
133 </>
134 ) : (
135 <BreadcrumbPage className="md:max-w-none max-w-20 truncate">
136 {item.label}
137 </BreadcrumbPage>
138 )}
139 </BreadcrumbItem>
140 ))}
141 </BreadcrumbList>
142 </Breadcrumb>
143 )
144}