Files
SculptedArcWebSite/components/site-header.tsx

148 lines
4.7 KiB
TypeScript

'use client'
import { useEffect, useRef, useState, type MouseEvent } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import saws from '../assets/saws.png'
import SocialMediaLinks from './social-media-links'
import './site-header.css'
const menuLinks = [
{ label: 'Home', href: '/' },
{ label: 'About', href: '/about-us' },
{ label: 'Services', href: '/services' },
{ label: 'Contact', href: '/contact' },
] as const
const ctaHref = '/contact'
function isActivePath(pathname: string, href: string) {
if (href === '/') return pathname === '/'
return pathname === href || pathname.startsWith(`${href}/`)
}
export default function SiteHeader() {
const pathname = usePathname()
const menuToggleRef = useRef<HTMLInputElement>(null)
const [scrolled, setScrolled] = useState(false)
const [pendingPath, setPendingPath] = useState<string | null>(null)
const activePath = pendingPath ?? pathname
useEffect(() => {
setPendingPath(null)
}, [pathname])
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 24)
onScroll()
window.addEventListener('scroll', onScroll, { passive: true })
return () => window.removeEventListener('scroll', onScroll)
}, [])
const closeMobileMenu = () => {
if (menuToggleRef.current) {
menuToggleRef.current.checked = false
}
}
const handleNavClick =
(href: string) => (event: MouseEvent<HTMLAnchorElement>) => {
setPendingPath(href)
closeMobileMenu()
event.currentTarget.blur()
}
return (
<header className="site-header-wrapper">
<nav
className={`site-header${scrolled ? ' site-header--scrolled' : ''}`}
aria-label="Main navigation"
>
<div className="site-header-content">
<Link href="/" className="site-header-logo" onClick={handleNavClick('/')}>
<img src={saws.src} alt="Sculpted Arc" className="site-header-logo-img" />
</Link>
<div className="site-header-nav desktop-menu">
{menuLinks.map((link) => {
const active = isActivePath(activePath, link.href)
return (
<Link
key={link.label}
href={link.href}
className={`menu-item${active ? ' menu-item--active' : ''}`}
aria-current={active ? 'page' : undefined}
onClick={handleNavClick(link.href)}
>
{link.label}
</Link>
)
})}
</div>
<div className="site-header-actions desktop-actions">
<SocialMediaLinks
className="site-header-social"
linkClassName="site-header-social-link"
/>
<Link href={ctaHref} className="site-header-cta">
Get a quote
</Link>
</div>
<div className="mobile-menu">
<input
ref={menuToggleRef}
type="checkbox"
id="mobile-nav-toggle"
className="mobile-menu-checkbox"
/>
<label
htmlFor="mobile-nav-toggle"
className="burger-icon"
aria-controls="mobile-nav-menu"
>
<span className="burger-icon-menu" aria-hidden="true">
&#9776;
</span>
<span className="burger-icon-close" aria-hidden="true">
&times;
</span>
</label>
<div id="mobile-nav-menu" className="mobile-dropdown">
<div className="mobile-dropdown-inner">
{menuLinks.map((link) => {
const active = isActivePath(activePath, link.href)
return (
<Link
key={link.label}
href={link.href}
className={`menu-item mobile-dropdown-item${active ? ' menu-item--active' : ''}`}
aria-current={active ? 'page' : undefined}
onClick={handleNavClick(link.href)}
>
{link.label}
</Link>
)
})}
<Link
href={ctaHref}
className="site-header-cta site-header-cta--mobile"
onClick={handleNavClick(ctaHref)}
>
Get a quote
</Link>
<SocialMediaLinks
className="site-header-social site-header-social--mobile"
linkClassName="site-header-social-link"
/>
</div>
</div>
</div>
</div>
</nav>
</header>
)
}