Files
2026-04-02 23:54:51 +01:00

88 lines
3.7 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { SITE, GITEA_URL, GITEA_USERNAME } from '@/lib/config';
export default function Nav() {
const [scrolled, setScrolled] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
useEffect(() => {
const fn = () => setScrolled(window.scrollY > 24);
window.addEventListener('scroll', fn, { passive: true });
return () => window.removeEventListener('scroll', fn);
}, []);
const links = [
{ href: '#about', label: 'About' },
{ href: '#projects', label: 'Projects' },
{ href: '#activity', label: 'Activity' },
{ href: '#contact', label: 'Contact' },
];
const navBase = 'fixed top-0 left-0 right-0 z-50 h-[60px] flex items-center transition-all duration-300';
const navStyle = scrolled
? 'bg-[rgba(7,7,7,0.85)] backdrop-blur-[20px] border-b border-white/[0.06]'
: 'bg-transparent';
return (
<nav className={`${navBase} ${navStyle}`} aria-label="Main navigation">
<div className="w-full max-w-5xl mx-auto px-6 flex items-center justify-between gap-8">
<a href="#" className="flex items-center gap-2.5 group" aria-label="William March">
<span className="text-sm font-semibold text-white/80 group-hover:text-white transition-colors duration-150 tracking-tight">
William March
</span>
</a>
<ul className="hidden md:flex items-center gap-7" role="list">
{links.map(l => (
<li key={l.href}>
<a href={l.href}
className="text-sm text-white/40 hover:text-white/80 transition-colors duration-150 font-medium">
{l.label}
</a>
</li>
))}
</ul>
<div className="hidden md:flex items-center gap-3">
<a
href={`${GITEA_URL}/${GITEA_USERNAME}`}
target="_blank" rel="noopener noreferrer"
className="flex items-center gap-1.5 text-xs text-white/40 hover:text-white/70 transition-colors duration-150 font-mono"
aria-label="Gitea profile">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" aria-hidden="true">
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.2c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/>
<path d="M9 18c-4.51 2-5-2-7-2"/>
</svg>
Git Repo
</a>
</div>
<button
className="md:hidden p-1.5 rounded-md text-white/50 hover:text-white/80 hover:bg-white/[0.05] transition-all"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu" aria-expanded={mobileOpen}>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
{mobileOpen
? <><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></>
: <><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></>
}
</svg>
</button>
</div>
{mobileOpen && (
<div className="absolute top-[60px] left-0 right-0 bg-[#0f0f0f] border-b border-white/[0.06] px-6 py-4 md:hidden">
{links.map(l => (
<a key={l.href} href={l.href}
onClick={() => setMobileOpen(false)}
className="block py-2.5 text-sm text-white/60 hover:text-white transition-colors">
{l.label}
</a>
))}
</div>
)}
</nav>
);
}