Refactored side menu to a separate component.

This commit is contained in:
Jay
2025-06-17 10:20:28 -04:00
parent c0343f2378
commit 2a35da629b
7 changed files with 320 additions and 156 deletions
@@ -0,0 +1,88 @@
.sideMenu {
height: 100vh;
width: 0;
position: fixed;
z-index: 20;
top: 0;
background: white;
overflow-x: hidden;
transition: 0.3s ease-out;
}
.sideMenuUnderlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 20;
background: rgba(0, 0, 0, 0);
transition: background-color 0.3s;
pointer-events: none;
}
.sideMenuUnderlay.open {
background: rgba(0, 0, 0, 0.2);
pointer-events: auto;
}
.left.sideMenu {
left: 0;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.2);
}
.right.sideMenu {
right: 0;
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2);
}
.menuWrapper {
position: absolute;
}
.left.menuWrapper {
right: 0;
}
.right.menuWrapper {
left: 0;
}
.topNav {
width: 100%;
display: flex;
}
.right.sideMenu .closeButton {
margin: 10px;
}
.left.sideMenu .closeButton {
margin: 10px 10px 10px auto;
}
/* Landscape Phone */
@media (min-width: 568px) and (max-width: 991px) and (orientation: landscape) {
.left.sideMenu.open,
.left.menuWrapper {
width: 80vh;
}
.right.sideMenu.open,
.right.menuWrapper {
width: 80vh;
}
}
/* Portrait Phone */
@media (max-width: 567px) {
.left.sideMenu.open,
.left.menuWrapper {
width: 80vw;
}
.right.sideMenu.open,
.right.menuWrapper {
width: 80vw;
}
}
+73
View File
@@ -0,0 +1,73 @@
import type { ReactNode } from "react";
import clsx from "clsx";
import styles from "./SideMenu.module.css";
interface SideMenuProps {
isOpen: boolean;
onClose: () => void;
children: ReactNode;
}
interface BaseMenuProps extends SideMenuProps {
position: "left" | "right";
}
function BaseMenu({ isOpen, onClose, children, position }: BaseMenuProps) {
const isLeftMenu = position === "left";
const handleUnderlayClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) {
onClose();
}
};
return (
<div
className={clsx(styles.sideMenuUnderlay, { [styles.open]: isOpen })}
onClick={handleUnderlayClick}
>
<div
data-cy={`${position}-menu`}
className={clsx(
styles.sideMenu,
isLeftMenu ? styles.left : styles.right,
{ [styles.open]: isOpen },
)}
onClick={(e) => e.stopPropagation()}
>
<div
className={clsx(
styles.menuWrapper,
isLeftMenu ? styles.left : styles.right,
)}
>
<div className={styles.topNav}>
<button
data-cy="close-menu"
className={styles.closeButton}
onClick={onClose}
>
×
</button>
</div>
{children}
</div>
</div>
</div>
);
}
function newSideMenu(position: "left" | "right") {
return function SideMenu({ isOpen, onClose, children }: SideMenuProps) {
return (
<BaseMenu isOpen={isOpen} onClose={onClose} position={position}>
{children}
</BaseMenu>
);
};
}
const LeftMenu = newSideMenu("left");
const RightMenu = newSideMenu("right");
export { LeftMenu, RightMenu };
+2
View File
@@ -0,0 +1,2 @@
import { LeftMenu, RightMenu } from "./SideMenu";
export { LeftMenu, RightMenu };