1- "use client" ;
1+ "use client" ;
22
33import Link from "next/link" ;
44import { Menu , X } from "lucide-react" ;
55import { signOut , useSession } from "next-auth/react" ;
66import { usePathname } from "next/navigation" ;
77import { useEffect , useMemo , useState } from "react" ;
88
9- type NavItem = {
10- href : string ;
11- label : string ;
12- } ;
9+ type NavItem = { href : string ; label : string } ;
1310
1411function isActivePath ( pathname : string , href : string ) {
15- if ( href === "/" ) {
16- return pathname === "/" ;
17- }
18-
12+ if ( href === "/" ) return pathname === "/" ;
1913 if ( href . includes ( "#" ) ) {
2014 const [ base ] = href . split ( "#" ) ;
2115 return pathname === base ;
2216 }
23-
2417 return pathname === href || pathname . startsWith ( `${ href } /` ) ;
2518}
19+
20+ const MONO = "var(--font-jetbrains, ui-monospace, monospace)" ;
21+
2622export default function AppNavbar ( ) {
2723 const pathname = usePathname ( ) ;
2824 const { data : session , status } = useSession ( ) ;
2925 const [ mobileOpen , setMobileOpen ] = useState ( false ) ;
26+ const [ scrolled , setScrolled ] = useState ( false ) ;
27+
28+ useEffect ( ( ) => { setMobileOpen ( false ) ; } , [ pathname ] ) ;
3029
3130 useEffect ( ( ) => {
32- setMobileOpen ( false ) ;
33- } , [ pathname ] ) ;
31+ const fn = ( ) => setScrolled ( window . scrollY > 20 ) ;
32+ window . addEventListener ( "scroll" , fn , { passive : true } ) ;
33+ return ( ) => window . removeEventListener ( "scroll" , fn ) ;
34+ } , [ ] ) ;
3435
3536 const isAuthenticated = status === "authenticated" && Boolean ( session ) ;
3637 const isPublicProfileRoute = pathname . startsWith ( "/u/" ) ;
3738 const identityLabel =
38- session ?. user ?. name ?? session ?. githubLogin ?? session ?. user ?. email ?? "GitHub user" ;
39+ session ?. githubLogin ?? session ?. user ?. name ?? session ?. user ?. email ?? "user" ;
3940
4041 const navItems = useMemo < NavItem [ ] > ( ( ) => {
4142 if ( isAuthenticated ) {
4243 return [
4344 { href : "/dashboard" , label : "Dashboard" } ,
4445 { href : "/dashboard#streaks" , label : "Streaks" } ,
45- { href : "/dashboard#pull-requests" , label : "Pull Requests " } ,
46+ { href : "/dashboard#pull-requests" , label : "PRs " } ,
4647 { href : "/dashboard#goals" , label : "Goals" } ,
4748 { href : "/leaderboard" , label : "Leaderboard" } ,
4849 { href : "/dashboard/settings" , label : "Settings" } ,
4950 ] ;
5051 }
51-
5252 return [
5353 { href : "/" , label : "Home" } ,
5454 { href : "/#features" , label : "Features" } ,
@@ -57,126 +57,164 @@ export default function AppNavbar() {
5757 ] ;
5858 } , [ isAuthenticated ] ) ;
5959
60+ const headerStyle : React . CSSProperties = {
61+ position : "sticky" ,
62+ top : 0 ,
63+ zIndex : 50 ,
64+ background : scrolled ? "rgba(6,11,24,0.92)" : "var(--background)" ,
65+ backdropFilter : scrolled ? "blur(16px)" : "none" ,
66+ WebkitBackdropFilter : scrolled ? "blur(16px)" : "none" ,
67+ borderBottom : "1px solid var(--border)" ,
68+ transition : "background 0.3s ease" ,
69+ } ;
70+
6071 return (
61- < header className = "sticky top-0 z-50 border-b border-[var(--border)] bg-[var(--background)] backdrop-blur-md" >
72+ < header style = { headerStyle } >
6273 < div className = "mx-auto flex w-full max-w-7xl items-center justify-between gap-4 px-4 py-3 sm:px-6 lg:px-8" >
74+
75+ { /* Logo */ }
6376 < Link
6477 href = { isAuthenticated ? "/dashboard" : "/" }
65- className = "inline-flex items-center gap-2 text-sm font-semibold tracking-[0.16em] text-[var(--foreground)] "
66- style = { { fontFamily : "var(--font-jetbrains, ui-monospace, monospace)" } }
78+ className = "inline-flex items-center gap-2 select-none "
79+ style = { { fontFamily : MONO } }
6780 >
68- < span className = "text-[ var(--accent)]" > { ">" } </ span >
69- < span > DEVTRACK</ span >
81+ < span className = "text-base font-bold" style = { { color : " var(--accent)" } } > ▲ </ span >
82+ < span className = "text-sm font-bold tracking-[0.18em] text-[var(--foreground)]" > DEVTRACK</ span >
7083 </ Link >
7184
72- < nav className = "hidden items-center gap-2 lg:flex" >
85+ { /* Desktop nav */ }
86+ < nav className = "hidden items-center lg:flex" aria-label = "Main navigation" >
7387 { navItems . map ( ( item ) => {
7488 const active = isActivePath ( pathname , item . href ) ;
75-
7689 return (
7790 < Link
7891 key = { item . href }
7992 href = { item . href }
80- className = { `rounded-full px-4 py-2 text-sm font-medium transition-colors ${
81- active
82- ? "bg-[var(--accent-soft)] text-[var(--accent)]"
83- : "text-[var(--muted-foreground)] hover:bg-[var(--card)] hover:text-[var(--foreground)]"
84- } `}
93+ className = "relative px-3 py-2 text-[12px] font-medium transition-colors duration-150"
94+ style = { {
95+ fontFamily : MONO ,
96+ color : active ? "var(--accent)" : "var(--muted-foreground)" ,
97+ } }
98+ onMouseEnter = { ( e ) => {
99+ if ( ! active ) ( e . currentTarget as HTMLAnchorElement ) . style . color = "var(--foreground)" ;
100+ } }
101+ onMouseLeave = { ( e ) => {
102+ if ( ! active ) ( e . currentTarget as HTMLAnchorElement ) . style . color = "var(--muted-foreground)" ;
103+ } }
85104 >
86105 { item . label }
106+ { active && (
107+ < span
108+ className = "absolute inset-x-2 bottom-0 h-px"
109+ style = { { background : "var(--accent)" } }
110+ />
111+ ) }
87112 </ Link >
88113 ) ;
89114 } ) }
90115 </ nav >
91116
117+ { /* Desktop right */ }
92118 < div className = "hidden items-center gap-3 lg:flex" >
93119 { isAuthenticated ? (
94120 < >
95- < div className = "hidden max-w-48 truncate rounded-full border border-[var(--border)] bg-[var(--card)] px-4 py-2 text-sm text-[var(--card-foreground)] xl:block" >
96- { identityLabel }
97- </ div >
121+ < span
122+ className = "hidden max-w-44 truncate text-[11px] text-[var(--muted-foreground)] xl:block"
123+ style = { { fontFamily : MONO } }
124+ >
125+ @{ identityLabel }
126+ </ span >
98127 < button
99128 type = "button"
100129 onClick = { ( ) => signOut ( { callbackUrl : "/" } ) }
101- className = "rounded-full bg-[var(--destructive)] px-4 py-2 text-sm font-semibold text-[var(--destructive-foreground)] transition-opacity hover:opacity-90"
130+ className = "rounded-md border border-[var(--border)] px-3 py-1.5 text-[11px] font-medium text-[var(--muted-foreground)] transition-colors hover:border-red-500/60 hover:text-red-400"
131+ style = { { fontFamily : MONO } }
102132 >
103- Sign out
133+ sign out →
104134 </ button >
105135 </ >
106136 ) : (
107137 ! isPublicProfileRoute && (
108138 < Link
109139 href = "/api/auth/signin/github?callbackUrl=/dashboard"
110- className = "rounded-full bg-[var(--accent)] px-4 py-2 text-sm font-semibold text-[var(--accent-foreground)] transition-opacity hover:opacity-90"
140+ className = "rounded-md px-4 py-2 text-[12px] font-semibold text-[var(--accent-foreground)] transition-opacity hover:opacity-90"
141+ style = { { fontFamily : MONO , background : "var(--accent)" } }
111142 >
112- Sign in with GitHub
143+ SIGN IN →
113144 </ Link >
114145 )
115146 ) }
116147 </ div >
117148
149+ { /* Mobile hamburger */ }
118150 < button
119151 type = "button"
120- onClick = { ( ) => setMobileOpen ( ( open ) => ! open ) }
121- className = "inline-flex items-center justify-center rounded-full border border-[var(--border)] bg-[var(--card )] p-2 text-[var(--foreground)] lg:hidden"
152+ onClick = { ( ) => setMobileOpen ( ( o ) => ! o ) }
153+ className = "inline-flex items-center justify-center rounded-md border border-[var(--border)] p-2 text-[var(--foreground)] lg:hidden"
122154 aria-expanded = { mobileOpen }
123155 aria-controls = "app-mobile-nav"
124156 aria-label = { mobileOpen ? "Close navigation menu" : "Open navigation menu" }
125157 >
126- { mobileOpen ? < X className = "h-5 w-5 " /> : < Menu className = "h-5 w-5 " /> }
158+ { mobileOpen ? < X className = "h-4 w-4 " /> : < Menu className = "h-4 w-4 " /> }
127159 </ button >
128160 </ div >
129161
130- { mobileOpen ? (
162+ { /* Mobile menu */ }
163+ { mobileOpen && (
131164 < div
132165 id = "app-mobile-nav"
133- className = "border-t border-[var(--border)] bg-[var(--background)] lg:hidden"
166+ className = "border-t border-[var(--border)] lg:hidden"
167+ style = { { background : "rgba(6,11,24,0.97)" , backdropFilter : "blur(16px)" } }
134168 >
135- < div className = "mx-auto flex w-full max-w-7xl flex-col gap-2 px-4 py-4 sm:px-6 lg:px-8 " >
169+ < div className = "mx-auto flex w-full max-w-7xl flex-col gap-1 px-4 py-4 sm:px-6" >
136170 { navItems . map ( ( item ) => {
137171 const active = isActivePath ( pathname , item . href ) ;
138-
139172 return (
140173 < Link
141174 key = { item . href }
142175 href = { item . href }
143- className = { `rounded-2xl px-4 py-3 text-sm font-medium transition-colors ${
144- active
145- ? "bg-[var(--accent-soft)] text-[var(--accent)]"
146- : "bg-[var(--card)] text-[var(--card-foreground)] hover:bg-[var(--control)]"
147- } `}
176+ className = "rounded-lg px-4 py-3 text-sm font-medium transition-colors"
177+ style = { {
178+ fontFamily : MONO ,
179+ color : active ? "var(--accent)" : "var(--muted-foreground)" ,
180+ background : active ? "var(--accent-soft)" : "transparent" ,
181+ } }
148182 >
149183 { item . label }
150184 </ Link >
151185 ) ;
152186 } ) }
153187
154- { isAuthenticated ? (
155- < >
156- < div className = "rounded-2xl border border-[var(--border)] bg-[var(--card)] px-4 py-3 text-sm text-[var(--card-foreground)]" >
157- { identityLabel }
158- </ div >
159- < button
160- type = "button"
161- onClick = { ( ) => signOut ( { callbackUrl : "/" } ) }
162- className = "rounded-2xl bg-[var(--destructive)] px-4 py-3 text-left text-sm font-semibold text-[var(--destructive-foreground)]"
163- >
164- Sign out
165- </ button >
166- </ >
167- ) : (
168- ! isPublicProfileRoute && (
169- < Link
170- href = "/api/auth/signin/github?callbackUrl=/dashboard"
171- className = "rounded-2xl bg-[var(--accent)] px-4 py-3 text-sm font-semibold text-[var(--accent-foreground)]"
172- >
173- Sign in with GitHub
174- </ Link >
175- )
176- ) }
188+ < div className = "mt-3 border-t border-[var(--border)] pt-3" >
189+ { isAuthenticated ? (
190+ < >
191+ < p className = "px-4 py-1.5 text-[11px] text-[var(--muted-foreground)]" style = { { fontFamily : MONO } } >
192+ @{ identityLabel }
193+ </ p >
194+ < button
195+ type = "button"
196+ onClick = { ( ) => signOut ( { callbackUrl : "/" } ) }
197+ className = "w-full rounded-lg px-4 py-3 text-left text-sm font-medium text-red-400 transition-colors hover:bg-red-500/10"
198+ style = { { fontFamily : MONO } }
199+ >
200+ sign out →
201+ </ button >
202+ </ >
203+ ) : (
204+ ! isPublicProfileRoute && (
205+ < Link
206+ href = "/api/auth/signin/github?callbackUrl=/dashboard"
207+ className = "block rounded-lg px-4 py-3 text-center text-sm font-semibold text-[var(--accent-foreground)]"
208+ style = { { background : "var(--accent)" } }
209+ >
210+ SIGN IN →
211+ </ Link >
212+ )
213+ ) }
214+ </ div >
177215 </ div >
178216 </ div >
179- ) : null }
217+ ) }
180218 </ header >
181219 ) ;
182220}
0 commit comments