|
|
|
@ -9,16 +9,15 @@ import styles from "./Navbar.module.css"; |
|
|
|
|
type Menu = { |
|
|
|
|
name: string; |
|
|
|
|
route: string; |
|
|
|
|
submenu?: { |
|
|
|
|
name: string; |
|
|
|
|
route: string; |
|
|
|
|
}[]; |
|
|
|
|
exact?: boolean; |
|
|
|
|
submenu?: Menu; |
|
|
|
|
}[]; |
|
|
|
|
|
|
|
|
|
const menu: Menu = [ |
|
|
|
|
{ |
|
|
|
|
name: "Home", |
|
|
|
|
route: "/", |
|
|
|
|
exact: true, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "About", |
|
|
|
@ -27,6 +26,7 @@ const menu: Menu = [ |
|
|
|
|
{ |
|
|
|
|
name: "About Us", |
|
|
|
|
route: "/about", |
|
|
|
|
exact: true, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "Meet the Team", |
|
|
|
@ -76,7 +76,21 @@ const menu: Menu = [ |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "Advice", |
|
|
|
|
route: "/resources/advice/coop", |
|
|
|
|
route: "/resources/advice/co-op", |
|
|
|
|
submenu: [ |
|
|
|
|
{ |
|
|
|
|
name: "Co-op Advice", |
|
|
|
|
route: "/resources/advice/co-op", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "Academic Advice", |
|
|
|
|
route: "/resources/advice/academic", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "Additional Resources", |
|
|
|
|
route: "/resources/advice/misc", |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: "Internships", |
|
|
|
@ -198,10 +212,11 @@ interface NavItemProps { |
|
|
|
|
|
|
|
|
|
function NavItem(props: NavItemProps) { |
|
|
|
|
const router = useRouter(); |
|
|
|
|
const isCurrentPage = |
|
|
|
|
router.pathname === props.route || |
|
|
|
|
(props.submenu != null && |
|
|
|
|
router.pathname.startsWith(getMainRoute(props.route))); |
|
|
|
|
const isCurrentPage = shouldHighlight( |
|
|
|
|
router.pathname, |
|
|
|
|
props.name, |
|
|
|
|
props.route |
|
|
|
|
); |
|
|
|
|
const isExternalLink = |
|
|
|
|
props.route.includes("http://") || props.route.includes("https://"); |
|
|
|
|
|
|
|
|
@ -273,6 +288,54 @@ function NavItem(props: NavItemProps) { |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
interface Leaf { |
|
|
|
|
name: string; |
|
|
|
|
route: string; |
|
|
|
|
exact?: boolean; |
|
|
|
|
ancestors: { name: string; route: string }[]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function collectLeaves( |
|
|
|
|
accumulator: Leaf[], |
|
|
|
|
entry: { |
|
|
|
|
name: string; |
|
|
|
|
route: string; |
|
|
|
|
exact?: boolean; |
|
|
|
|
submenu?: Menu; |
|
|
|
|
} |
|
|
|
|
): Leaf[] { |
|
|
|
|
if (entry.submenu == null) { |
|
|
|
|
return [...accumulator, { ...entry, ancestors: [] }]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const subleaves = entry.submenu.reduce(collectLeaves, [] as Leaf[]); |
|
|
|
|
return [ |
|
|
|
|
...accumulator, |
|
|
|
|
...subleaves.map((leaf) => ({ |
|
|
|
|
...leaf, |
|
|
|
|
ancestors: [...leaf.ancestors, { name: entry.name, route: entry.route }], |
|
|
|
|
})), |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const leaves: Leaf[] = menu.reduce(collectLeaves, [] as Leaf[]); |
|
|
|
|
|
|
|
|
|
function shouldHighlight( |
|
|
|
|
pathname: string, |
|
|
|
|
name: string, |
|
|
|
|
route: string |
|
|
|
|
): boolean { |
|
|
|
|
const match = leaves.find((leaf) => |
|
|
|
|
leaf.exact ? leaf.route === pathname : pathname.startsWith(leaf.route) |
|
|
|
|
); |
|
|
|
|
return match |
|
|
|
|
? (match.name === name && match.route === route) || |
|
|
|
|
match.ancestors.find( |
|
|
|
|
(ancestor) => ancestor.name === name && ancestor.route === route |
|
|
|
|
) != null |
|
|
|
|
: false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getMainRoute(route: string) { |
|
|
|
|
if (route === "/") { |
|
|
|
|
return "/"; |
|
|
|
|