"use client"; import { useEffect, useState } from "react"; import { usePathname } from "next/navigation"; import Logo from "./Logo"; import NavLinks from "./NavLinks"; import SearchTrigger from "./SearchTrigger"; import AuthMenu from "./auth/AuthMenu"; import RemainingVotesBadge from "./auth/RemainingVotesBadge"; import { cn } from "@/lib/cn"; /** * 导航栏 · 上下文敏感的玻璃态切换 * - 顶部/盖在 Hero 之上时:完全透明,只有内容(无玻璃层、无分割线) * - 内容滚到 nav 下方时:渐显为毛玻璃(blur + saturate + surface 微着色),与下方筛选条无缝连接 * - 玻璃层用独立 absolute 子层 + opacity 过渡,避免直接切 backdrop-filter class 的硬切 * * 检测策略: * - 路由存在 [data-hero-banner] → IntersectionObserver 观察 Hero(首页) * - 否则 → 滚动监听,scrollY <= 0 时透明,任意向下滚动即玻璃 */ export default function Navigation() { const pathname = usePathname(); // 初始乐观:任何页面首屏都假设在顶部/Hero 上,透明。effect 挂载后会立刻校正。 const [isTransparent, setIsTransparent] = useState(true); // 维护一个站内导航计数器(per-tab),供 FloatingBackButton 判断 router.back() 是否安全 useEffect(() => { const prev = parseInt(sessionStorage.getItem("nav:count") || "0", 10); sessionStorage.setItem("nav:count", String(prev + 1)); }, [pathname]); useEffect(() => { const heroEl = document.querySelector("[data-hero-banner]"); // 1) 有 Hero 的页面:观察 Hero 是否还在视口顶部下方 if (heroEl) { setIsTransparent(true); const observer = new IntersectionObserver( ([entry]) => setIsTransparent(entry.isIntersecting), { // 视口顶部下移 80px(导航高度),让 Hero 完全滚出 nav 下方时触发 rootMargin: "-80px 0px 0px 0px", threshold: 0, }, ); observer.observe(heroEl); return () => observer.disconnect(); } // 2) 无 Hero 的页面:scrollY === 0 时透明,任何向下滚动即玻璃 const onScroll = () => setIsTransparent(window.scrollY <= 0); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, [pathname]); return (
{/* 玻璃层 · 通过 opacity 渐显渐隐 · bg-surface 与全站卡片同色 */}
{/* 顶部 1px 高光 · 仅玻璃态下显示 */}
{/* 移动端:单独一行 nav links · 顶部分割线只在玻璃态显示 */}
); }