diff --git a/src/app/page.tsx b/src/app/page.tsx index 32d7377..7c2950b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -11,6 +11,7 @@ import { getActivityEndTime, sortArtists, type SortKey } from "@/lib/mock-data"; import { useVoteStore } from "@/lib/store"; import { useVoteAction } from "@/hooks/useVoteAction"; import { useScrollRestore } from "@/hooks/useScrollRestore"; +import { useUIStore } from "@/lib/ui-store"; import { cn } from "@/lib/cn"; import { tosUrl } from "@/lib/tos"; @@ -23,6 +24,7 @@ export default function Home() { const [sortKey, setSortKey] = useState("votes"); const [filterStuck, setFilterStuck] = useState(false); const filterSentinelRef = useRef(null); + const setStoreFilterStuck = useUIStore((s) => s.setFilterStuck); const endTime = useMemo(() => getActivityEndTime(), []); @@ -66,6 +68,13 @@ export default function Home() { }; }, []); + // 把 filterStuck 同步到全局 UI store —— 让导航栏感知,在吸顶时关掉自己的玻璃, + // 让筛选条延伸出的"共享玻璃带"成为唯一的 backdrop-filter,消除接缝 + useEffect(() => { + setStoreFilterStuck(filterStuck); + return () => setStoreFilterStuck(false); + }, [filterStuck, setStoreFilterStuck]); + return ( <> {/* Hero · 全屏沉浸式视频 · 作为第一个 snap 点 @@ -119,16 +128,25 @@ export default function Home() { {/* 哨兵:用于检测筛选条是否吸顶 */}
- {/* 筛选条 · 外层铺满(与导航栏同宽),吸顶后启用毛玻璃;内层版心承载文案 */} + {/* 筛选条 · 外层铺满,内层版心承载文案。 + 吸顶时,absolute 子层把玻璃从 -top-20 一路扩到容器底部 —— + 这是一个单一元素的 backdrop-filter,横跨 nav 区域 + filter 区域, + 消除两块独立玻璃在 y=80 接缝处的视觉割裂。导航栏同步关掉自己的玻璃。 */}
-
+ {/* 共享玻璃带:absolute,吸顶时延伸到 nav 顶部,opacity 平滑过渡 */} +
+
s.filterStuck); + const glassOff = isTransparent || filterStuck; // 维护一个站内导航计数器(per-tab),供 FloatingBackButton 判断 router.back() 是否安全 useEffect(() => { @@ -57,12 +62,15 @@ export default function Navigation() { return (
- {/* 玻璃层 · 通过 opacity 渐显渐隐 · bg-surface 与全站卡片同色 */} + {/* 玻璃层 · 通过 opacity 渐显渐隐 · bg-surface 与全站卡片同色 + glassOff = isTransparent || filterStuck: + - isTransparent: Hero / 页顶,本来就要透明 + - filterStuck: 筛选条已伸出共享玻璃,nav 关掉自己的玻璃避免接缝 */}
{/* 顶部 1px 高光 · 仅玻璃态下显示 */} @@ -70,7 +78,7 @@ export default function Navigation() { aria-hidden className={cn( "absolute inset-x-0 top-0 h-px bg-white/[0.06] transition-opacity duration-300", - isTransparent ? "opacity-0" : "opacity-100", + glassOff ? "opacity-0" : "opacity-100", )} />