ui fixes
This commit is contained in:
@@ -14,11 +14,16 @@
|
||||
* hidden and replaced with a "← Back to search results" button. This
|
||||
* keeps the cross-page-navigation polish that the search page relies on.
|
||||
*
|
||||
* Sticky headers collapse on scroll-down and re-appear on scroll-up
|
||||
* (mobile-address-bar pattern). Long reading pages get back the vertical
|
||||
* real estate without losing the title anchor on demand. Only applies
|
||||
* when `sticky` — a non-sticky header has nothing to slide behind.
|
||||
*
|
||||
* Pages that don't want a sub-header (e.g. the redesigned homepage which
|
||||
* paints its own editorial hero) can simply not render PageHeader.
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -63,12 +68,39 @@ export function PageHeader({
|
||||
return false;
|
||||
});
|
||||
|
||||
// Scroll-direction-driven collapse. Hidden when the user is scrolling
|
||||
// down past the first viewport-tenth and revealed again as soon as
|
||||
// they scroll up. Near the top we always show so quick reading doesn't
|
||||
// feel jumpy. Only wired up when `sticky` — that's the only case where
|
||||
// the header has a fixed slot to slide behind.
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const lastScrollYRef = useRef(0);
|
||||
useEffect(() => {
|
||||
if (!sticky) return;
|
||||
lastScrollYRef.current = window.scrollY;
|
||||
function onScroll() {
|
||||
const y = window.scrollY;
|
||||
const delta = y - lastScrollYRef.current;
|
||||
// Threshold of ~8px filters out scroll-jitter / momentum noise.
|
||||
if (y < 80) setCollapsed(false);
|
||||
else if (delta > 8) setCollapsed(true);
|
||||
else if (delta < -8) setCollapsed(false);
|
||||
lastScrollYRef.current = y;
|
||||
}
|
||||
window.addEventListener("scroll", onScroll, { passive: true });
|
||||
return () => window.removeEventListener("scroll", onScroll);
|
||||
}, [sticky]);
|
||||
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
"px-4 sm:px-6",
|
||||
bare ? "py-6" : "border-b border-border bg-card/85 backdrop-blur py-5",
|
||||
sticky && "sticky top-12 sm:top-14 z-20",
|
||||
sticky &&
|
||||
"sticky top-12 sm:top-14 z-20 transition-transform duration-200 ease-out",
|
||||
// -translate-y-full tucks the band fully behind the SiteHeader
|
||||
// (which sits at a higher z-index), so it visually disappears.
|
||||
sticky && collapsed && "-translate-y-full",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user