Skip to content

Commit

Permalink
Added scroll based menu highlight feature (#1085)
Browse files Browse the repository at this point in the history
Co-authored-by: Beier (Bill) <[email protected]>
  • Loading branch information
Tiru-99 and bluebill1049 authored Nov 19, 2024
1 parent 29c6c58 commit 23c94ef
Showing 1 changed file with 75 additions and 22 deletions.
97 changes: 75 additions & 22 deletions src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
import { useEffect, useState } from "react"
import Link from "next/link"
import colors from "../../styles/colors"
import styles from "./SideMenu.module.css"
import typographyStyles from "../../styles/typography.module.css"
import { useRouter } from "next/router"
import colors from "../../styles/colors"
import { Pages } from "../../types/types"

function Menu({ pages = [] }: { pages: Pages }) {
const router = useRouter()
const { asPath: pathname } = router
const [activeSection, setActiveSection] = useState<string>("")

useEffect(() => {
const handleScroll = () => {
const sections = pages.flatMap((page) =>
[page, ...(page.pages || [])].map((p) => ({
id: p.pathname.replace("#", ""),
top:
document.getElementById(p.pathname.replace("#", ""))?.offsetTop ||
0,
}))
)

const currentSection = sections.reduce((acc, section) => {
const { id, top } = section
if (window.scrollY >= top - 100) {
console.log(id)
return id
}
return acc
}, "")

setActiveSection(currentSection)
}

window.addEventListener("scroll", handleScroll)

handleScroll()

return () => window.removeEventListener("scroll", handleScroll)
}, [pages])

const scrollToSection = (sectionId: string, event: React.MouseEvent) => {
event.preventDefault()
const element = document.getElementById(sectionId.replace("#", ""))
if (element) {
element.scrollIntoView({ behavior: "smooth" })
}
}

return (
<aside className={styles.menu}>
Expand All @@ -26,41 +63,57 @@ function Menu({ pages = [] }: { pages: Pages }) {

<ul className="scrollArea">
{pages.map((page) => {
const isActive = pathname === page.pathname
const isActive = activeSection === page.pathname.replace("#", "")
const hasActiveChild = page.pages?.some(
(subPage) => activeSection === subPage.pathname.replace("#", "")
)

return (
<li
key={page.pathname}
className={styles.menuItem}
className={`${styles.menuItem} ${
isActive || hasActiveChild ? styles.activeParent : ""
}`}
style={{
display: page?.pages ? "block" : "flex",
}}
>
<code aria-hidden className={styles.code}>{`</>`}</code>
<Link
className={isActive ? styles.isActive : ""}
<code aria-hidden className={styles.code}>
{`</>`}
</code>
<a
href={page.pathname}
className={isActive ? styles.isActive : ""}
onClick={(e) => scrollToSection(page.pathname, e)}
>
{page.name}
</Link>
</a>

{page?.pages && (
<ul>
{page.pages.map((page) => {
const isActive = pathname === page.pathname
{page.pages.map((subPage) => {
const isSubActive =
activeSection === subPage.pathname.replace("#", "")

return (
<li key={page.pathname} className={styles.menuItem}>
<code
aria-hidden
className={styles.code}
>{`</>`}</code>{" "}
<Link
className={isActive ? styles.isActive : ""}
href={page.pathname}
<li
key={subPage.pathname}
className={`${styles.menuItem} ${
isSubActive ? styles.activeItem : ""
}`}
>
<code aria-hidden className={styles.code}>
{`</>`}
</code>
<a
href={subPage.pathname}
className={isSubActive ? styles.isActive : ""}
onClick={(e) =>
scrollToSection(subPage.pathname, e)
}
>
{page.name}
</Link>
{subPage.name}
</a>
</li>
)
})}
Expand Down

0 comments on commit 23c94ef

Please sign in to comment.