2026-02-07 20:17:46 -05:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import { usePathname } from 'next/navigation';
|
2026-05-25 09:49:40 -04:00
|
|
|
import { useEffect, useId, useRef, useState } from 'react';
|
2026-04-11 23:27:29 -04:00
|
|
|
import { ThemeToggle } from './ThemeToggle';
|
2026-02-07 20:17:46 -05:00
|
|
|
|
2026-05-25 09:49:40 -04:00
|
|
|
const navItems = [
|
|
|
|
|
{ href: '/', label: 'Home' },
|
2026-05-25 10:05:58 -04:00
|
|
|
{ href: '/projects', label: 'Projects' },
|
2026-05-25 09:49:40 -04:00
|
|
|
{ href: '/blog', label: 'Writing' },
|
|
|
|
|
{ href: '/resume', label: 'Resume' },
|
|
|
|
|
];
|
|
|
|
|
|
2026-02-07 20:17:46 -05:00
|
|
|
export function Navbar() {
|
|
|
|
|
const pathname = usePathname();
|
2026-04-14 18:07:25 -04:00
|
|
|
const [menuOpen, setMenuOpen] = useState(false);
|
2026-05-25 09:49:40 -04:00
|
|
|
const menuId = useId();
|
2026-04-14 18:07:25 -04:00
|
|
|
const menuRef = useRef<HTMLDivElement | null>(null);
|
2026-02-07 20:17:46 -05:00
|
|
|
|
2026-05-25 09:49:40 -04:00
|
|
|
const isActive = (path: string) => path === '/' ? pathname === '/' : pathname?.startsWith(path);
|
|
|
|
|
const linkClass = (path: string) => `relative py-1 transition-colors after:absolute after:inset-x-0 after:-bottom-0.5 after:h-px after:origin-left after:bg-accent after:transition-transform ${isActive(path)
|
|
|
|
|
? 'text-ink after:scale-x-100'
|
|
|
|
|
: 'hover:text-ink after:scale-x-0 hover:after:scale-x-100'
|
|
|
|
|
}`;
|
2026-04-14 18:07:25 -04:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!menuOpen) return;
|
|
|
|
|
|
|
|
|
|
const handlePointer = (event: MouseEvent) => {
|
|
|
|
|
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
|
|
|
setMenuOpen(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const handleKey = (event: KeyboardEvent) => {
|
|
|
|
|
if (event.key === 'Escape') setMenuOpen(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.addEventListener('mousedown', handlePointer);
|
|
|
|
|
document.addEventListener('keydown', handleKey);
|
|
|
|
|
return () => {
|
|
|
|
|
document.removeEventListener('mousedown', handlePointer);
|
|
|
|
|
document.removeEventListener('keydown', handleKey);
|
|
|
|
|
};
|
|
|
|
|
}, [menuOpen]);
|
|
|
|
|
|
2026-02-07 20:17:46 -05:00
|
|
|
return (
|
2026-04-11 23:27:29 -04:00
|
|
|
<nav
|
|
|
|
|
aria-label="Main navigation"
|
2026-05-25 09:49:40 -04:00
|
|
|
className="fixed left-0 top-0 z-50 w-full border-b border-line bg-paper-overlay shadow-[0_1px_0_rgba(255,255,255,0.26)] backdrop-blur-xl"
|
2026-04-11 23:27:29 -04:00
|
|
|
>
|
2026-05-25 09:49:40 -04:00
|
|
|
<div className="mx-auto flex h-14 max-w-[72rem] items-center justify-between gap-4 px-5 sm:px-6">
|
|
|
|
|
<Link href="/" className="flex min-w-0 items-baseline gap-2.5 transition-opacity hover:opacity-75">
|
|
|
|
|
<span className="truncate text-[0.96rem] font-medium text-ink">
|
2026-04-11 23:27:29 -04:00
|
|
|
Akshay Kolli
|
|
|
|
|
</span>
|
2026-05-25 09:49:40 -04:00
|
|
|
<span className="hidden font-mono text-[0.65rem] uppercase text-muted-strong sm:inline">
|
2026-04-11 23:27:29 -04:00
|
|
|
Research
|
|
|
|
|
</span>
|
2026-02-07 20:17:46 -05:00
|
|
|
</Link>
|
|
|
|
|
|
2026-05-25 09:49:40 -04:00
|
|
|
<div className="flex items-center gap-2 text-[0.68rem] font-mono uppercase text-muted-strong sm:gap-5">
|
|
|
|
|
<div className="hidden items-center gap-5 sm:flex">
|
|
|
|
|
{navItems.map((item) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={item.href}
|
|
|
|
|
href={item.href}
|
|
|
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
|
|
|
|
className={linkClass(item.href)}
|
|
|
|
|
>
|
|
|
|
|
{item.label}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
<a
|
|
|
|
|
href="https://github.com/akkolli"
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
aria-label="GitHub profile"
|
|
|
|
|
className="transition-colors hover:text-ink"
|
|
|
|
|
>
|
|
|
|
|
GitHub
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
2026-04-14 18:07:25 -04:00
|
|
|
<div ref={menuRef} className="relative sm:hidden">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setMenuOpen((open) => !open)}
|
|
|
|
|
aria-label="More navigation items"
|
|
|
|
|
aria-expanded={menuOpen}
|
2026-05-25 09:49:40 -04:00
|
|
|
aria-controls={menuId}
|
|
|
|
|
className="inline-flex h-8 w-8 items-center justify-center rounded-full border border-transparent text-muted-strong transition-colors hover:border-line hover:bg-accent-soft hover:text-ink"
|
2026-04-14 18:07:25 -04:00
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
aria-hidden="true"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
className="h-4 w-4 fill-none stroke-current"
|
|
|
|
|
strokeWidth="1.7"
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
>
|
|
|
|
|
<path d="M4 7h16" />
|
|
|
|
|
<path d="M4 12h16" />
|
|
|
|
|
<path d="M4 17h16" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
{menuOpen && (
|
|
|
|
|
<div
|
2026-05-25 09:49:40 -04:00
|
|
|
id={menuId}
|
|
|
|
|
className="absolute right-0 top-[calc(100%+0.65rem)] min-w-[10.5rem] overflow-hidden rounded-md border border-line bg-paper-strong shadow-[0_18px_46px_rgba(17,19,21,0.13)]"
|
2026-04-14 18:07:25 -04:00
|
|
|
>
|
2026-05-25 09:49:40 -04:00
|
|
|
<nav aria-label="Mobile navigation" className="py-1">
|
|
|
|
|
{navItems.map((item) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={item.href}
|
|
|
|
|
href={item.href}
|
|
|
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
|
|
|
|
onClick={() => setMenuOpen(false)}
|
|
|
|
|
className={`block px-3.5 py-2.5 text-[0.68rem] font-mono uppercase transition-colors hover:bg-accent-soft hover:text-ink ${isActive(item.href) ? 'bg-accent-soft text-ink' : 'text-muted-strong'}`}
|
|
|
|
|
>
|
|
|
|
|
{item.label}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
<a
|
|
|
|
|
href="https://github.com/akkolli"
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
aria-label="GitHub profile"
|
|
|
|
|
className="block px-3.5 py-2.5 text-[0.68rem] font-mono uppercase text-muted-strong transition-colors hover:bg-accent-soft hover:text-ink"
|
|
|
|
|
>
|
|
|
|
|
GitHub
|
|
|
|
|
</a>
|
|
|
|
|
</nav>
|
2026-04-14 18:07:25 -04:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-04-11 23:27:29 -04:00
|
|
|
<ThemeToggle />
|
2026-02-07 20:17:46 -05:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</nav>
|
|
|
|
|
);
|
|
|
|
|
}
|