deafgain-website/src/components/Layout/Navbar.tsx

116 lines
3.9 KiB
TypeScript

import { useState, useEffect, useRef } from 'react'
import { Link, useLocation } from 'react-router-dom'
import { motion, AnimatePresence } from 'framer-motion'
import { HiMenu, HiX } from 'react-icons/hi'
const Navbar = () => {
const [isOpen, setIsOpen] = useState(false)
const menuRef = useRef<HTMLDivElement>(null)
const location = useLocation()
const navItems = [
{ name: 'Home', path: '/' },
{ name: 'Services', path: '/services' },
{ name: 'About', path: '/about' },
{ name: 'Resources', path: '/resources' },
{ name: 'Contact', path: '/contact' }
]
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsOpen(false)
}
}
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [])
// Close mobile menu when route changes
useEffect(() => {
setIsOpen(false)
}, [location])
return (
<nav className="bg-primary text-accent-snow relative z-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-24">
<Link
to="/"
className="font-black text-2xl sm:text-3xl tracking-wider text-accent-snow drop-shadow-lg"
aria-label="DeafGain Home"
>
DeafGain
</Link>
{/* Desktop Navigation */}
<div className="hidden md:block">
<div className="flex items-center space-x-8">
{navItems.map((item) => (
<Link
key={item.name}
to={item.path}
className={`text-lg font-bold tracking-wide transition-colors drop-shadow-md
${location.pathname === item.path
? 'text-accent-lake'
: 'text-accent-snow hover:text-accent-lake'}`}
aria-current={location.pathname === item.path ? 'page' : undefined}
>
{item.name}
</Link>
))}
</div>
</div>
{/* Mobile menu button */}
<button
onClick={() => setIsOpen(!isOpen)}
className="md:hidden inline-flex items-center justify-center p-2 rounded-md
text-accent-snow hover:text-accent-lake hover:bg-secondary/20
transition-colors duration-200"
aria-expanded={isOpen}
aria-controls="mobile-menu"
aria-label={isOpen ? "Close menu" : "Open menu"}
>
{isOpen ? <HiX size={28} /> : <HiMenu size={28} />}
</button>
</div>
</div>
{/* Mobile Navigation */}
<AnimatePresence>
{isOpen && (
<motion.div
ref={menuRef}
id="mobile-menu"
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.2 }}
className="md:hidden absolute w-full bg-primary shadow-lg"
>
<div className="px-4 pt-2 pb-3 space-y-1">
{navItems.map((item) => (
<Link
key={item.name}
to={item.path}
className={`block px-3 py-4 text-base font-medium rounded-md
transition-colors duration-200
${location.pathname === item.path
? 'bg-secondary text-accent-lake'
: 'text-accent-snow hover:bg-secondary/20 hover:text-accent-lake'}`}
aria-current={location.pathname === item.path ? 'page' : undefined}
>
{item.name}
</Link>
))}
</div>
</motion.div>
)}
</AnimatePresence>
</nav>
)
}
export default Navbar