143 lines
4.1 KiB
TypeScript
143 lines
4.1 KiB
TypeScript
import Avatar from "@mui/material/Avatar";
|
|
import Box from "@mui/material/Box";
|
|
import ListItem from "@mui/material/ListItem";
|
|
import ListItemButton from "@mui/material/ListItemButton";
|
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
|
import ListItemText from "@mui/material/ListItemText";
|
|
import Typography from "@mui/material/Typography";
|
|
import type {} from "@mui/material/themeCssVarsAugmentation";
|
|
import * as React from "react";
|
|
import { Link, matchPath, useLocation } from "react-router";
|
|
import DashboardSidebarContext from "./DashboardSidebarContext";
|
|
import { MINI_DRAWER_WIDTH } from "./constants";
|
|
|
|
export interface DashboardSidebarPageItemProps {
|
|
title: string;
|
|
icon?: React.ReactNode;
|
|
href: string;
|
|
action?: React.ReactNode;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export default function DashboardSidebarPageItem({
|
|
title,
|
|
icon,
|
|
href,
|
|
action,
|
|
disabled = false,
|
|
}: DashboardSidebarPageItemProps) {
|
|
const { pathname } = useLocation();
|
|
|
|
const sidebarContext = React.useContext(DashboardSidebarContext);
|
|
if (!sidebarContext) {
|
|
throw new Error("Sidebar context was used without a provider.");
|
|
}
|
|
const {
|
|
onPageItemClick,
|
|
mini = false,
|
|
fullyExpanded = true,
|
|
} = sidebarContext;
|
|
|
|
const hasExternalHref = href
|
|
? href.startsWith("http://") || href.startsWith("https://")
|
|
: false;
|
|
|
|
const LinkComponent = hasExternalHref ? "a" : Link;
|
|
|
|
const selected = !!matchPath(href, pathname);
|
|
|
|
return (
|
|
<React.Fragment>
|
|
<ListItem disablePadding style={{ padding: "5px" }}>
|
|
<ListItemButton
|
|
selected={selected}
|
|
disabled={disabled}
|
|
sx={{
|
|
height: mini ? 50 : "auto",
|
|
}}
|
|
{...{
|
|
LinkComponent,
|
|
...(hasExternalHref
|
|
? {
|
|
target: "_blank",
|
|
rel: "noopener noreferrer",
|
|
}
|
|
: {}),
|
|
to: href,
|
|
onClick: onPageItemClick,
|
|
}}
|
|
>
|
|
{icon || mini ? (
|
|
<Box
|
|
sx={
|
|
mini
|
|
? {
|
|
position: "absolute",
|
|
left: "50%",
|
|
top: "calc(50% - 6px)",
|
|
transform: "translate(-50%, -50%)",
|
|
}
|
|
: {}
|
|
}
|
|
>
|
|
<ListItemIcon
|
|
sx={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: mini ? "center" : "auto",
|
|
}}
|
|
>
|
|
{icon ?? null}
|
|
{!icon && mini ? (
|
|
<Avatar
|
|
sx={{
|
|
fontSize: 10,
|
|
height: 16,
|
|
width: 16,
|
|
}}
|
|
>
|
|
{title
|
|
.split(" ")
|
|
.slice(0, 2)
|
|
.map((titleWord) => titleWord.charAt(0).toUpperCase())}
|
|
</Avatar>
|
|
) : null}
|
|
</ListItemIcon>
|
|
{mini ? (
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
position: "absolute",
|
|
bottom: -18,
|
|
left: "50%",
|
|
transform: "translateX(-50%)",
|
|
fontSize: 10,
|
|
fontWeight: 500,
|
|
textAlign: "center",
|
|
whiteSpace: "nowrap",
|
|
overflow: "hidden",
|
|
textOverflow: "ellipsis",
|
|
maxWidth: MINI_DRAWER_WIDTH - 28,
|
|
}}
|
|
>
|
|
{title}
|
|
</Typography>
|
|
) : null}
|
|
</Box>
|
|
) : null}
|
|
{!mini ? (
|
|
<ListItemText
|
|
primary={title}
|
|
sx={{
|
|
whiteSpace: "nowrap",
|
|
zIndex: 1,
|
|
}}
|
|
/>
|
|
) : null}
|
|
{action && !mini && fullyExpanded ? action : null}
|
|
</ListItemButton>
|
|
</ListItem>
|
|
</React.Fragment>
|
|
);
|
|
}
|