mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
feat: add animation to mode switch when hover (#1489)
Co-authored-by: Yifeng Wang <doodlewind@toeverything.info> Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-is": "^18.2.0",
|
||||
"react-lottie": "^1.2.3",
|
||||
"swr": "^2.0.4",
|
||||
"y-indexeddb": "^9.0.9",
|
||||
"y-protocols": "^1.0.5",
|
||||
@@ -47,6 +48,7 @@
|
||||
"@swc-jotai/react-refresh": "^0.0.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-lottie": "^1.2.6",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.35.0",
|
||||
|
||||
@@ -22,6 +22,9 @@ import { useWorkspacesHelper } from '../../hooks/use-workspaces';
|
||||
import { ThemeProvider } from '../../providers/ThemeProvider';
|
||||
import { pathGenerator, RemWorkspaceFlavour } from '../../shared';
|
||||
import { WorkSpaceSliderBar } from '../pure/workspace-slider-bar';
|
||||
vi.mock('react-lottie', () => ({
|
||||
default: (props: React.PropsWithChildren) => <>{props.children}</>,
|
||||
}));
|
||||
|
||||
const fetchMocker = createFetchMock(vi);
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,4 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { EdgelessIcon, PaperIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { CSSProperties } from 'react';
|
||||
|
||||
@@ -8,7 +7,8 @@ import {
|
||||
usePageMetaHelper,
|
||||
} from '../../../../hooks/use-page-meta';
|
||||
import { BlockSuiteWorkspace } from '../../../../shared';
|
||||
import { StyledEditorModeSwitch, StyledSwitchItem } from './style';
|
||||
import { StyledEditorModeSwitch } from './style';
|
||||
import { EdgelessSwitchItem, PageSwitchItem } from './switch-items';
|
||||
|
||||
export type EditorModeSwitchProps = {
|
||||
// todo(himself65): combine these two properties
|
||||
@@ -35,7 +35,7 @@ export const EditorModeSwitch = ({
|
||||
switchLeft={mode === 'page'}
|
||||
showAlone={trash}
|
||||
>
|
||||
<StyledSwitchItem
|
||||
<PageSwitchItem
|
||||
data-testid="switch-page-mode-button"
|
||||
active={mode === 'page'}
|
||||
hide={trash && mode !== 'page'}
|
||||
@@ -43,10 +43,8 @@ export const EditorModeSwitch = ({
|
||||
setPageMeta(pageId, { mode: 'page' });
|
||||
toast('Page mode');
|
||||
}}
|
||||
>
|
||||
<PaperIcon />
|
||||
</StyledSwitchItem>
|
||||
<StyledSwitchItem
|
||||
/>
|
||||
<EdgelessSwitchItem
|
||||
data-testid="switch-edgeless-mode-button"
|
||||
active={mode === 'edgeless'}
|
||||
hide={trash && mode !== 'edgeless'}
|
||||
@@ -54,9 +52,7 @@ export const EditorModeSwitch = ({
|
||||
setPageMeta(pageId, { mode: 'edgeless' });
|
||||
toast('Edgeless mode');
|
||||
}}
|
||||
>
|
||||
<EdgelessIcon />
|
||||
</StyledSwitchItem>
|
||||
/>
|
||||
</StyledEditorModeSwitch>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -40,9 +40,9 @@ export const StyledEditorModeSwitch = styled('div')<{
|
||||
});
|
||||
|
||||
export const StyledSwitchItem = styled('button')<{
|
||||
active: boolean;
|
||||
active?: boolean;
|
||||
hide?: boolean;
|
||||
}>(({ theme, active, hide = false }) => {
|
||||
}>(({ theme, active = false, hide = false }) => {
|
||||
return {
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
@@ -54,5 +54,8 @@ export const StyledSwitchItem = styled('button')<{
|
||||
position: 'relative',
|
||||
zIndex: 2,
|
||||
fontSize: '20px',
|
||||
path: {
|
||||
fill: 'currentColor',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import React, { cloneElement, HTMLAttributes, useState } from 'react';
|
||||
import Lottie from 'react-lottie';
|
||||
|
||||
import * as edgelessHoverAnimationData from './animation-data/edgeless-hover.json';
|
||||
import * as pageHoverAnimationData from './animation-data/page-hover.json';
|
||||
import { StyledSwitchItem } from './style';
|
||||
|
||||
type HoverAnimateControllerProps = {
|
||||
active?: boolean;
|
||||
hide?: boolean;
|
||||
children: React.ReactElement;
|
||||
} & HTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const HoverAnimateController = ({
|
||||
active,
|
||||
hide,
|
||||
children,
|
||||
...props
|
||||
}: HoverAnimateControllerProps) => {
|
||||
const [startAnimate, setStartAnimate] = useState(false);
|
||||
return (
|
||||
<StyledSwitchItem
|
||||
hide={hide}
|
||||
active={active}
|
||||
onMouseEnter={() => {
|
||||
setStartAnimate(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setStartAnimate(false);
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{cloneElement(children, {
|
||||
isStopped: !startAnimate,
|
||||
speed: 5,
|
||||
width: 20,
|
||||
height: 20,
|
||||
})}
|
||||
</StyledSwitchItem>
|
||||
);
|
||||
};
|
||||
|
||||
export const PageSwitchItem = (
|
||||
props: Omit<HoverAnimateControllerProps, 'children'>
|
||||
) => {
|
||||
return (
|
||||
<HoverAnimateController {...props}>
|
||||
<Lottie
|
||||
options={{
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: pageHoverAnimationData,
|
||||
rendererSettings: {
|
||||
preserveAspectRatio: 'xMidYMid slice',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</HoverAnimateController>
|
||||
);
|
||||
};
|
||||
|
||||
export const EdgelessSwitchItem = (
|
||||
props: Omit<HoverAnimateControllerProps, 'children'>
|
||||
) => {
|
||||
return (
|
||||
<HoverAnimateController {...props}>
|
||||
<Lottie
|
||||
options={{
|
||||
loop: false,
|
||||
autoplay: false,
|
||||
animationData: edgelessHoverAnimationData,
|
||||
rendererSettings: {
|
||||
preserveAspectRatio: 'xMidYMid slice',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</HoverAnimateController>
|
||||
);
|
||||
};
|
||||
@@ -42,6 +42,9 @@ import {
|
||||
useSyncRouterWithCurrentWorkspaceAndPage,
|
||||
} from '../use-sync-router-with-current-workspace-and-page';
|
||||
import { useWorkspaces, useWorkspacesHelper } from '../use-workspaces';
|
||||
vi.mock('react-lottie', () => ({
|
||||
default: (props: React.PropsWithChildren) => <>{props.children}</>,
|
||||
}));
|
||||
|
||||
let blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
beforeAll(() => {
|
||||
|
||||
Reference in New Issue
Block a user