47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
|
import { STOREFRONT_STICKY_SCROLL_Y } from '@/layout/Header';
|
|
|
|
/**
|
|
* Reserves vertical space when Header (+ Navbar on xl) become fixed on scroll,
|
|
* so page content does not jump underneath.
|
|
*/
|
|
export function StickyHeaderSpacer() {
|
|
const [height, setHeight] = useState(0);
|
|
const [isFixed, setIsFixed] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const onScroll = () => {
|
|
setIsFixed(window.scrollY > STOREFRONT_STICKY_SCROLL_Y);
|
|
};
|
|
onScroll();
|
|
window.addEventListener('scroll', onScroll, { passive: true });
|
|
return () => window.removeEventListener('scroll', onScroll);
|
|
}, []);
|
|
|
|
useLayoutEffect(() => {
|
|
const measure = () => {
|
|
if (!isFixed) {
|
|
setHeight(0);
|
|
return;
|
|
}
|
|
const header = document.querySelector<HTMLElement>(
|
|
'[data-storefront-header]'
|
|
);
|
|
const nav = document.querySelector<HTMLElement>('[data-storefront-nav]');
|
|
const headerH = header?.offsetHeight || 0;
|
|
const navVisible =
|
|
!!nav && window.getComputedStyle(nav).display !== 'none';
|
|
const navH = navVisible ? nav.offsetHeight || 0 : 0;
|
|
setHeight(headerH + navH);
|
|
};
|
|
|
|
measure();
|
|
window.addEventListener('resize', measure, { passive: true });
|
|
return () => window.removeEventListener('resize', measure);
|
|
}, [isFixed]);
|
|
|
|
if (!isFixed || height <= 0) return null;
|
|
return <div style={{ height }} aria-hidden="true" />;
|
|
}
|