feat(mobile): sticky journal date-picker, auto fold when scroll (#8885)

This commit is contained in:
CatsJuice 2024-11-22 10:06:42 +00:00
parent ad10690043
commit 5994814db8
No known key found for this signature in database
GPG Key ID: 1C1E76924FAFDDE4
5 changed files with 62 additions and 7 deletions

View File

@ -6,6 +6,7 @@ export const MONTH_VIEW_HEIGHT =
TOTAL_WEEKS * CELL_HEIGHT + (TOTAL_WEEKS - 1) * ROWS_GAP;
export const WEEK_VIEW_HEIGHT = CELL_HEIGHT;
export const HORIZONTAL_SWIPE_THRESHOLD = 4 * CELL_HEIGHT;
export const HORIZONTAL_SWIPE_THRESHOLD = 2 * CELL_HEIGHT;
export const SCROLL_DOWN_TO_FOLD_THRESHOLD = 30;
export const DATE_FORMAT = 'YYYY-MM-DD';

View File

@ -1,9 +1,10 @@
import { useCallback, useEffect, useState } from 'react';
import { type HTMLAttributes, useCallback, useEffect, useState } from 'react';
import { JournalDatePickerContext } from './context';
import { ResizeViewport } from './viewport';
export interface JournalDatePickerProps {
export interface JournalDatePickerProps
extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
date: string;
onChange: (date: string) => void;
withDotDates: Set<string | null | undefined>;
@ -12,6 +13,7 @@ export const JournalDatePicker = ({
date: selected,
onChange,
withDotDates,
...attrs
}: JournalDatePickerProps) => {
const [cursor, setCursor] = useState(selected);
@ -39,7 +41,7 @@ export const JournalDatePicker = ({
withDotDates,
}}
>
<ResizeViewport></ResizeViewport>
<ResizeViewport {...attrs} />
</JournalDatePickerContext.Provider>
);
};

View File

@ -1,11 +1,21 @@
import { useGlobalEvent } from '@affine/core/mobile/hooks/use-global-events';
import anime from 'animejs';
import clsx from 'clsx';
import dayjs from 'dayjs';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import {
type HTMLAttributes,
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
import {
CELL_HEIGHT,
DATE_FORMAT,
MONTH_VIEW_HEIGHT,
SCROLL_DOWN_TO_FOLD_THRESHOLD,
WEEK_VIEW_HEIGHT,
} from './constants';
import { JournalDatePickerContext } from './context';
@ -14,7 +24,10 @@ import { SwipeHelper } from './swipe-helper';
import * as styles from './viewport.css';
import { WeekHeader, WeekRowSwipe } from './week';
export const ResizeViewport = () => {
export const ResizeViewport = ({
className,
...attrs
}: HTMLAttributes<HTMLDivElement>) => {
const { selected } = useContext(JournalDatePickerContext);
const draggableRef = useRef<HTMLDivElement>(null);
const viewportRef = useRef<HTMLDivElement>(null);
@ -97,8 +110,29 @@ export const ResizeViewport = () => {
});
}, [handleToggleModeWithAnimation, mode]);
// auto fold when scroll down
const prevScrollYRef = useRef(window.scrollY);
useGlobalEvent(
'scroll',
useCallback(() => {
if (mode === 'week') return;
if (isAnimating) return;
const offset = window.scrollY - prevScrollYRef.current;
if (offset >= SCROLL_DOWN_TO_FOLD_THRESHOLD) {
prevScrollYRef.current = window.scrollY;
handleToggleModeWithAnimation('week', 0);
}
}, [handleToggleModeWithAnimation, isAnimating, mode])
);
useGlobalEvent(
'scrollend',
useCallback(() => {
prevScrollYRef.current = window.scrollY;
}, [])
);
return (
<div className={styles.root}>
<div className={clsx(styles.root, className)} {...attrs}>
<WeekHeader className={styles.weekRow} />
<div ref={viewportRef} style={{ height: draggedHeight }}>
{mode === 'month' || isDragging || isAnimating ? (

View File

@ -93,3 +93,15 @@ export const journalIconButton = style({
right: 12,
display: 'flex',
});
export const journalDatePickerSticky = style({
background: cssVarV2('layer/background/primary'),
position: 'sticky',
zIndex: 1,
top: 56,
selectors: {
'&[data-standalone]': {
top: 'calc(44px + env(safe-area-inset-top, 12px))',
},
},
});

View File

@ -262,6 +262,12 @@ const MobileDetailPage = ({
date={date}
onChange={handleDateChange}
withDotDates={allJournalDates}
className={styles.journalDatePickerSticky}
data-standalone={
environment.isPwa || BUILD_CONFIG.isAndroid || BUILD_CONFIG.isIOS
? ''
: undefined
}
/>
) : null}
<DetailPageImpl />