Skip to content

Commit e3f01b7

Browse files
Fix: Correctly highlight active navigation link on scroll
The previous implementation had a logic flaw where the active navigation link would not be cleared correctly when scrolling between sections. This was because the `setActive` function was only called when a section was in view, but it was not cleared when no section was active. This commit refactors the scroll event handler in `Navbar.tsx` to correctly identify the active section and clear the highlighting if no section is active, regardless of the scroll position. This ensures that the active link is always correctly highlighted.
1 parent c62cc24 commit e3f01b7

File tree

6 files changed

+57
-13
lines changed

6 files changed

+57
-13
lines changed
85.4 KB
Loading
26.3 KB
Loading
495 KB
Loading
60.9 KB
Loading
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import re
2+
from playwright.sync_api import sync_playwright, Page, expect
3+
4+
def run(playwright):
5+
browser = playwright.chromium.launch(headless=True)
6+
page = browser.new_page()
7+
8+
try:
9+
# Navigate to the local development server
10+
page.goto("http://localhost:5173")
11+
12+
# Wait for the page to load by waiting for a known element
13+
page.wait_for_selector("section#about")
14+
15+
# --- Verify 'About' section ---
16+
# Scroll to the 'about' section to trigger the highlighter
17+
page.evaluate("document.querySelector('section#about').scrollIntoView()")
18+
# Wait for scroll and potential UI update
19+
page.wait_for_timeout(500)
20+
# Check if the 'About' link is active
21+
about_link = page.locator('//ul[contains(@class, "sm:flex")]//a[text()="About"]/parent::li')
22+
expect(about_link).to_have_class(re.compile(r"\btext-white\b"))
23+
page.screenshot(path="jules-scratch/verification/verify-about.png")
24+
25+
# --- Verify 'Work' section ---
26+
page.evaluate("document.querySelector('section#work').scrollIntoView()")
27+
page.wait_for_timeout(500)
28+
work_link = page.locator('//ul[contains(@class, "sm:flex")]//a[text()="Work"]/parent::li')
29+
expect(work_link).to_have_class(re.compile(r"\btext-white\b"))
30+
page.screenshot(path="jules-scratch/verification/verify-work.png")
31+
32+
# --- Verify 'Contact' section ---
33+
page.evaluate("document.querySelector('section#contact').scrollIntoView()")
34+
page.wait_for_timeout(500)
35+
contact_link = page.locator('//ul[contains(@class, "sm:flex")]//a[text()="Contact"]/parent::li')
36+
expect(contact_link).to_have_class(re.compile(r"\btext-white\b"))
37+
page.screenshot(path="jules-scratch/verification/verify-contact.png")
38+
39+
# --- Verify scrolling to top ---
40+
page.evaluate("window.scrollTo(0, 0)")
41+
page.wait_for_timeout(500)
42+
# Check that all links are inactive (i.e., have text-secondary class)
43+
inactive_links = page.locator('//ul[contains(@class, "sm:flex")]//li[contains(@class, "text-secondary")]')
44+
expect(inactive_links).to_have_count(3)
45+
page.screenshot(path="jules-scratch/verification/verify-top.png")
46+
47+
finally:
48+
browser.close()
49+
50+
with sync_playwright() as playwright:
51+
run(playwright)

src/components/layout/Navbar.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,10 @@ const Navbar = () => {
1414
useEffect(() => {
1515
const handleScroll = () => {
1616
const scrollTop = window.scrollY;
17-
if (scrollTop > 100) {
18-
setScrolled(true);
19-
} else {
20-
setScrolled(false);
21-
setActive("");
22-
}
23-
};
24-
25-
window.addEventListener("scroll", handleScroll);
17+
setScrolled(scrollTop > 100);
2618

27-
const navbarHighlighter = () => {
2819
const sections = document.querySelectorAll("section[id]");
20+
let activeSectionId: string | null = null;
2921

3022
sections.forEach((current) => {
3123
const sectionId = current.getAttribute("id");
@@ -35,16 +27,17 @@ const Navbar = () => {
3527
current.getBoundingClientRect().top - sectionHeight * 0.2;
3628

3729
if (sectionTop < 0 && sectionTop + sectionHeight > 0) {
38-
setActive(sectionId);
30+
activeSectionId = sectionId;
3931
}
4032
});
33+
34+
setActive(activeSectionId || "");
4135
};
4236

43-
window.addEventListener("scroll", navbarHighlighter);
37+
window.addEventListener("scroll", handleScroll);
4438

4539
return () => {
4640
window.removeEventListener("scroll", handleScroll);
47-
window.removeEventListener("scroll", navbarHighlighter);
4841
};
4942
}, []);
5043

0 commit comments

Comments
 (0)