wilddragon-site/src.bright-backup/components/Navigation.tsx
2026-04-17 15:51:01 -04:00

150 lines
5 KiB
TypeScript
Executable file

"use client";
import { useState, useEffect } from "react";
import { Menu, X } from "lucide-react";
import Image from "next/image";
const navLinks = [
{ href: "#about", label: "About" },
{ href: "#services", label: "Services" },
{ href: "#projects", label: "Projects" },
{ href: "#gallery", label: "Gallery" },
{ href: "#contact", label: "Contact" },
];
export default function Navigation() {
const [scrolled, setScrolled] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
const [activeSection, setActiveSection] = useState("");
useEffect(() => {
const handleScroll = () => setScrolled(window.scrollY > 50);
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
// Track active section
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveSection(`#${entry.target.id}`);
}
});
},
{ threshold: 0.3, rootMargin: "-80px 0px -40% 0px" }
);
const sections = document.querySelectorAll("section[id]");
sections.forEach((section) => observer.observe(section));
return () => observer.disconnect();
}, []);
// Lock body scroll when mobile menu is open
useEffect(() => {
document.body.style.overflow = mobileOpen ? "hidden" : "";
return () => { document.body.style.overflow = ""; };
}, [mobileOpen]);
return (
<nav
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-500 ${
scrolled
? "bg-surface/90 backdrop-blur-xl border-b border-border py-3"
: "bg-transparent py-5"
}`}
>
<div className="max-w-6xl mx-auto px-6 flex items-center justify-between">
<a href="#" className="flex items-center gap-3 group">
<Image
src="/images/dragon-mark.png"
alt="Wild Dragon"
width={28}
height={28}
className="brightness-0 invert transition-all duration-300"
/>
<span className="font-mono text-[11px] tracking-[0.2em] uppercase text-white/80 group-hover:text-white transition-colors duration-300">
Wild Dragon
</span>
</a>
{/* Desktop nav */}
<div className="hidden md:flex items-center gap-8">
{navLinks.map((link) => (
<a
key={link.href}
href={link.href}
className={`text-[13px] font-medium transition-all duration-200 relative ${
activeSection === link.href
? "text-accent"
: "text-white/50 hover:text-white"
}`}
>
{link.label}
{activeSection === link.href && (
<span className="absolute -bottom-1.5 left-0 right-0 h-px bg-accent glow-accent-sm" />
)}
</a>
))}
<a
href="#contact"
className="ml-2 px-5 py-2 text-[12px] font-medium rounded-md bg-accent text-white hover:bg-accent-light transition-all duration-200 hover:shadow-lg hover:shadow-accent/20"
>
Hire Me
</a>
</div>
{/* Mobile toggle */}
<button
className="md:hidden relative z-50"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
{mobileOpen ? (
<X className="text-white" size={22} />
) : (
<Menu className="text-white" size={22} />
)}
</button>
</div>
{/* Mobile menu - full overlay */}
<div
className={`md:hidden fixed inset-0 bg-surface z-40 transition-all duration-300 ${
mobileOpen
? "opacity-100 pointer-events-auto"
: "opacity-0 pointer-events-none"
}`}
>
<div className="flex flex-col items-center justify-center h-full gap-8">
{navLinks.map((link, i) => (
<a
key={link.href}
href={link.href}
onClick={() => setMobileOpen(false)}
className={`text-2xl font-light text-white/80 hover:text-accent transition-all duration-300 ${
mobileOpen
? "opacity-100 translate-y-0"
: "opacity-0 translate-y-4"
}`}
style={{ transitionDelay: mobileOpen ? `${i * 80 + 100}ms` : "0ms" }}
>
{link.label}
</a>
))}
<a
href="#contact"
onClick={() => setMobileOpen(false)}
className={`mt-4 px-8 py-3.5 bg-accent text-white text-base font-medium rounded-md transition-all duration-300 hover:shadow-lg hover:shadow-accent/20 ${
mobileOpen ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"
}`}
style={{ transitionDelay: mobileOpen ? `${navLinks.length * 80 + 100}ms` : "0ms" }}
>
Hire Me
</a>
</div>
</div>
</nav>
);
}