Skip to content

Commit

Permalink
Merge pull request #459 from audioverse-org/av-467
Browse files Browse the repository at this point in the history
Make mobile scroll transitions much smoother
  • Loading branch information
jlaverde77 authored Sep 13, 2023
2 parents 693d6d9 + edda727 commit 3b0eef9
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 94 deletions.
10 changes: 0 additions & 10 deletions .vscode/settings.json

This file was deleted.

14 changes: 14 additions & 0 deletions src/components/organisms/mobileHeader.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@
align-items: center;
justify-content: space-between;
z-index: 1;
padding-top: 24px;
padding-bottom: 14px;
transition: $transition-quick padding-top, $transition-quick padding-bottom;

> :first-child {
margin-right: 16px;
}
}

.down .title {
padding-top: 16px;
padding-bottom: 8px;
}

.subnav {
display: flex;
align-items: flex-end;
Expand All @@ -39,6 +47,12 @@
position: relative;
overflow: hidden;
background: $ts-cream;
height: 24px;
transition: $transition-quick height;
}

.down .subnav {
height: 0;
}

.subnavItems {
Expand Down
41 changes: 12 additions & 29 deletions src/components/organisms/mobileHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,11 @@ import IconExitSmall from '~public/img/icons/icon-exit-small.svg';
import MoreIcon from '~public/img/icons/icon-more.svg';

import styles from './mobileHeader.module.scss';
import { useTransitionProgress } from './mobileHeader.useTransitionProgress';
import useScrollDirection, {
SCROLL_DIRECTIONS,
} from './mobileHeader.useScrollDirection';
import { EntityFilterId } from './searchResults.filters';

type Transition = [number, number];

const SUBNAV_HEIGHT: Transition = [24, 0];
const TITLE_PAD_TOP: Transition = [24, 16];
const TITLE_PAD_BOTTOM: Transition = [14, 8];

const COLLAPSING_HEIGHT = [
SUBNAV_HEIGHT,
TITLE_PAD_TOP,
TITLE_PAD_BOTTOM,
].reduce((acc, [s, e]) => acc + (s - e), 0);

const px = (progress: number, [s, e]: Transition) =>
`${s + (e - s) * progress}px`;

export default function MobileHeader({
setShowingMenu,
scrollRef,
Expand All @@ -53,18 +40,17 @@ export default function MobileHeader({
const lang = useLanguageRoute();
const navItems = useNavigationItems();
const { getRecording } = useContext(PlaybackContext);
const progress = useTransitionProgress(scrollRef, COLLAPSING_HEIGHT);
const scrollDirection = useScrollDirection(scrollRef);

return (
<div className={styles.base}>
<div
className={clsx(styles.base, {
[styles.up]: scrollDirection === SCROLL_DIRECTIONS.UP,
[styles.down]: scrollDirection === SCROLL_DIRECTIONS.DOWN,
})}
>
<div className={styles.wrapper}>
<div
className={styles.title}
style={{
paddingTop: px(progress, TITLE_PAD_TOP),
paddingBottom: px(progress, TITLE_PAD_BOTTOM),
}}
>
<div className={styles.title}>
<Header />
<Button
type="super"
Expand All @@ -78,10 +64,7 @@ export default function MobileHeader({
/>
{getRecording() && <ButtonPlayback />}
</div>
<div
className={styles.subnav}
style={{ height: px(progress, SUBNAV_HEIGHT) }}
>
<div className={styles.subnav}>
<Mininav
items={navItems.slice(0, -2).map((item) => {
if (!item.href) {
Expand Down
37 changes: 37 additions & 0 deletions src/components/organisms/mobileHeader.useScrollDirection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect, useState } from 'react';

import useScrollTop from '~src/lib/hooks/useScrollTop';

export const SCROLL_DIRECTIONS = {
UP: 'up',
DOWN: 'down',
};

export default function useScrollDirection(
scrollRef: React.RefObject<HTMLDivElement>
) {
const scrollTop = useScrollTop(scrollRef);
const [lastScrollTop, setLastScrollTop] = useState<number>(0);
const [direction, setDirection] = useState<string>(SCROLL_DIRECTIONS.UP);

useEffect(() => {
setLastScrollTop(Math.max(scrollTop, 0));
}, [scrollTop]);

useEffect(() => {
const scrollHeight = scrollRef.current?.scrollHeight || 0;
const clientHeight = scrollRef.current?.clientHeight || 0;
const clientTop = scrollHeight - scrollTop;
const buffer = clientTop - clientHeight;
const maxHeaderHeight = 101;
if (buffer < maxHeaderHeight) return;
if (scrollTop > lastScrollTop) {
setDirection(SCROLL_DIRECTIONS.DOWN);
}
if (scrollTop < lastScrollTop) {
setDirection(SCROLL_DIRECTIONS.UP);
}
}, [scrollTop, lastScrollTop, scrollRef]);

return direction;
}
55 changes: 0 additions & 55 deletions src/components/organisms/mobileHeader.useTransitionProgress.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/lib/hooks/useScrollTop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useCallback, useEffect, useState } from 'react';

import isServerSide from '../isServerSide';

export default function useScrollTop(
scrollRef: React.RefObject<HTMLDivElement>
) {
const [scrollTop, setScrollTop] = useState<number>(0);

const listener = useCallback(() => {
if (isServerSide() || !scrollRef.current) return;
setScrollTop(scrollRef.current.scrollTop);
}, [scrollRef]);

useEffect(() => {
if (isServerSide() || !scrollRef.current) return;
const el = scrollRef.current;
el.addEventListener('scroll', listener);
return () => el.removeEventListener('scroll', listener);
}, [listener, scrollRef]);

return scrollTop;
}

1 comment on commit 3b0eef9

@vercel
Copy link

@vercel vercel bot commented on 3b0eef9 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.