303 lines
18 KiB
TypeScript
303 lines
18 KiB
TypeScript
// * Packages
|
|
import { Link, usePage } from "@inertiajs/react";
|
|
import { useEffect, useRef } from "react";
|
|
import {
|
|
ChevronDown,
|
|
MoreHorizontal,
|
|
Home,
|
|
Users,
|
|
SquareArrowOutUpRight,
|
|
Telescope,
|
|
} from "lucide-react";
|
|
import { route } from "ziggy-js";
|
|
// * Components shadcn
|
|
import {
|
|
Sidebar,
|
|
SidebarHeader,
|
|
SidebarContent,
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarGroupLabel,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
SidebarMenuAction,
|
|
useSidebar,
|
|
} from "@/components/ui/sidebar";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import {
|
|
Collapsible,
|
|
CollapsibleTrigger,
|
|
CollapsibleContent,
|
|
} from "@/components/ui/collapsible";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
import { Button } from "@/components/ui/button";
|
|
// * Other
|
|
import ApplicationLogo from "@/back/Components/ApplicationLogo";
|
|
import { Views } from "@/lib/utils";
|
|
import str from "@/hooks/use-string";
|
|
import useTrans from "@/hooks/use-translations";
|
|
import { AppEnv, AuthProp } from "@/back/types/global";
|
|
|
|
export default function AppSidebar() {
|
|
const appMode = (usePage().props.appEnv as AppEnv).mode;
|
|
const { state } = useSidebar();
|
|
const prevStateRef = useRef(state);
|
|
const isCollapsed = state === "collapsed";
|
|
const auth = usePage().props.auth as AuthProp;
|
|
const navList = [
|
|
{
|
|
title: useTrans("back.pages"),
|
|
show: true,
|
|
links: [
|
|
{
|
|
title: useTrans("back.dashboard"),
|
|
model: "dashboard",
|
|
show: true,
|
|
icon: Home,
|
|
actions: [],
|
|
},
|
|
{
|
|
title: useTrans("back.your_website"),
|
|
link: route("front.homepage"),
|
|
show: true,
|
|
icon: SquareArrowOutUpRight,
|
|
actions: [],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: useTrans("back.administration"),
|
|
show: auth.user.role === 1,
|
|
links: [
|
|
{
|
|
title: str(useTrans("models.classes.user"))
|
|
.ucFirst()
|
|
.plural()
|
|
.value(),
|
|
model: "users",
|
|
icon: Users,
|
|
show: auth.policies.users.viewAny,
|
|
actions: [Views.CREATION],
|
|
},
|
|
{
|
|
title: useTrans("back.telescope"),
|
|
link: route("telescope"),
|
|
icon: Telescope,
|
|
show: appMode === "local",
|
|
actions: [],
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
useEffect(() => {
|
|
if (prevStateRef.current !== state) {
|
|
const elmts = document.querySelectorAll(".sidebar-transition");
|
|
elmts.forEach((element) => {
|
|
element.classList.add("animation-transition");
|
|
setTimeout(() => {
|
|
element.classList.remove("animation-transition");
|
|
}, 400);
|
|
});
|
|
prevStateRef.current = state;
|
|
}
|
|
}, [state]);
|
|
|
|
const GetTranslation = (label: string) => {
|
|
return useTrans(`crud.actions.${label}`);
|
|
};
|
|
|
|
return (
|
|
<Sidebar collapsible="icon" className="z-30">
|
|
<SidebarHeader className="sidebar-transition">
|
|
<ApplicationLogo isCollapsed={isCollapsed} />
|
|
</SidebarHeader>
|
|
<SidebarContent
|
|
className={`sidebar-transition ${isCollapsed ? "pt-2" : ""}`}
|
|
>
|
|
{navList.map(
|
|
(navGroup) =>
|
|
navGroup.show && (
|
|
<Collapsible
|
|
key={navGroup.title}
|
|
className="group/collapsible"
|
|
defaultOpen
|
|
>
|
|
<SidebarGroup>
|
|
{!isCollapsed && (
|
|
<SidebarGroupLabel asChild>
|
|
<CollapsibleTrigger>
|
|
{navGroup.title}
|
|
<ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
|
|
</CollapsibleTrigger>
|
|
</SidebarGroupLabel>
|
|
)}
|
|
<CollapsibleContent>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
{navGroup.links.map(
|
|
(navLink) => {
|
|
const sidebarButton = (
|
|
<SidebarMenuButton
|
|
className={`${
|
|
route().current(
|
|
`back.${navLink.model}.*`,
|
|
)
|
|
? "text-secondary-foreground"
|
|
: "text-primary-foreground"
|
|
}`}
|
|
asChild
|
|
>
|
|
{navLink.link ? (
|
|
<a
|
|
href={
|
|
navLink.link
|
|
}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
>
|
|
<navLink.icon />
|
|
{
|
|
navLink.title
|
|
}
|
|
</a>
|
|
) : (
|
|
<Link
|
|
href={route(
|
|
`back.${navLink.model}.index`,
|
|
)}
|
|
className="bg-transparent"
|
|
>
|
|
<navLink.icon />
|
|
{
|
|
navLink.title
|
|
}
|
|
</Link>
|
|
)}
|
|
</SidebarMenuButton>
|
|
);
|
|
return (
|
|
navLink.show && (
|
|
<SidebarMenuItem
|
|
className={`transition-colors rounded-md ${
|
|
route().current(
|
|
`back.${navLink.model}.*`,
|
|
)
|
|
? "bg-secondary text-secondary-foreground"
|
|
: "bg-opacity-0"
|
|
}`}
|
|
key={
|
|
navLink.title
|
|
}
|
|
>
|
|
{isCollapsed ? (
|
|
<Tooltip>
|
|
<TooltipTrigger
|
|
asChild
|
|
>
|
|
{
|
|
sidebarButton
|
|
}
|
|
</TooltipTrigger>
|
|
<TooltipContent side="right">
|
|
<p>
|
|
{
|
|
navLink.title
|
|
}
|
|
</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
) : (
|
|
sidebarButton
|
|
)}
|
|
{navLink
|
|
.actions
|
|
.length >
|
|
0 && (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger
|
|
asChild
|
|
>
|
|
<SidebarMenuAction
|
|
className={`${
|
|
route().current(
|
|
`back.${navLink.model}.*`,
|
|
)
|
|
? "text-secondary-foreground"
|
|
: ""
|
|
} !top-0 !right-0 px-4 h-full`}
|
|
>
|
|
<MoreHorizontal />
|
|
</SidebarMenuAction>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent
|
|
side="right"
|
|
align="start"
|
|
>
|
|
{navLink.actions.map(
|
|
(
|
|
action,
|
|
) =>
|
|
auth
|
|
.policies
|
|
.users[
|
|
action.policy as keyof typeof auth.policies.users
|
|
] && (
|
|
<DropdownMenuItem
|
|
className="p-0"
|
|
key={
|
|
action.label
|
|
}
|
|
>
|
|
<Button
|
|
variant="ghost"
|
|
asChild
|
|
>
|
|
<Link
|
|
href={route(
|
|
`back.${navLink.model}.${action.value}`,
|
|
)}
|
|
className="w-full"
|
|
>
|
|
<action.icon />
|
|
{str(
|
|
GetTranslation(
|
|
action.label,
|
|
),
|
|
)
|
|
.ucFirst()
|
|
.value()}
|
|
</Link>
|
|
</Button>
|
|
</DropdownMenuItem>
|
|
),
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)}
|
|
</SidebarMenuItem>
|
|
)
|
|
);
|
|
},
|
|
)}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</CollapsibleContent>
|
|
</SidebarGroup>
|
|
</Collapsible>
|
|
),
|
|
)}
|
|
</SidebarContent>
|
|
</Sidebar>
|
|
);
|
|
}
|