Capital/components/AppShell.tsx

140 lines
3.8 KiB
TypeScript
Raw Permalink Normal View History

2024-02-24 06:16:57 +00:00
"use client";
import {
Slide,
Toolbar,
Typography,
AppBar as MuiAppBar,
AppBarProps as MuiAppBarProps,
useScrollTrigger,
IconButton,
2024-02-24 13:56:35 +00:00
styled,
Box,
useMediaQuery,
2024-02-24 06:16:57 +00:00
} from "@mui/material";
import { ReactElement, ReactNode, useEffect, useState } from "react";
import { SITE_NAME } from "@/app/consts";
import NavigationDrawer, { DRAWER_WIDTH, AppNavigationHeader, isMobileQuery } from "@/components/NavigationDrawer";
import MenuIcon from "@mui/icons-material/Menu";
import Image from "next/image";
2024-02-24 09:33:35 +00:00
import Link from "next/link";
2024-02-24 06:16:57 +00:00
2024-02-24 13:56:35 +00:00
function HideOnScroll(props: { window?: () => Window; children: ReactElement }) {
2024-02-24 06:16:57 +00:00
const { children, window } = props;
const trigger = useScrollTrigger({
2024-02-24 13:56:35 +00:00
target: window ? window() : undefined,
2024-02-24 06:16:57 +00:00
});
return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const ShellAppBar = styled(MuiAppBar, {
2024-02-24 13:56:35 +00:00
shouldForwardProp: (prop) => prop !== "open",
2024-02-24 06:16:57 +00:00
})<AppBarProps>(({ theme, open }) => {
const isMobile = useMediaQuery(isMobileQuery);
2024-02-24 13:56:35 +00:00
return {
2024-02-24 06:16:57 +00:00
transition: theme.transitions.create(["margin", "width"], {
easing: theme.transitions.easing.sharp,
2024-02-24 13:56:35 +00:00
duration: theme.transitions.duration.leavingScreen,
2024-02-24 06:16:57 +00:00
}),
2024-02-24 13:56:35 +00:00
...(!isMobile &&
open && {
width: `calc(100% - ${DRAWER_WIDTH}px)`,
transition: theme.transitions.create(["margin", "width"], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginRight: DRAWER_WIDTH,
2024-02-24 06:16:57 +00:00
}),
2024-02-24 13:56:35 +00:00
};
2024-02-24 06:16:57 +00:00
});
const AppMain = styled("main", { shouldForwardProp: (prop) => prop !== "open" })<{
open?: boolean;
}>(({ theme, open }) => {
const isMobile = useMediaQuery(isMobileQuery);
2024-02-24 13:56:35 +00:00
return {
2024-02-24 06:16:57 +00:00
flexGrow: 1,
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.sharp,
2024-02-24 13:56:35 +00:00
duration: theme.transitions.duration.leavingScreen,
2024-02-24 06:16:57 +00:00
}),
marginRight: -DRAWER_WIDTH,
2024-02-24 13:56:35 +00:00
...(!isMobile &&
open && {
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginRight: 0,
2024-02-24 06:16:57 +00:00
}),
2024-02-24 13:56:35 +00:00
position: "relative",
};
2024-02-24 06:16:57 +00:00
});
2024-02-24 13:56:35 +00:00
export default function AppShell({ children }: { children: ReactNode }) {
2024-02-24 06:16:57 +00:00
let documentWindow: Window;
const isMobile = useMediaQuery(isMobileQuery);
const [open, setOpen] = useState(false);
useEffect(() => {
documentWindow = window;
2024-02-24 08:07:59 +00:00
});
2024-02-24 06:16:57 +00:00
return (
2024-02-24 08:07:59 +00:00
<>
2024-02-24 06:16:57 +00:00
<HideOnScroll window={() => documentWindow}>
2024-02-24 08:07:59 +00:00
<ShellAppBar open={open} position="fixed">
<Toolbar sx={{ height: 64 }}>
2024-02-24 06:16:57 +00:00
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
2024-02-24 08:07:59 +00:00
sx={{ ml: isMobile ? 0.5 : 0, mr: 2 }}
2024-02-24 06:16:57 +00:00
>
2024-02-24 09:33:35 +00:00
<Image src="/smartsheep.svg" alt="Logo" width={32} height={32} />
2024-02-24 06:16:57 +00:00
</IconButton>
2024-02-24 10:29:29 +00:00
<Typography variant="h6" component="div" sx={{ flexGrow: 1, fontSize: "1.2rem" }}>
2024-02-24 13:56:35 +00:00
<Link href="/">{SITE_NAME}</Link>
2024-02-24 06:16:57 +00:00
</Typography>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
onClick={() => setOpen(true)}
sx={{ mr: 1, display: !isMobile && open ? "none" : "block" }}
>
<MenuIcon />
</IconButton>
</Toolbar>
</ShellAppBar>
</HideOnScroll>
2024-02-24 08:07:59 +00:00
<Box sx={{ display: "flex" }}>
<AppMain open={open}>
<AppNavigationHeader />
{children}
</AppMain>
2024-02-24 06:16:57 +00:00
2024-02-24 08:07:59 +00:00
<NavigationDrawer open={open} onClose={() => setOpen(false)} />
</Box>
</>
2024-02-24 06:16:57 +00:00
);
2024-02-24 13:56:35 +00:00
}