import { useEffect, useState } from "react" import { ArrowUpRight } from "lucide-react" import { Button } from "@/components/ui/button" import { Logo } from "@/components/ui/logo" export function Header() { // 두 상태는 조건이 다르다. 하나로 묶으면 다크 히어로 위에 흰 바가 떠버린다. // compact — 조금이라도 스크롤하면 높이를 줄인다. // onStage — 다크 히어로를 벗어나기 전까지. 이때는 배경을 깔지 않고 로고를 반전시킨다. const [compact, setCompact] = useState(false) const [onStage, setOnStage] = useState(true) useEffect(() => { const handleScroll = () => setCompact(window.scrollY > 40) window.addEventListener("scroll", handleScroll, { passive: true }) handleScroll() return () => window.removeEventListener("scroll", handleScroll) }, []) /* "다크 히어로 위에 있는가"는 스크롤 수치가 아니라 교차 상태다. scrollY 로 계산하면 하이드레이션 전에 스크롤 위치가 잡힌 경우(ScrollRestoration, 새로고침, 뒤로가기) 초기 계산이 0 에서 끝나고 이후 스크롤 이벤트가 없으면 영영 갱신되지 않는다 — 흰 배경 위에 흰 글자 버튼이 남는다. IntersectionObserver 는 관찰 시작 즉시 올바른 값을 준다. */ useEffect(() => { const stage = document.querySelector("[data-stage-hero]") if (!stage) { setOnStage(false) // 다크 히어로가 없는 페이지에서는 항상 라이트 return } // 헤더 높이(약 80px)만큼 위에서 미리 전환되도록 상단 마진을 음수로 준다. const io = new IntersectionObserver(([entry]) => setOnStage(entry.isIntersecting), { rootMargin: "-80px 0px 0px 0px", threshold: 0, }) io.observe(stage) return () => io.disconnect() }, []) return (
) } const NAV_LINKS = [ { href: "#how-it-works", label: "협상 데모" }, { href: "#how-it-works-demo", label: "이용 가이드" }, { href: "#comparison", label: "도입 전후 비교" }, { href: "#faq", label: "자주 묻는 질문" }, ]