Skip to content

Commit aadc490

Browse files
Merge pull request #150 from BHUVANSH855/enhancement/142-active-navbar
Enhancement: Add Active Page Indicator in Navbar (#142)
2 parents 9aa4c03 + 5e9c1c2 commit aadc490

File tree

1 file changed

+138
-25
lines changed

1 file changed

+138
-25
lines changed

src/components/site-header.tsx

Lines changed: 138 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use client";
2-
2+
import { usePathname } from "next/navigation";
33
import { useTheme } from "@/state/theme";
44
import Link from "next/link";
55
import Image from "next/image";
@@ -14,6 +14,39 @@ export default function SiteHeader() {
1414
const { data: session } = useSession();
1515
const [open, setOpen] = useState(false);
1616
const { theme, changeTheme } = useTheme();
17+
const pathname = usePathname();
18+
const [activeSection, setActiveSection] = useState<string | null>(null);
19+
const isRouteActive = (path: string) => pathname === path;
20+
21+
useEffect(() => {
22+
if (pathname !== "/") {
23+
setActiveSection(null);
24+
return;
25+
}
26+
27+
const sections = ["features", "how-it-works", "testimonials", "faq"];
28+
29+
const handleScroll = () => {
30+
let currentSection: string | null = null;
31+
32+
for (const section of sections) {
33+
const element = document.getElementById(section);
34+
if (element) {
35+
const rect = element.getBoundingClientRect();
36+
if (rect.top <= 150 && rect.bottom >= 150) {
37+
currentSection = section;
38+
}
39+
}
40+
}
41+
42+
setActiveSection(currentSection);
43+
};
44+
45+
window.addEventListener("scroll", handleScroll);
46+
handleScroll();
47+
48+
return () => window.removeEventListener("scroll", handleScroll);
49+
}, [pathname]);
1750

1851
useEffect(() => {
1952
document.body.style.overflow = open ? "hidden" : "auto";
@@ -39,12 +72,66 @@ export default function SiteHeader() {
3972

4073
{/* NAV LINKS */}
4174
<nav className="hidden items-center text-sm font-medium text-slate-600 dark:text-slate-300 gap-8 md:flex">
42-
<Link href="/#features" className="hover:text-slate-900 dark:hover:text-white">Features</Link>
43-
<Link href="/#how-it-works" className="hover:text-slate-900 dark:hover:text-white">How it works</Link>
44-
<Link href="/#testimonials" className="hover:text-slate-900 dark:hover:text-white">Stories</Link>
45-
<Link href="/#faq" className="hover:text-slate-900 dark:hover:text-white">FAQ</Link>
46-
<Link href="/upload" className="hover:text-slate-900 dark:hover:text-white">Upload</Link>
47-
<Link href="/routes" className="hover:text-slate-900 dark:hover:text-white">Routes</Link>
75+
<Link
76+
href="/#features"
77+
className={`transition-colors ${
78+
activeSection === "features"
79+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
80+
: "hover:text-slate-900 dark:hover:text-white"
81+
}`}
82+
>
83+
Features
84+
</Link>
85+
<Link
86+
href="/#how-it-works"
87+
className={`transition-colors ${
88+
activeSection === "how-it-works"
89+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
90+
: "hover:text-slate-900 dark:hover:text-white"
91+
}`}
92+
>
93+
How it works
94+
</Link>
95+
<Link
96+
href="/#testimonials"
97+
className={`transition-colors ${
98+
activeSection === "testimonials"
99+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
100+
: "hover:text-slate-900 dark:hover:text-white"
101+
}`}
102+
>
103+
Stories
104+
</Link>
105+
<Link
106+
href="/#faq"
107+
className={`transition-colors ${
108+
activeSection === "faq"
109+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
110+
: "hover:text-slate-900 dark:hover:text-white"
111+
}`}
112+
>
113+
FAQ
114+
</Link>
115+
<Link
116+
href="/upload"
117+
className={`transition-colors ${
118+
isRouteActive("/upload")
119+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
120+
: "hover:text-slate-900 dark:hover:text-white"
121+
}`}
122+
>
123+
Upload
124+
</Link>
125+
<Link
126+
href="/routes"
127+
className={`transition-colors ${
128+
isRouteActive("/routes")
129+
? "text-slate-900 dark:text-white font-semibold border-b-2 border-slate-900 dark:border-white"
130+
: "hover:text-slate-900 dark:hover:text-white"
131+
}`}
132+
>
133+
Routes
134+
</Link>
48135
</nav>
49136

50137
{/* RIGHT SIDE */}
@@ -92,24 +179,50 @@ export default function SiteHeader() {
92179
{/* MOBILE MENU */}
93180
<AnimatePresence>
94181
{open && (
95-
<motion.div
96-
initial={{ opacity: 0, height: 0 }}
97-
animate={{ opacity: 1, height: "auto" }}
98-
exit={{ opacity: 0, height: 0 }}
99-
className="md:hidden bg-white dark:bg-slate-900 border-t dark:border-slate-800"
100-
>
101-
<div className="px-6 py-4 space-y-3">
102-
<Link href="/upload">Upload</Link>
103-
<Link href="/routes">Routes</Link>
104-
105-
{session?.user?.id ? (
106-
<Link href="/dashboard">Dashboard</Link>
107-
) : (
108-
<>
109-
<Link href="/signin">Sign in</Link>
110-
<Link href="/signup">Get started</Link>
111-
</>
112-
)}
182+
<motion.div initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }} className="overflow-hidden z-20 absolute left-0 right-0 border-b border-slate-200/60 dark:border-slate-800/60 bg-white dark:bg-slate-900 md:hidden transition duration-150">
183+
<div className="mx-auto max-w-6xl px-6 py-3">
184+
<div className="grid gap-2 dark:*:text-slate-200">
185+
<Link href="/#features" className="rounded px-2 py-2 text-slate-800 hover:opacity-80" onClick={() => setOpen(false)}>Features</Link>
186+
<Link href="/#how-it-works" className="rounded px-2 py-2 text-slate-800 hover:opacity-80" onClick={() => setOpen(false)}>How it works</Link>
187+
<Link href="/#testimonials" className="rounded px-2 py-2 text-slate-800 hover:opacity-80" onClick={() => setOpen(false)}>Stories</Link>
188+
<Link href="/#faq" className="rounded px-2 py-2 text-slate-800 hover:opacity-80" onClick={() => setOpen(false)}>FAQ</Link>
189+
<Link
190+
href="/upload"
191+
className={`rounded px-2 py-2 ${
192+
isRouteActive("/upload")
193+
? "bg-slate-100 dark:bg-slate-800 font-semibold"
194+
: "text-slate-800 hover:opacity-80"
195+
}`}
196+
onClick={() => setOpen(false)}
197+
>
198+
Upload
199+
</Link>
200+
<Link
201+
href="/routes"
202+
className={`rounded px-2 py-2 ${
203+
isRouteActive("/routes")
204+
? "bg-slate-100 dark:bg-slate-800 font-semibold"
205+
: "text-slate-800 hover:opacity-80"
206+
}`}
207+
onClick={() => setOpen(false)}
208+
>
209+
Routes
210+
</Link>
211+
<div className="flex pl-2 pr-8 py-2 justify-between">
212+
<p>Dark Theme</p>
213+
<Toggle theme={theme} changeTheme={changeTheme} />
214+
</div>
215+
<div className="flex flex-col gap-2 pt-2 border-t border-slate-100 dark:border-slate-800">
216+
{session?.user?.id ? (
217+
<Link className="rounded-lg bg-slate-900 dark:bg-white px-4 py-2.5 text-center text-sm font-semibold text-white dark:text-slate-900 shadow-sm" href="/dashboard" onClick={() => setOpen(false)}>Dashboard</Link>
218+
) : (
219+
<>
220+
<Link href="/signin" className="text-center py-2 text-sm font-medium text-slate-600 dark:text-slate-300" onClick={() => setOpen(false)}>Sign in</Link>
221+
<Link href="/signup" className="rounded-lg bg-slate-900 dark:bg-white px-4 py-2.5 text-center text-sm font-semibold text-white dark:text-slate-900 shadow-sm" onClick={() => setOpen(false)}>Get started</Link>
222+
</>
223+
)}
224+
</div>
225+
</div>
113226
</div>
114227
</motion.div>
115228
)}

0 commit comments

Comments
 (0)