Skip to content

Commit f1faf84

Browse files
Add nav highlighting on scroll!!
1 parent 659894e commit f1faf84

File tree

5 files changed

+63
-20
lines changed

5 files changed

+63
-20
lines changed

web/components/NavMenu.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import React from 'react'
2-
import { Link } from 'gatsby'
1+
import React, { useEffect } from 'react'
32
import styled from 'styled-components'
43

54
const NavMenuPanel = styled.nav`
@@ -19,12 +18,11 @@ const A = styled.a`
1918
}
2019
`
2120

22-
export default function NavMenu({ data, handleNavMenuToggle }) {
21+
export default function NavMenu({ data, handleNavMenuToggle, activeSection }) {
2322
// console.log('menu props: ', data)
24-
2523
return (
2624
<NavMenuPanel>
27-
<ul>
25+
<ul id="navmenu_list">
2826
<li>
2927
<A href='#top-of-page'>Home</A>
3028
</li>
@@ -34,6 +32,8 @@ export default function NavMenu({ data, handleNavMenuToggle }) {
3432
<A
3533
href={`#${node.anchor_id}`}
3634
onClick={handleNavMenuToggle}
35+
// TODO: instead of keeping current-section class in css file is there a way to do it with styled-components props and Gatsby
36+
className={node.anchor_id === activeSection && 'current-section'}
3737
>
3838
{node.name}
3939
</A>

web/components/layout.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ export default function Layout({ children }) {
2626
</nav>
2727
</header>
2828

29-
<>
30-
{children}
31-
</>
29+
<>{children}</>
3230

3331
</div>
3432
)

web/src/pages/index.js

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'
22
import { graphql } from 'gatsby'
33
import styled from 'styled-components'
44
import Layout from '../../components/layout'
5-
import Footer from '../../components/footer'
5+
import Footer from '../../components/Footer'
66
import ToC from '../../components/TableOfContents'
77
import NavMenu from '../../components/NavMenu'
88
import TopicSection from '../../components/TopicSection'
@@ -33,17 +33,58 @@ export default function Index({ data }) {
3333
// these "nav" references are for the secondary nav that appears once you've scrolled past table of contents
3434
const [navIsActive, setNavIsActive] = useState(false)
3535
const [navMenuIsActive, setNavMenuIsActive] = useState(false)
36-
// console.log('Index data: ', data)
36+
const [activeSection, setActiveSection] = useState(null)
3737

3838
useEffect(() => {
3939
window.addEventListener('scroll', handleScroll)
40+
window.addEventListener('scroll', handleObserver)
4041
return () => {
4142
window.removeEventListener('scroll', handleScroll)
43+
// TODO: this should be here, right?
44+
window.addEventListener('scroll', handleObserver)
4245
}
4346
}, [])
4447

48+
function handleObserver() {
49+
const options = { rootMargin: '-30px 0px -50% 0px' };
50+
const observer = new IntersectionObserver(checkIntersection, options)
51+
52+
const topicSections = document.querySelectorAll('section')
53+
topicSections.forEach(section => {
54+
observer.observe(section)
55+
})
56+
57+
function checkIntersection(entries) {
58+
entries.forEach(entry => {
59+
if (entry.isIntersecting) {
60+
intersectionHandler(entry)
61+
}
62+
})
63+
}
64+
65+
function intersectionHandler(entry) {
66+
// console.log('intersectionHandler entry: ', entry)
67+
const id = entry.target.id
68+
setActiveSection(id)
69+
const currentlyActive = document.querySelector('#navmenu_list .current-section')
70+
// console.log('currentlyActive: ', currentlyActive)
71+
const shouldBeActive = document.querySelector(`#navmenu_list a[href='#${id}']`)
72+
// console.log('shouldBeActive: ', shouldBeActive)
73+
if (currentlyActive) {
74+
currentlyActive.classList.remove('current-section')
75+
// console.log('currentlyActive if: ', currentlyActive)
76+
}
77+
if (shouldBeActive) {
78+
shouldBeActive.classList.add('current-section')
79+
// console.log('shouldBeActive if: ', shouldBeActive)
80+
}
81+
}
82+
}
83+
4584
function handleScroll() {
4685
console.log('handleScroll')
86+
// TODO: is this all neccessary for cross-browser issues?
87+
// setDocScrollTop(Math.max(document.documentElement.scrollTop, document.body.scrollTop))
4788
// TODO: replace offset number with calculation that determines once ToC section has been passed
4889
if (window.pageYOffset > 900) {
4990
setNavIsActive(true)
@@ -56,9 +97,9 @@ export default function Index({ data }) {
5697
function handleNavMenuToggle() {
5798
setNavMenuIsActive(navMenuIsActive ? false : true)
5899
}
59-
100+
60101
return (
61-
<>
102+
<div>
62103
<Layout id="top-of-page">
63104
<ToC data={data.allSanitySection.edges} />
64105

@@ -84,13 +125,15 @@ export default function Index({ data }) {
84125
<NavMenu
85126
data={data.allSanitySection.edges}
86127
handleNavMenuToggle={handleNavMenuToggle}
128+
activeSection={activeSection}
129+
id="navmenu_list"
87130
/>
88131
)}
89132
</SecondaryNavBar>
90133
)}
91134

92135
<Footer />
93-
</>
136+
</div>
94137
)
95138
}
96139

web/src/styles/global.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ footer span {
235235
line-height: 1.5;
236236
}
237237

238+
.current-section.current-section {
239+
color: rgb(144, 210, 245);
240+
}
241+
242+
.highlight.highlight {
243+
/* font-size: 1.2em; */
244+
color: rgb(144, 210, 245);
245+
}
246+
238247
@media screen and (max-width: 672px) {
239248
body {
240249
font-size: .8em;

web/src/utils/typography.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)