118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
'use client';
|
|
import React, { useState, useEffect } from 'react';
|
|
import Link from 'next/link';
|
|
import { usePathname } from 'next/navigation';
|
|
import { Menu, X, Eye, Tv2, TreePine, Heart, Calendar, Info } from 'lucide-react';
|
|
|
|
const links = [
|
|
{ href: '/streams', label: 'Live Cams', icon: Tv2 },
|
|
{ href: '/wildlife', label: 'Wildlife', icon: TreePine },
|
|
{ href: '/events', label: 'Events', icon: Calendar },
|
|
{ href: '/donate', label: 'Donate', icon: Heart },
|
|
{ href: '/about', label: 'About', icon: Info },
|
|
];
|
|
|
|
export default function Navbar() {
|
|
const [open, setOpen] = useState(false);
|
|
const [scrolled, setScrolled] = useState(false);
|
|
const pathname = usePathname();
|
|
|
|
useEffect(() => {
|
|
const handler = () => setScrolled(window.scrollY > 40);
|
|
window.addEventListener('scroll', handler);
|
|
return () => window.removeEventListener('scroll', handler);
|
|
}, []);
|
|
|
|
return (
|
|
<header
|
|
className={`sticky top-0 z-50 w-full transition-all duration-300 ${
|
|
scrolled
|
|
? 'bg-deepGreen/95 backdrop-blur-md shadow-lg shadow-black/30 border-b border-white/5'
|
|
: 'bg-deepGreen border-b border-white/5'
|
|
}`}
|
|
>
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between gap-6">
|
|
{/* Logo */}
|
|
<Link href="/" className="flex items-center gap-2 shrink-0 group">
|
|
<div className="w-9 h-9 rounded-full bg-teal/20 flex items-center justify-center border border-teal/30 group-hover:border-teal/60 transition-all">
|
|
<Eye size={20} className="text-teal" />
|
|
</div>
|
|
<div className="flex flex-col leading-none">
|
|
<span className="text-gold font-bold text-base tracking-tight">Owl Stream</span>
|
|
<span className="text-stone-400 text-[10px] font-medium tracking-widest uppercase">CCFW</span>
|
|
</div>
|
|
</Link>
|
|
|
|
{/* Desktop Nav */}
|
|
<nav className="hidden md:flex items-center gap-1">
|
|
{links.map(({ href, label }) => {
|
|
const active = pathname === href || pathname.startsWith(href + '/');
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
className={`px-4 py-2 rounded-lg text-sm font-semibold transition-all ${
|
|
active
|
|
? 'bg-teal/20 text-teal'
|
|
: 'text-stone-300 hover:text-white hover:bg-white/5'
|
|
}`}
|
|
>
|
|
{label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
{/* Donate CTA (desktop) */}
|
|
<Link
|
|
href="/donate"
|
|
className="hidden md:inline-flex items-center gap-2 px-5 py-2 rounded-full bg-gold text-deepGreen font-bold text-sm hover:bg-goldLight transition-all shadow-lg shadow-gold/20 shrink-0"
|
|
>
|
|
<Heart size={14} />
|
|
Support CCFW
|
|
</Link>
|
|
|
|
{/* Mobile hamburger */}
|
|
<button
|
|
className="md:hidden p-2 rounded-lg text-stone-300 hover:bg-white/10 transition-all"
|
|
onClick={() => setOpen(!open)}
|
|
aria-label="Toggle menu"
|
|
>
|
|
{open ? <X size={24} /> : <Menu size={24} />}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Mobile Menu */}
|
|
{open && (
|
|
<div className="md:hidden bg-surfaceGreen border-t border-white/5 px-4 py-4 space-y-1">
|
|
{links.map(({ href, label, icon: Icon }) => {
|
|
const active = pathname === href;
|
|
return (
|
|
<Link
|
|
key={href}
|
|
href={href}
|
|
onClick={() => setOpen(false)}
|
|
className={`flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all ${
|
|
active ? 'bg-teal/20 text-teal' : 'text-stone-300 hover:bg-white/5 hover:text-white'
|
|
}`}
|
|
>
|
|
<Icon size={18} />
|
|
{label}
|
|
</Link>
|
|
);
|
|
})}
|
|
<div className="pt-3 border-t border-white/5">
|
|
<Link
|
|
href="/donate"
|
|
onClick={() => setOpen(false)}
|
|
className="flex items-center justify-center gap-2 w-full py-3 rounded-xl bg-gold text-deepGreen font-bold text-sm"
|
|
>
|
|
<Heart size={16} /> Support CCFW
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</header>
|
|
);
|
|
}
|