diff --git a/apps/web/package.json b/apps/web/package.json
index 69d058dcb..539ab70a9 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -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",
diff --git a/apps/web/src/components/__tests__/WorkSpaceSliderBar.spec.tsx b/apps/web/src/components/__tests__/WorkSpaceSliderBar.spec.tsx
index 77b7d0842..546b40e30 100644
--- a/apps/web/src/components/__tests__/WorkSpaceSliderBar.spec.tsx
+++ b/apps/web/src/components/__tests__/WorkSpaceSliderBar.spec.tsx
@@ -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);
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/edgeless-hover.json b/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/edgeless-hover.json
new file mode 100644
index 000000000..dcfd8643d
--- /dev/null
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/edgeless-hover.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":29.9700012207031,"ip":0,"op":60.0000024438501,"w":500,"h":500,"nm":"edgeless-hover","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 3/paper-edgeless-icons Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[183.5,183.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.604],[0,0],[-5.614,0],[0,0],[0,5.605],[0,0],[5.615,0]],"o":[[-5.614,0],[0,0],[0,5.605],[0,0],[5.615,0],[0,0],[0,-5.604],[0,0]],"v":[[-30.525,-40.7],[-40.699,-30.525],[-40.699,30.524],[-30.525,40.699],[30.525,40.699],[40.699,30.524],[40.699,-30.525],[30.525,-40.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[22.447,0],[0,0],[0,22.437],[0,0],[-22.446,0],[0,0],[0,-22.437],[0,0]],"o":[[0,0],[-22.446,0],[0,0],[0,-22.437],[0,0],[22.447,0],[0,0],[0,22.437]],"v":[[30.525,71.224],[-30.525,71.224],[-71.225,30.524],[-71.225,-30.525],[-30.525,-71.225],[30.525,-71.225],[71.224,-30.525],[71.224,30.524]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[295.322,295.323],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[315.322,315.323],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[295.322,295.323]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.426,0],[0,8.426],[0,0],[-8.426,0],[0,-8.426],[0,0]],"o":[[-8.426,0],[0,0],[0,-8.426],[8.426,0],[0,0],[0,8.426]],"v":[[0,30.525],[-15.262,15.263],[-15.262,-15.262],[0,-30.525],[15.262,-15.262],[15.262,15.263]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[76.561,183.399],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[56.561,183.399],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[76.561,183.399]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.426,0],[0,8.426],[5.395,13.057],[9.956,9.956],[13.037,5.406],[14.1,0],[0,8.426],[-8.426,0],[-16.753,-6.955],[-12.808,-12.818],[-6.955,-16.773],[0,-18.105]],"o":[[-8.426,0],[0,-14.09],[-5.416,-13.016],[-9.957,-9.956],[-13.026,-5.385],[-8.426,0],[0,-8.426],[18.134,0],[16.763,6.936],[12.788,12.778],[6.936,16.773],[0,8.426]],"v":[[61.049,76.312],[45.788,61.05],[37.66,20.151],[14.497,-14.487],[-20.161,-37.659],[-61.049,-45.787],[-76.311,-61.049],[-61.049,-76.312],[-8.475,-65.839],[36.09,-36.069],[65.858,8.486],[76.311,61.05]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[254.447,112.349],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[274.447,92.349],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[254.447,112.349]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.446,0],[0,-22.437],[-22.446,0],[0,22.436]],"o":[[-22.446,0],[0,22.436],[22.446,0],[0,-22.437]],"v":[[0,-40.7],[-40.7,0],[0,40.699],[40.7,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[39.269,0],[0,39.268],[-39.269,0],[0,-39.269]],"o":[[-39.269,0],[0,-39.269],[39.269,0],[0,39.268]],"v":[[0,71.224],[-71.224,0],[0,-71.225],[71.224,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[71.474,295.323],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[51.474,315.323],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[71.474,295.323]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.446,0],[0,-22.437],[-22.446,0],[0,22.436]],"o":[[-22.446,0],[0,22.436],[22.446,0],[0,-22.437]],"v":[[0,-40.7],[-40.7,0.001],[0,40.7],[40.7,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[39.269,0],[0,39.268],[-39.269,0],[0,-39.269]],"o":[[-39.269,0],[0,-39.269],[39.269,0],[0,39.268]],"v":[[0,71.225],[-71.224,0.001],[0,-71.225],[71.224,0.001]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[71.474,71.475],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[51.474,51.475],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[71.474,71.475]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/page-hover.json b/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/page-hover.json
new file mode 100644
index 000000000..0b870fa0c
--- /dev/null
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/animation-data/page-hover.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":29.9700012207031,"ip":0,"op":60.0000024438501,"w":500,"h":500,"nm":"page-hover","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 1/paper-edgeless-icons Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[183,183,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.557,0],[0,0],[0,8.639],[-8.64,0],[0,0],[-2.201,1.651],[0,9.536],[0,0],[-8.64,0],[0,-8.64],[0,0],[16.892,-16.892]],"o":[[0,0],[-8.64,0],[0,-8.64],[0,0],[17.442,0],[10.412,-10.453],[0,0],[0,-8.64],[8.639,0],[0,0],[0,18.155],[-9.027,8.987]],"v":[[46.947,182.579],[-109.545,182.579],[-125.194,166.93],[-109.545,151.281],[46.947,151.281],[78.001,145.086],[93.895,114.766],[93.895,-166.93],[109.545,-182.579],[125.194,-166.93],[125.194,114.766],[99.743,167.561]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[240.204,182.829],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[260.204,202.829],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[240.204,182.829]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.64,0],[0,8.639],[0,0],[-16.892,16.882],[-22.598,0],[0,0],[0,-8.64],[8.639,0],[0,0],[2.171,-1.65],[0,-9.546],[0,0]],"o":[[-8.64,0],[0,0],[0,-18.145],[8.976,-8.986],[0,0],[8.639,0],[0,8.64],[0,0],[-17.453,0],[-10.443,10.484],[0,0],[0,8.639]],"v":[[-109.545,182.579],[-125.194,166.93],[-125.194,-114.766],[-99.743,-167.562],[-46.948,-182.579],[109.545,-182.579],[125.194,-166.93],[109.545,-151.281],[-46.948,-151.281],[-77.972,-145.107],[-93.896,-114.766],[-93.896,166.93]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[125.443,182.829],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[105.443,162.829],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[125.443,182.829]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.64,0],[0,0],[0,8.639],[-8.64,0],[0,0],[0,-8.64]],"o":[[0,0],[-8.64,0],[0,-8.64],[0,0],[8.64,0],[0,8.639]],"v":[[67.813,15.649],[-67.813,15.649],[-83.463,0],[-67.813,-15.649],[67.813,-15.649],[83.462,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[182.824,271.513],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[212.824,281.513],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[182.824,271.513]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.757],[0,0],[-5.756,0],[0,0],[0,5.756],[0,0],[5.747,0]],"o":[[-5.756,0],[0,0],[0,5.756],[0,0],[5.747,0],[0,0],[0,-5.757],[0,0]],"v":[[-41.732,-31.294],[-52.165,-20.86],[-52.165,20.87],[-41.732,31.303],[41.73,31.303],[52.163,20.87],[52.163,-20.86],[41.73,-31.294]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[23.006,0],[0,0],[0,23.015],[0,0],[-23.015,0],[0,0],[0,-23.016],[0,0]],"o":[[0,0],[-23.015,0],[0,0],[0,-23.016],[0,0],[23.006,0],[0,0],[0,23.015]],"v":[[41.73,62.592],[-41.732,62.592],[-83.463,20.87],[-83.463,-20.86],[-41.732,-62.592],[41.73,-62.592],[83.463,-20.86],[83.463,20.87]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.466666696586,0.458823559331,0.490196108351,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[182.824,141.088],"to":[0,0],"ti":[0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":30,"s":[152.824,131.088],"to":[0,0],"ti":[0,0]},{"t":58.0000023623884,"s":[182.824,141.088]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60.0000024438501,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx b/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
index 4e62239a4..1ebab9879 100644
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/index.tsx
@@ -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}
>
-
-
-
-
+
-
-
+ />
);
};
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts b/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
index b3682dbcb..cf448ec76 100644
--- a/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/style.ts
@@ -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',
+ },
};
});
diff --git a/apps/web/src/components/blocksuite/header/editor-mode-switch/switch-items.tsx b/apps/web/src/components/blocksuite/header/editor-mode-switch/switch-items.tsx
new file mode 100644
index 000000000..dbf8a616a
--- /dev/null
+++ b/apps/web/src/components/blocksuite/header/editor-mode-switch/switch-items.tsx
@@ -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;
+
+const HoverAnimateController = ({
+ active,
+ hide,
+ children,
+ ...props
+}: HoverAnimateControllerProps) => {
+ const [startAnimate, setStartAnimate] = useState(false);
+ return (
+ {
+ setStartAnimate(true);
+ }}
+ onMouseLeave={() => {
+ setStartAnimate(false);
+ }}
+ {...props}
+ >
+ {cloneElement(children, {
+ isStopped: !startAnimate,
+ speed: 5,
+ width: 20,
+ height: 20,
+ })}
+
+ );
+};
+
+export const PageSwitchItem = (
+ props: Omit
+) => {
+ return (
+
+
+
+ );
+};
+
+export const EdgelessSwitchItem = (
+ props: Omit
+) => {
+ return (
+
+
+
+ );
+};
diff --git a/apps/web/src/hooks/__tests__/index.spec.tsx b/apps/web/src/hooks/__tests__/index.spec.tsx
index ea91911a5..7f2fa0a40 100644
--- a/apps/web/src/hooks/__tests__/index.spec.tsx
+++ b/apps/web/src/hooks/__tests__/index.spec.tsx
@@ -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(() => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 82232ab9e..a4908c21b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -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==}