fix: optimize history animation (#5973)

- adjust timing
- make sure card do not show the bottom border on transitioning

<div class='graphite__hidden'>
          <div>🎥 Video uploaded on Graphite:</div>
            <a href="https://app.graphite.dev/media/video/T2klNLEk0wxLh4NRDzhk/7a225ec1-eb33-45ab-bf27-646bb2519a83.mp4">
              <img src="https://app.graphite.dev/api/v1/graphite/video/thumbnail/T2klNLEk0wxLh4NRDzhk/7a225ec1-eb33-45ab-bf27-646bb2519a83.mp4">
            </a>
          </div>
<video src="https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/T2klNLEk0wxLh4NRDzhk/7a225ec1-eb33-45ab-bf27-646bb2519a83.mp4">Kapture 2024-03-01 at 10.56.09.mp4</video>
This commit is contained in:
Peng Xiao
2024-03-01 06:08:08 +00:00
parent de939bb6f6
commit a1ea19fcb7
2 changed files with 43 additions and 41 deletions

View File

@@ -17,7 +17,6 @@ import type { DialogContentProps } from '@radix-ui/react-dialog';
import { Doc, type PageMode, Workspace } from '@toeverything/infra';
import { useService } from '@toeverything/infra/di';
import { atom, useAtom, useSetAtom } from 'jotai';
import { range } from 'lodash-es';
import {
Fragment,
type PropsWithChildren,
@@ -25,7 +24,6 @@ import {
useCallback,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import { encodeStateAsUpdate } from 'yjs';
@@ -116,7 +114,7 @@ const HistoryEditorPreview = ({
const content = useMemo(() => {
return (
<>
<div className={styles.previewContent}>
<div className={styles.previewHeader}>
<StyledEditorModeSwitch switchLeft={mode === 'page'}>
<PageSwitchItem
@@ -154,7 +152,7 @@ const HistoryEditorPreview = ({
<Loading size={24} />
</div>
)}
</>
</div>
);
}, [
mode,
@@ -165,23 +163,23 @@ const HistoryEditorPreview = ({
ts,
]);
const previewRef = useRef<HTMLDivElement | null>(null);
return (
<div className={styles.previewWrapper} ref={previewRef}>
{range(0, historyList.length).map(i => {
<div className={styles.previewWrapper}>
{historyList.map((item, i) => {
const historyIndex = historyList.findIndex(h => h.timestamp === ts);
const distance = i - historyIndex;
const flag =
distance === 0
? 'current'
: distance > 2
? '> 2'
: distance < 0
? '< 0'
: distance;
distance > 20
? '> 20'
: distance < -20
? '< -20'
: distance.toString();
return (
<div data-distance={flag} key={i} className={styles.previewContainer}>
<div
data-distance={flag}
key={item.id}
className={styles.previewContainer}
>
{historyIndex === i ? content : null}
</div>
);

View File

@@ -1,5 +1,7 @@
import { cssVar } from '@toeverything/theme';
import { createVar, globalStyle, style } from '@vanilla-extract/css';
import { range } from 'lodash-es';
const headerHeight = createVar('header-height');
const footerHeight = createVar('footer-height');
const historyListWidth = createVar('history-list-width');
@@ -35,51 +37,53 @@ export const previewWrapper = style({
width: `calc(100% - ${historyListWidth})`,
backgroundColor: cssVar('backgroundSecondaryColor'),
});
export const previewContainer = style({
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
position: 'absolute',
bottom: 0,
top: 0,
left: 40,
borderTopLeftRadius: 8,
borderTopRightRadius: 8,
borderRadius: 8,
overflow: 'hidden',
boxShadow: cssVar('shadow3'),
height: 'calc(100% - 40px)',
height: '200%',
width: `calc(100% - 80px)`,
backgroundColor: cssVar('backgroundPrimaryColor'),
transformOrigin: 'top center',
transition: 'all 0.5s ease-in-out',
transition: 'transform 0.3s 0.1s ease-in-out, opacity 0.3s ease-in-out',
selectors: {
'&[data-distance="> 2"]': {
transform: 'scale(0.60)',
...Object.fromEntries(
range(-20, 20).map(i => [
`&[data-distance="${i}"]`,
{
transform: `scale(${1 - 0.05 * i}) translateY(${-8 * i + 40}px)`,
opacity: [0, 1, 2].includes(i) ? 1 : 0,
zIndex: -i,
pointerEvents: i === 0 ? 'auto' : 'none',
},
])
),
'&[data-distance="> 20"]': {
transform: `scale(0) translateY(${-8 * 20 + 40}px)`,
opacity: 0,
zIndex: -3,
zIndex: -20,
pointerEvents: 'none',
},
'&[data-distance="2"]': {
transform: 'scale(0.90) translateY(-16px)',
zIndex: -2,
pointerEvents: 'none',
},
'&[data-distance="1"]': {
transform: 'scale(0.95) translateY(-8px)',
zIndex: -1,
pointerEvents: 'none',
},
'&[data-distance="current"]': {
opacity: 1,
zIndex: 0,
},
'&[data-distance="< 0"]': {
transform: 'scale(1.60) translateY(18px)',
'&[data-distance="< -20"]': {
transform: `scale(2) translateY(${-8 * -20 + 40}px)`,
opacity: 0,
zIndex: 1,
zIndex: 20,
pointerEvents: 'none',
},
},
});
export const previewContent = style({
height: '50%',
});
export const previewHeader = style({
display: 'flex',
alignItems: 'center',