2026-10-24 21:19:22 +02:00
|
|
|
import { useEffect, useState } from 'react';
|
2025-12-01 22:57:12 +01:00
|
|
|
import Link from 'next/link';
|
2026-10-24 21:19:22 +02:00
|
|
|
import ThemeToggle from './ThemeToggle';
|
|
|
|
|
import Icon from './Icon';
|
|
|
|
|
|
|
|
|
|
const links = [
|
|
|
|
|
{ href: '/#about', label: 'About' },
|
|
|
|
|
{ href: '/#stack', label: 'Stack' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export default function Header() {
|
|
|
|
|
const [scrolled, setScrolled] = useState(false);
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const onScroll = () => setScrolled(window.scrollY > 8);
|
|
|
|
|
onScroll();
|
|
|
|
|
window.addEventListener('scroll', onScroll, { passive: true });
|
|
|
|
|
return () => window.removeEventListener('scroll', onScroll);
|
|
|
|
|
}, []);
|
2025-12-01 22:57:12 +01:00
|
|
|
|
|
|
|
|
return (
|
2026-10-24 21:19:22 +02:00
|
|
|
<header className={`header ${scrolled ? 'is-scrolled' : ''} ${open ? 'is-open' : ''}`}>
|
|
|
|
|
<nav className="navbar shell">
|
|
|
|
|
<Link href="/" className="logo" onClick={() => setOpen(false)}>
|
2026-10-24 22:12:25 +02:00
|
|
|
<svg className="logo-mark" viewBox="0 0 32 32" aria-hidden="true">
|
|
|
|
|
<rect width="32" height="32" rx="7" fill="#0c0a09" />
|
|
|
|
|
<g fill="none" stroke="#fafaf9" strokeWidth="3" strokeLinecap="round">
|
|
|
|
|
<path d="M11.5 13v9a3.5 3.5 0 0 1-3.5 3.5h-1" />
|
|
|
|
|
<path d="M15.5 18h10a5 5 0 1 0-1.46 3.54" />
|
|
|
|
|
</g>
|
|
|
|
|
<circle cx="11.5" cy="8" r="2" fill="#34d399" />
|
|
|
|
|
</svg>
|
2026-10-24 21:19:22 +02:00
|
|
|
<span className="logo-text">
|
|
|
|
|
jesseinit<span className="logo-dot">.dev</span>
|
|
|
|
|
</span>
|
|
|
|
|
</Link>
|
|
|
|
|
|
|
|
|
|
<div className="nav-links">
|
|
|
|
|
{links.map((link) => (
|
|
|
|
|
<Link key={link.href} href={link.href} className="nav-link" onClick={() => setOpen(false)}>
|
|
|
|
|
{link.label}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="nav-actions">
|
|
|
|
|
<ThemeToggle />
|
|
|
|
|
<a href="/#contact" className="button button-primary button-small nav-cta">
|
|
|
|
|
Contact
|
|
|
|
|
</a>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="icon-button nav-menu"
|
|
|
|
|
aria-label={open ? 'Close menu' : 'Open menu'}
|
|
|
|
|
aria-expanded={open}
|
|
|
|
|
onClick={() => setOpen(!open)}
|
|
|
|
|
>
|
|
|
|
|
<Icon name={open ? 'close' : 'menu'} />
|
|
|
|
|
</button>
|
2025-12-01 22:57:12 +01:00
|
|
|
</div>
|
|
|
|
|
</nav>
|
|
|
|
|
</header>
|
|
|
|
|
);
|
|
|
|
|
}
|