Enhance sidebar menu experience

This commit is contained in:
sianida26 2024-03-29 03:20:56 +07:00
parent b9214dfe88
commit f4ddd8461d
5 changed files with 42 additions and 12 deletions

View File

@ -4,9 +4,11 @@ import { Text } from "@mantine/core";
import classNames from "./styles/sidebarChildMenu.module.css";
import SidebarMenu from "../types/SidebarMenu";
import dashboardConfig from "../dashboard.config";
interface Props {
item: NonNullable<SidebarMenu["children"]>[number];
active: boolean;
}
/**
@ -26,7 +28,8 @@ export default function ChildMenu(props: Props) {
<Text<"a">
component="a"
className={classNames.link}
href={`/dashboard${linkPath}`}
href={`${dashboardConfig.baseRoute}${linkPath}`}
fw={props.active ? "bold" : "normal"}
>
{props.item.label}
</Text>

View File

@ -1,4 +1,4 @@
import React, { ReactNode, useState } from "react";
import React, { useState } from "react";
import {
Box,
@ -6,7 +6,9 @@ import {
Group,
ThemeIcon,
UnstyledButton,
alpha,
rem,
useMantineTheme,
} from "@mantine/core";
import { TbChevronRight } from "react-icons/tb";
import * as TbIcons from "react-icons/tb";
@ -14,6 +16,9 @@ import * as TbIcons from "react-icons/tb";
import ChildMenu from "./SidebarChildMenu";
import classNames from "./styles/sidebarMenuItem.module.css";
import SidebarMenu from "../types/SidebarMenu";
import dashboardConfig from "../dashboard.config";
import { usePathname } from "next/navigation";
import areURLsSame from "@/utils/areUrlSame";
interface Props {
menu: SidebarMenu;
@ -30,7 +35,11 @@ interface Props {
export default function MenuItem({ menu }: Props) {
const hasChildren = Array.isArray(menu.children);
const [opened, setOpened] = useState(false);
const pathname = usePathname()
const theme = useMantineTheme();
const [opened, setOpened] = useState(menu.children?.some(child => areURLsSame(`${dashboardConfig.baseRoute}${child.link}`, pathname)) ?? false);
const toggleOpenMenu = () => {
setOpened((prev) => !prev);
@ -38,20 +47,23 @@ export default function MenuItem({ menu }: Props) {
// Mapping children menu items if available
const subItems = (hasChildren ? menu.children! : []).map((child, index) => (
<ChildMenu key={index} item={child} />
<ChildMenu key={index} item={child} active={areURLsSame(`${dashboardConfig.baseRoute}${child.link}`, pathname)} />
));
const Icons = TbIcons as any;
const Icon = typeof menu.icon === "string" ? Icons[menu.icon] : menu.icon;
// const a = typeof menu.icon === "string"
const isActive = areURLsSame(`${dashboardConfig.baseRoute}${menu.link}`, pathname)
return (
<>
{/* Main Menu Item */}
<UnstyledButton
<UnstyledButton<"a" | "button">
onClick={toggleOpenMenu}
className={classNames.control}
href={menu.link ? dashboardConfig.baseRoute + menu.link : ""}
component={menu.link ? "a" : "button"}
>
<Group justify="space-between" gap={0}>
{/* Icon and Label */}
@ -60,7 +72,7 @@ export default function MenuItem({ menu }: Props) {
<Icon style={{ width: rem(18), height: rem(18) }} />
</ThemeIcon>
<Box ml="md">{menu.label}</Box>
<Box ml="md" fw={isActive ? 700 : 500}>{menu.label}</Box>
</Box>
{/* Chevron Icon for collapsible items */}

View File

@ -5,6 +5,7 @@ const sidebarMenus: SidebarMenu[] = [
label: "Dashboard",
icon: "TbLayoutDashboard",
allowedPermissions: ["*"],
link: "/",
},
{
label: "Users",

View File

@ -7,10 +7,11 @@ export default interface SidebarMenu {
children?: {
label: string;
link: string;
allowedPermissions?: PermissionCode[],
allowedRoles?: RoleCode[],
allowedPermissions?: PermissionCode[];
allowedRoles?: RoleCode[];
}[];
link?: string;
color?: ThemeIconProps["color"];
allowedPermissions?: PermissionCode[],
allowedRoles?: RoleCode[]
}
allowedPermissions?: PermissionCode[];
allowedRoles?: RoleCode[];
}

13
src/utils/areUrlSame.ts Normal file
View File

@ -0,0 +1,13 @@
function areURLsSame(url1: string, url2: string): boolean {
const normalizeUrl = (url: string) => {
// Remove query parameters
url = url.split("?")[0];
// Ensure there is no trailing slash
url = url.endsWith("/") ? url.slice(0, -1) : url;
return url.toLowerCase();
};
return normalizeUrl(url1) === normalizeUrl(url2);
}
export default areURLsSame;