feat(editor): add animation for switching to edgeless mode firstly (#10021)

Close [BS-2327](https://linear.app/affine-design/issue/BS-2327/page-block-%E5%9C%A8-edgeless-%E5%88%87%E6%8D%A2%E7%BC%A9%E6%94%BE%E5%8A%A8%E7%94%BB)

### What Changes:
- Add a zoom animation when switching to edgeless mode firstly
- Move viewport record from `sessionStorage` to `localStorage`

https://github.com/user-attachments/assets/dac11aab-76bd-44b1-8c0e-4a8a10919841
This commit is contained in:
L-Sun
2025-02-10 07:41:10 +00:00
parent 1d1eab8139
commit 9f56a21d8a
10 changed files with 120 additions and 39 deletions

View File

@@ -6,19 +6,25 @@ import {
EdgelessLegacySlotIdentifier,
normalizeWheelDeltaY,
} from '@blocksuite/affine-block-surface';
import type {
RootBlockModel,
ShapeElementModel,
} from '@blocksuite/affine-model';
import {
type NoteBlockModel,
NoteDisplayMode,
type RootBlockModel,
type ShapeElementModel,
} from '@blocksuite/affine-model';
import { EDGELESS_BLOCK_CHILD_PADDING } from '@blocksuite/affine-shared/consts';
import {
DocModeProvider,
EditorSettingProvider,
EditPropsStore,
FeatureFlagService,
FontLoaderService,
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import type { Viewport } from '@blocksuite/affine-shared/types';
import {
isTouchPadPinchEvent,
matchFlavours,
requestConnectedFrame,
requestThrottledConnectedFrame,
} from '@blocksuite/affine-shared/utils';
@@ -340,11 +346,65 @@ export class EdgelessRootBlockComponent extends BlockComponent<
private _initViewport() {
const { std, gfx } = this;
const pageBlockViewportFitAnimation = () => {
const primaryMode = std.get(DocModeProvider).getPrimaryMode(this.doc.id);
const note = this.model.children.find(
(child): child is NoteBlockModel =>
matchFlavours(child, ['affine:note']) &&
child.displayMode !== NoteDisplayMode.EdgelessOnly
);
if (primaryMode !== 'page' || !note || note.edgeless.collapse)
return false;
const leftPadding = parseInt(
window
.getComputedStyle(this)
.getPropertyValue('--affine-editor-side-padding')
.replace('px', '')
);
if (isNaN(leftPadding)) return false;
let editorWidth = parseInt(
window
.getComputedStyle(this)
.getPropertyValue('--affine-editor-width')
.replace('px', '')
);
if (isNaN(editorWidth)) return false;
const containerWidth = this.getBoundingClientRect().width;
const leftMargin =
containerWidth > editorWidth ? (containerWidth - editorWidth) / 2 : 0;
const pageTitleAnchor = gfx.viewport.toModelCoord(
leftPadding + leftMargin,
0
);
const noteBound = Bound.deserialize(note.xywh);
const edgelessTitleAnchor = Vec.add(noteBound.tl, [
EDGELESS_BLOCK_CHILD_PADDING,
12,
]);
const center = Vec.sub(edgelessTitleAnchor, pageTitleAnchor);
gfx.viewport.setCenter(center[0], center[1]);
gfx.viewport.smoothZoom(0.65, undefined, 15);
return true;
};
const run = () => {
const storedViewport = std.get(EditPropsStore).getStorage('viewport');
if (!storedViewport) {
this.gfx.fitToScreen();
const enablePageBlock = this.std
.get(FeatureFlagService)
.getFlag('enable_page_block');
if (!(enablePageBlock && pageBlockViewportFitAnimation())) {
this.gfx.fitToScreen();
}
return;
}