Add base authenticated route
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
import * as React from "react";
|
||||
import { type Theme, type SxProps } from "@mui/material/styles";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Grow from "@mui/material/Grow";
|
||||
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 Paper from "@mui/material/Paper";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import type {} from "@mui/material/themeCssVarsAugmentation";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import { Link } from "react-router";
|
||||
import DashboardSidebarContext from "./DashboardSidebarContext";
|
||||
import { MINI_DRAWER_WIDTH } from "./constants";
|
||||
|
||||
export interface DashboardSidebarPageItemProps {
|
||||
id: string;
|
||||
title: string;
|
||||
icon?: React.ReactNode;
|
||||
href: string;
|
||||
action?: React.ReactNode;
|
||||
defaultExpanded?: boolean;
|
||||
expanded?: boolean;
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
nestedNavigation?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function DashboardSidebarPageItem({
|
||||
id,
|
||||
title,
|
||||
icon,
|
||||
href,
|
||||
action,
|
||||
defaultExpanded = false,
|
||||
expanded = defaultExpanded,
|
||||
selected = false,
|
||||
disabled = false,
|
||||
nestedNavigation,
|
||||
}: DashboardSidebarPageItemProps) {
|
||||
const sidebarContext = React.useContext(DashboardSidebarContext);
|
||||
if (!sidebarContext) {
|
||||
throw new Error("Sidebar context was used without a provider.");
|
||||
}
|
||||
const {
|
||||
onPageItemClick,
|
||||
mini = false,
|
||||
fullyExpanded = true,
|
||||
fullyCollapsed = false,
|
||||
} = sidebarContext;
|
||||
|
||||
const [isHovered, setIsHovered] = React.useState(false);
|
||||
|
||||
const handleClick = React.useCallback(() => {
|
||||
if (onPageItemClick) {
|
||||
onPageItemClick(id, !!nestedNavigation);
|
||||
}
|
||||
}, [onPageItemClick, id, nestedNavigation]);
|
||||
|
||||
let nestedNavigationCollapseSx: SxProps<Theme> = { display: "none" };
|
||||
if (mini && fullyCollapsed) {
|
||||
nestedNavigationCollapseSx = {
|
||||
fontSize: 18,
|
||||
position: "absolute",
|
||||
top: "41.5%",
|
||||
right: "2px",
|
||||
transform: "translateY(-50%) rotate(-90deg)",
|
||||
};
|
||||
} else if (!mini && fullyExpanded) {
|
||||
nestedNavigationCollapseSx = {
|
||||
ml: 0.5,
|
||||
fontSize: 20,
|
||||
transform: `rotate(${expanded ? 0 : -90}deg)`,
|
||||
transition: (theme: Theme) =>
|
||||
theme.transitions.create("transform", {
|
||||
easing: theme.transitions.easing.sharp,
|
||||
duration: 100,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const hasExternalHref = href
|
||||
? href.startsWith("http://") || href.startsWith("https://")
|
||||
: false;
|
||||
|
||||
const LinkComponent = hasExternalHref ? "a" : Link;
|
||||
|
||||
const miniNestedNavigationSidebarContextValue = React.useMemo(() => {
|
||||
return {
|
||||
onPageItemClick: onPageItemClick ?? (() => {}),
|
||||
mini: false,
|
||||
fullyExpanded: true,
|
||||
fullyCollapsed: false,
|
||||
hasDrawerTransitions: false,
|
||||
};
|
||||
}, [onPageItemClick]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ListItem
|
||||
disablePadding
|
||||
{...(nestedNavigation && mini
|
||||
? {
|
||||
onMouseEnter: () => {
|
||||
setIsHovered(true);
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
setIsHovered(false);
|
||||
},
|
||||
}
|
||||
: {})}
|
||||
sx={{
|
||||
display: "block",
|
||||
py: 0,
|
||||
px: 1,
|
||||
overflowX: "hidden",
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
selected={selected}
|
||||
disabled={disabled}
|
||||
sx={{
|
||||
height: mini ? 50 : "auto",
|
||||
}}
|
||||
{...(nestedNavigation && !mini
|
||||
? {
|
||||
onClick: handleClick,
|
||||
}
|
||||
: {})}
|
||||
{...(!nestedNavigation
|
||||
? {
|
||||
LinkComponent,
|
||||
...(hasExternalHref
|
||||
? {
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
}
|
||||
: {}),
|
||||
to: href,
|
||||
onClick: handleClick,
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{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}
|
||||
{nestedNavigation ? (
|
||||
<ExpandMoreIcon sx={nestedNavigationCollapseSx} />
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
{nestedNavigation && mini ? (
|
||||
<Grow in={isHovered}>
|
||||
<Box
|
||||
sx={{
|
||||
position: "fixed",
|
||||
left: MINI_DRAWER_WIDTH - 2,
|
||||
pl: "6px",
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={8}
|
||||
sx={{
|
||||
pt: 0.2,
|
||||
pb: 0.2,
|
||||
transform: "translateY(-50px)",
|
||||
}}
|
||||
>
|
||||
<DashboardSidebarContext.Provider
|
||||
value={miniNestedNavigationSidebarContextValue}
|
||||
>
|
||||
{nestedNavigation}
|
||||
</DashboardSidebarContext.Provider>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Grow>
|
||||
) : null}
|
||||
</ListItem>
|
||||
{nestedNavigation && !mini ? (
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
{nestedNavigation}
|
||||
</Collapse>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user