mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-12 07:36:42 +08: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);
|
||||
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
+1
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(() => {
|
||||
|
||||
Generated
+43
-1
@@ -154,6 +154,7 @@ importers:
|
||||
'@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
|
||||
cmdk: ^0.1.22
|
||||
css-spring: ^4.1.0
|
||||
@@ -172,6 +173,7 @@ importers:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-is: ^18.2.0
|
||||
react-lottie: ^1.2.3
|
||||
redux: ^4.2.1
|
||||
swc-plugin-coverage-instrument: ^0.0.14
|
||||
swr: ^2.0.4
|
||||
@@ -207,6 +209,7 @@ importers:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-is: 18.2.0
|
||||
react-lottie: 1.2.3_react@18.2.0
|
||||
swr: 2.0.4_react@18.2.0
|
||||
y-indexeddb: 9.0.9_yjs@13.5.48
|
||||
y-protocols: 1.0.5
|
||||
@@ -219,6 +222,7 @@ importers:
|
||||
'@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
|
||||
@@ -5171,6 +5175,12 @@ packages:
|
||||
'@types/react': 18.0.28
|
||||
dev: false
|
||||
|
||||
/@types/react-lottie/1.2.6:
|
||||
resolution: {integrity: sha512-fvGJHD7SeUdVESHo7f7erRnXkTWaa/6Mo5TB+R0/ieSftKoFspA4sMlF2qMH6BljXI7ehFJbBtrD5bzDxPCkGg==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.28
|
||||
dev: true
|
||||
|
||||
/@types/react-transition-group/4.4.5:
|
||||
resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
|
||||
dependencies:
|
||||
@@ -5364,7 +5374,7 @@ packages:
|
||||
'@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.21.0
|
||||
magic-string: 0.27.0
|
||||
react-refresh: 0.14.0
|
||||
vite: 4.1.4
|
||||
vite: 4.1.4_@types+node@18.14.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -6004,6 +6014,13 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/babel-runtime/6.26.0:
|
||||
resolution: {integrity: sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==}
|
||||
dependencies:
|
||||
core-js: 2.6.12
|
||||
regenerator-runtime: 0.11.1
|
||||
dev: false
|
||||
|
||||
/balanced-match/1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
@@ -6569,6 +6586,12 @@ packages:
|
||||
browserslist: 4.21.5
|
||||
dev: true
|
||||
|
||||
/core-js/2.6.12:
|
||||
resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==}
|
||||
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/core-util-is/1.0.3:
|
||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
|
||||
@@ -9590,6 +9613,10 @@ packages:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
|
||||
/lottie-web/5.10.2:
|
||||
resolution: {integrity: sha512-d0PFIGiwuMsJYaF4uPo+qG8dEorlI+xFI2zrrFtE1bGO4WoLIz+NjremxEq1swpR7juR10aeOtmNh3d6G3ub0A==}
|
||||
dev: false
|
||||
|
||||
/loupe/2.3.6:
|
||||
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
|
||||
dependencies:
|
||||
@@ -10960,6 +10987,17 @@ packages:
|
||||
/react-is/18.2.0:
|
||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||
|
||||
/react-lottie/1.2.3_react@18.2.0:
|
||||
resolution: {integrity: sha512-qLCERxUr8M+4mm1LU0Ruxw5Y5Fn/OmYkGfnA+JDM/dZb3oKwVAJCjwnjkj9TMHtzR2U6sMEUD3ZZ1RaHagM7kA==}
|
||||
engines: {npm: ^3.0.0}
|
||||
peerDependencies:
|
||||
react: ^0.14.7 || ^15.0.0 || ^16.0.0
|
||||
dependencies:
|
||||
babel-runtime: 6.26.0
|
||||
lottie-web: 5.10.2
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-refresh/0.14.0:
|
||||
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -11150,6 +11188,10 @@ packages:
|
||||
resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
|
||||
dev: true
|
||||
|
||||
/regenerator-runtime/0.11.1:
|
||||
resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==}
|
||||
dev: false
|
||||
|
||||
/regenerator-runtime/0.13.11:
|
||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user