minesweeper/src/Shell.tsx

109 lines
3.3 KiB
TypeScript

import { PropsWithChildren, useEffect, useRef, useState } from "react";
import { Button } from "./components/Button";
import { motion } from "framer-motion";
import { GitBranch, History, Home, Menu, Play, Settings } from "lucide-react";
import Hr from "./components/Hr";
import NavLink from "./components/NavLink";
import { useMediaQuery } from "@uidotdev/usehooks";
import Header from "./components/Header";
import { Tag } from "./components/Tag";
const drawerWidth = 256;
const drawerWidthWithPadding = drawerWidth;
const Shell: React.FC<PropsWithChildren> = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const drawerRef = useRef<HTMLDivElement>(null);
const x = isOpen ? 0 : -drawerWidthWithPadding;
const width = isOpen ? drawerWidthWithPadding : 0;
const isMobile = useMediaQuery("(max-width: 768px)");
useEffect(() => {
setIsOpen(!isMobile);
}, [isMobile]);
useEffect(() => {
const onOutsideClick = (e: MouseEvent) => {
if (
drawerRef.current &&
!drawerRef.current.contains(e.target as Node) &&
isMobile
) {
setIsOpen(false);
e.stopPropagation();
e.preventDefault();
}
};
document.addEventListener("click", onOutsideClick);
return () => {
document.removeEventListener("click", onOutsideClick);
};
});
return (
<div className="bg-black min-h-screen">
<motion.div
className="bg-black p-4 fixed h-screen w-64 flex border-white/10 border-1"
ref={drawerRef}
animate={{ x }}
transition={{ type: "tween" }}
>
<div className="w-full p-2 flex flex-col gap-6">
<h1 className="[background:var(--bg-brand)] [-webkit-text-fill-color:transparent] font-black [-webkit-background-clip:text!important] font-mono text-3xl">
Minesweeper
<br />
Business
</h1>
<Hr />
<NavLink href="/">
<Home />
Home
</NavLink>
<NavLink href="/play">
<Play />
Play
</NavLink>
<NavLink href="/history">
<History />
History
</NavLink>
<NavLink href="/settings">
<Settings />
Settings <Tag size="sm">NEW</Tag>
</NavLink>
<Hr />
<div className="grow" />
<NavLink href="https://github.com/MasterGordon/minesweeper" external>
<GitBranch />
Source
</NavLink>
</div>
<div className="relative">
<Button
className="absolute left-4 bg-black border-white/10 border-y-1 border-r-1 rounded-l-none"
variant="ghost"
onClick={() => setIsOpen((isOpen) => !isOpen)}
>
<Menu />
</Button>
</div>
</motion.div>
<motion.div className="flex max-w-[100vw]">
<motion.div
className="hidden md:block"
animate={{ width: width }}
transition={{ type: "tween" }}
layout
/>
<motion.div className="flex flex-col gap-4 grow max-w-6xl mx-auto w-[calc(100vw-256px)]">
<div className="flex flex-col justify-center gap-4 sm:mx-16 mt-16 sm:mt-2 mx-2">
<Header />
{children}
</div>
</motion.div>
</motion.div>
</div>
);
};
export default Shell;