This commit is contained in:
gosangam
2026-05-31 06:50:05 +05:30
parent 0ae3334d98
commit 0ff8005df2
9 changed files with 253 additions and 102 deletions
+34 -2
View File
@@ -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,
)}
>