Refactor sticky nav hook/components
This commit is contained in:
parent
c959e88ebb
commit
ffde3cedaf
@ -36,9 +36,8 @@ export default function Nav({
|
|||||||
const showNav = !isPathSignIn(pathname);
|
const showNav = !isPathSignIn(pathname);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isNavSticky,
|
classNameStickyContainer,
|
||||||
shouldHideStickyNav,
|
classNameStickyNav,
|
||||||
shouldAnimateStickyNav,
|
|
||||||
} = useStickyNav(ref);
|
} = useStickyNav(ref);
|
||||||
|
|
||||||
const renderLink = (
|
const renderLink = (
|
||||||
@ -63,9 +62,7 @@ export default function Nav({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AppGrid
|
<AppGrid
|
||||||
className={clsx(
|
className={classNameStickyContainer}
|
||||||
isNavSticky && 'sticky top-0 z-10 pointer-events-none',
|
|
||||||
)}
|
|
||||||
classNameMain='pointer-events-auto'
|
classNameMain='pointer-events-auto'
|
||||||
contentMain={
|
contentMain={
|
||||||
<AnimateItems
|
<AnimateItems
|
||||||
@ -77,15 +74,11 @@ export default function Nav({
|
|||||||
key="nav"
|
key="nav"
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-full',
|
'w-full flex items-center bg-main',
|
||||||
|
NAV_HEIGHT_CLASS,
|
||||||
// Enlarge nav to ensure it fully masks underlying content
|
// Enlarge nav to ensure it fully masks underlying content
|
||||||
'md:w-[calc(100%+8px)] md:translate-x-[-4px] md:px-[4px]',
|
'md:w-[calc(100%+8px)] md:translate-x-[-4px] md:px-[4px]',
|
||||||
'flex items-center bg-main',
|
classNameStickyNav,
|
||||||
shouldAnimateStickyNav && 'transition-transform duration-200',
|
|
||||||
shouldHideStickyNav
|
|
||||||
? 'translate-y-[-100%]'
|
|
||||||
: 'translate-y-0',
|
|
||||||
NAV_HEIGHT_CLASS,
|
|
||||||
)}>
|
)}>
|
||||||
<ViewSwitcher
|
<ViewSwitcher
|
||||||
currentSelection={switcherSelectionForPath()}
|
currentSelection={switcherSelectionForPath()}
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import useScrollDirection from '@/utility/useScrollDirection';
|
import useScrollDirection from '@/utility/useScrollDirection';
|
||||||
import { RefObject } from 'react';
|
import clsx from 'clsx/lite';
|
||||||
|
import { RefObject, useMemo } from 'react';
|
||||||
|
|
||||||
export default function useStickyNav(
|
export default function useStickyNav(
|
||||||
ref: RefObject<HTMLElement | null>,
|
ref: RefObject<HTMLElement | null>,
|
||||||
isEnabled = true,
|
isEnabled = true,
|
||||||
) {
|
) {
|
||||||
const { scrollDirection, lastScrollY } = useScrollDirection();
|
const { scrollDirection, scrollY } = useScrollDirection();
|
||||||
|
|
||||||
const navHeight = ref.current?.clientHeight ?? 0;
|
const navHeight = ref.current?.clientHeight ?? 0;
|
||||||
|
|
||||||
const hasScrolledPastNav = lastScrollY > navHeight;
|
const hasScrolledPastNav = scrollY > navHeight;
|
||||||
|
|
||||||
const isNavSticky = isEnabled && (
|
const isNavSticky = isEnabled && (
|
||||||
hasScrolledPastNav ||
|
hasScrolledPastNav ||
|
||||||
@ -21,13 +22,20 @@ export default function useStickyNav(
|
|||||||
scrollDirection === 'down';
|
scrollDirection === 'down';
|
||||||
|
|
||||||
const shouldAnimateStickyNav =
|
const shouldAnimateStickyNav =
|
||||||
isNavSticky &&
|
isNavSticky && (
|
||||||
lastScrollY > navHeight * 2 ||
|
scrollY > navHeight * 2 ||
|
||||||
scrollDirection === 'up';
|
scrollDirection === 'up'
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
const classNames = useMemo(() => ({
|
||||||
isNavSticky,
|
classNameStickyContainer: clsx(
|
||||||
shouldHideStickyNav,
|
isNavSticky && 'sticky top-0 z-10 pointer-events-none',
|
||||||
shouldAnimateStickyNav,
|
),
|
||||||
};
|
classNameStickyNav: clsx(
|
||||||
|
shouldHideStickyNav ? 'translate-y-[-100%]' : 'translate-y-0',
|
||||||
|
shouldAnimateStickyNav && 'transition-transform duration-200',
|
||||||
|
),
|
||||||
|
}), [isNavSticky, shouldAnimateStickyNav, shouldHideStickyNav]);
|
||||||
|
|
||||||
|
return classNames;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,26 +1,28 @@
|
|||||||
import { useEffect, useState, useRef } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export default function useScrollDirection() {
|
export default function useScrollDirection() {
|
||||||
const [scrollDirection, setScrollDirection] = useState<'up' | 'down'>('down');
|
const [scrollInfo, setScrollInfo] = useState({
|
||||||
|
scrollDirection: 'down' as 'up' | 'down',
|
||||||
const lastScrollY = useRef(0);
|
scrollY: 0,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
const pageHeight =
|
const pageHeight = (
|
||||||
document.documentElement.scrollHeight - window.innerHeight;
|
document.documentElement.scrollHeight -
|
||||||
setScrollDirection((
|
window.innerHeight
|
||||||
window.scrollY >= lastScrollY.current ||
|
);
|
||||||
lastScrollY.current > pageHeight
|
setScrollInfo(prev => ({
|
||||||
) ? 'down' : 'up');
|
scrollDirection: (
|
||||||
lastScrollY.current = window.scrollY;
|
window.scrollY >= prev.scrollY ||
|
||||||
|
prev.scrollY > pageHeight
|
||||||
|
) ? 'down' : 'up',
|
||||||
|
scrollY: window.scrollY,
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
return () => window.removeEventListener('scroll', handleScroll);
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return scrollInfo;
|
||||||
scrollDirection,
|
|
||||||
lastScrollY: lastScrollY.current,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user