Updated sticky header logic.

This commit is contained in:
Mike Cao 2023-02-09 08:22:36 -08:00
parent 45c13da262
commit f062cdbed2
8 changed files with 31 additions and 24 deletions

View File

@ -1,15 +1,21 @@
import { useEffect, useRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import useSticky from 'hooks/useSticky'; import useSticky from 'hooks/useSticky';
export default function StickyHeader({ className, stickyClassName, stickyStyle, children }) { export default function StickyHeader({ className, stickyClassName, stickyStyle, children }) {
const { ref, isSticky } = useSticky(); const { ref, isSticky } = useSticky();
const initialWidth = useRef(0);
useEffect(() => {
initialWidth.current = ref.current.clientWidth;
}, [ref]);
return ( return (
<div <div
ref={ref} ref={ref}
data-sticky={isSticky} data-sticky={isSticky}
className={classNames(className, { [stickyClassName]: isSticky })} className={classNames(className, { [stickyClassName]: isSticky })}
style={isSticky ? { ...stickyStyle, width: ref?.current?.clientWidth } : null} style={isSticky ? { ...stickyStyle, width: initialWidth.current } : null}
> >
{children} {children}
</div> </div>

View File

@ -19,7 +19,7 @@ export default function AppLayout({ title, children }) {
<div className={styles.nav}> <div className={styles.nav}>
<NavBar /> <NavBar />
</div> </div>
<div className={styles.body}> <div className={styles.body} id="layout-body">
<Container> <Container>
<main>{children}</main> <main>{children}</main>
</Container> </Container>

View File

@ -6,11 +6,10 @@
.nav { .nav {
grid-row: 1 / 3; grid-row: 1 / 3;
height: 100vh;
position: fixed;
} }
.body { .body {
grid-area: 1 / 2; grid-area: 1 / 2;
overflow: auto; overflow: auto;
height: 100vh;
} }

View File

@ -2,21 +2,25 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
min-height: 90px;
min-width: 140px; min-width: 140px;
} }
.value { .value {
min-height: 36px; display: flex;
align-items: center;
font-size: 36px; font-size: 36px;
font-weight: 700; font-weight: 700;
white-space: nowrap; white-space: nowrap;
min-height: 60px;
} }
.label { .label {
white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
white-space: nowrap;
min-height: 30px;
} }
.change { .change {

View File

@ -2,10 +2,7 @@
display: flex; display: flex;
cursor: pointer; cursor: pointer;
min-height: 80px; min-height: 80px;
} gap: 20px;
.bar > div + div {
padding-left: 20px;
} }
@media only screen and (max-width: 992px) { @media only screen and (max-width: 992px) {

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { Button, Icon, Text, Row, Column, Loading } from 'react-basics'; import { Button, Icon, Text, Row, Column, Container } from 'react-basics';
import Link from 'next/link'; import Link from 'next/link';
import PageviewsChart from './PageviewsChart'; import PageviewsChart from './PageviewsChart';
import MetricsBar from './MetricsBar'; import MetricsBar from './MetricsBar';

View File

@ -18,6 +18,7 @@
.header { .header {
min-height: 90px; min-height: 90px;
margin-bottom: 20px;
} }
.metrics { .metrics {
@ -25,16 +26,15 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 10px 0;
} }
.sticky { .sticky {
position: fixed; position: fixed;
top: 0; top: 0;
margin: auto;
background: var(--base50); background: var(--base50);
border-bottom: 1px solid var(--base300); border-bottom: 1px solid var(--base300);
z-index: 3; z-index: 3;
width: inherit;
} }
.filter { .filter {

View File

@ -1,27 +1,28 @@
import { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef } from 'react';
export default function useSticky(defaultSticky = false) { export default function useSticky(
element = document.getElementById('layout-body'),
defaultSticky = false,
) {
const [isSticky, setIsSticky] = useState(defaultSticky); const [isSticky, setIsSticky] = useState(defaultSticky);
const ref = useRef(null); const ref = useRef(null);
const initialTop = useRef(0); const initialTop = useRef(null);
useEffect(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
if (window.pageYOffset > initialTop.current) { setIsSticky(element.scrollTop > initialTop.current);
setIsSticky(true);
} else {
setIsSticky(false);
}
}; };
if (initialTop.current === null) {
initialTop.current = ref.current.offsetTop; initialTop.current = ref.current.offsetTop;
}
window.addEventListener('scroll', handleScroll); element.addEventListener('scroll', handleScroll);
return () => { return () => {
window.removeEventListener('scroll', handleScroll); element.removeEventListener('scroll', handleScroll);
}; };
}, []); }, [setIsSticky]);
return { ref, isSticky }; return { ref, isSticky };
} }