agency-web/app/components/SiteHeader.tsx

82 lines
2.5 KiB
TypeScript

"use client";
/**
* SiteHeader — fixed top nav. Compacts (adds a glass backdrop) once you scroll
* past the hero, and includes a mobile menu toggle. The wordmark is real text
* ("feedback studios") with the brand mark inline.
*/
import { useEffect, useRef, useState } from "react";
import PillMark from "./PillMark";
const links = [
{ href: "#services", label: "Services" },
{ href: "#work", label: "Work" },
{ href: "#process", label: "About" },
{ href: "#faq", label: "FAQ" },
];
export default function SiteHeader() {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
const headerRef = useRef<HTMLElement>(null);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 80);
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
// Close the mobile menu on Escape.
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === "Escape") setOpen(false);
};
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open]);
return (
<header
ref={headerRef}
className={`site-header${scrolled ? " is-scrolled" : ""}${open ? " is-open" : ""}`}
>
<div className="site-header__inner">
<a className="brand hoverable" href="#top" aria-label="Feedback Studios, home">
<PillMark className="brand__mark" title="Feedback Studios" />
<span className="brand__word">
feedback<span className="brand__word-2">studios</span>
</span>
</a>
<nav className="site-nav" aria-label="Primary">
<ul>
{links.map((l) => (
<li key={l.href}>
<a className="hoverable" href={l.href} onClick={() => setOpen(false)}>
{l.label}
</a>
</li>
))}
</ul>
<a className="btn btn--sm btn--primary hoverable" href="#contact" onClick={() => setOpen(false)}>
<span>Get a growth audit</span>
</a>
</nav>
<button
type="button"
className="site-header__toggle hoverable"
aria-expanded={open}
aria-label={open ? "Close menu" : "Open menu"}
onClick={() => setOpen((v) => !v)}
>
<span />
<span />
</button>
</div>
</header>
);
}