import Link from "next/link"; import { useRouter } from "next/router"; import React, { useReducer } from "react"; import { Image } from "./Image"; import styles from "./Navbar.module.css"; type Menu = { name: string; route: string; submenu?: { name: string; route: string; }[]; }[]; const menu: Menu = [ { name: "Home", route: "/", }, { name: "About", route: "/about", submenu: [ { name: "About Us", route: "/about", }, { name: "Meet the Team", route: "/about/team", }, { name: "Constitution", route: "/about/constitution", }, { name: "Code of Conduct", route: "/about/code-of-conduct", }, { name: "Our Supporters", route: "/about/our-supporters", }, ], }, { name: "Get Involved", route: "/get-involved", }, { name: "Events", route: "/events", }, { name: "Resources", route: "/resources/services", submenu: [ { name: "Services", route: "/resources/services", }, { name: "Machine Usage", route: "/resources/machine-usage-agreement", }, { name: "Tech Talks", route: "/resources/tech-talks", }, { name: "CS Club Wiki", route: "https://wiki.csclub.uwaterloo.ca", }, { name: "Advice", route: "/resources/advice/coop", }, { name: "Internships", route: "https://github.com/uwcsc/winter2022-internships", }, ], }, ]; export function Navbar() { const router = useRouter(); const [state, dispatch] = useReducer(reducer, initialState); return ( ); } interface MobileState { isNavOpen: boolean; activeSubmenus: Set; // strings are NavLink routes } type MobileAction = | { type: "open"; route: string } | { type: "toggle"; route: string } | { type: "close" }; const initialState: MobileState = { isNavOpen: false, activeSubmenus: new Set(), }; function reducer(state: MobileState, action: MobileAction): MobileState { switch (action.type) { case "open": return { isNavOpen: true, activeSubmenus: new Set([getMainRoute(action.route)]), }; case "toggle": { const newSet = new Set(state.activeSubmenus); if (state.activeSubmenus.has(getMainRoute(action.route))) { newSet.delete(getMainRoute(action.route)); } else { newSet.add(getMainRoute(action.route)); } return { isNavOpen: state.isNavOpen, activeSubmenus: newSet, }; } case "close": return initialState; } } interface NavItemProps { name: string; route: string; submenu?: { name: string; route: string; }[]; mainRouteActive: boolean; onToggle(route: string): void; onClose(): void; } function NavItem(props: NavItemProps) { const router = useRouter(); const isCurrentPage = router.pathname === props.route || (props.submenu != null && router.pathname.startsWith(getMainRoute(props.route))); const isExternalLink = props.route.includes("http://") || props.route.includes("https://"); function handleClick() { if (document.activeElement instanceof HTMLElement) { document.activeElement.blur(); } props.onClose(); } return ( <> {isExternalLink ? ( {props.name} ) : ( {props.name} )} {(props.submenu?.length ?? 0) > 0 ? ( <> ) : null} ); } function getMainRoute(route: string) { if (route === "/") { return "/"; } else if (route.startsWith("http://") || route.startsWith("https://")) { return route; } return "/" + route.split("/")[1]; }