S SmartDocs
系列: Ricky typescript 96 行 · 更新於 2026-04-18

SiteHeader.tsx

Ricky/cat_project/frontend/src/components/SiteHeader.tsx

"use client";

import Link from "next/link";
import { useCallback, useEffect, useState } from "react";

export function SiteHeader() {
  const [open, setOpen] = useState(false);
  const [isMobile, setIsMobile] = useState(false);

  const closeMenu = useCallback(() => setOpen(false), []);

  useEffect(() => {
    const mq = window.matchMedia("(max-width: 768px)");
    const sync = () => setIsMobile(mq.matches);
    sync();
    mq.addEventListener("change", sync);
    return () => mq.removeEventListener("change", sync);
  }, []);

  useEffect(() => {
    if (!open) return;
    document.body.style.overflow = "hidden";
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") closeMenu();
    };
    window.addEventListener("keydown", onKey);
    return () => {
      document.body.style.overflow = "";
      window.removeEventListener("keydown", onKey);
    };
  }, [open, closeMenu]);

  useEffect(() => {
    if (!isMobile && open) setOpen(false);
  }, [isMobile, open]);

  return (
    <header className={`Header${open ? " Header--menu-open" : ""}`}>
      <div className="logo">
        <div className="logo-circle">
          <div className="cat-face" />
        </div>
        <h1>PawMatch</h1>
      </div>

      <button
        type="button"
        className="Header-menuBtn"
        aria-expanded={open}
        aria-controls="site-nav-drawer"
        onClick={() => setOpen((v) => !v)}
      >
        <span className="sr-only">{open ? "Close menu" : "Open menu"}</span>
        <span className="Header-menuBtn-bars" aria-hidden />
      </button>

      {open && isMobile && (
        <button
          type="button"
          className="Header-backdrop"
          aria-label="Close menu"
          onClick={closeMenu}
        />
      )}

      <div
        id="site-nav-drawer"
        className="Header-panel"
        inert={isMobile && !open ? true : undefined}
      >
        <nav className="Header-links" aria-label="Page sections">
          <a href="#features" onClick={closeMenu}>
            Features
          </a>
          <a href="#how" onClick={closeMenu}>
            How It Works
          </a>
          <a href="#mission" onClick={closeMenu}>
            Mission
          </a>
          <a href="#benefits" onClick={closeMenu}>
            Benefits
          </a>
        </nav>
        <nav className="Header-ctas" aria-label="Account">
          <Link href="/cat-questionnaire" className="btn-primary" onClick={closeMenu}>
            Join Platform
          </Link>
          <Link href="/login" className="btn-primary" onClick={closeMenu}>
            Login
          </Link>
        </nav>
      </div>
    </header>
  );
}

相關文章