diff --git a/blocksuite/affine/all/src/extensions/common.ts b/blocksuite/affine/all/src/extensions/common.ts index c15d469e52..b67d6f7c73 100644 --- a/blocksuite/affine/all/src/extensions/common.ts +++ b/blocksuite/affine/all/src/extensions/common.ts @@ -57,6 +57,7 @@ export const CommonBlockSpecs: ExtensionType[] = [ DefaultOpenDocExtension, FontLoaderService, CalloutBlockSpec, + FrameBlockSpec, ].flat(); export const PageFirstPartyBlockSpecs: ExtensionType[] = [ @@ -72,6 +73,5 @@ export const EdgelessFirstPartyBlockSpecs: ExtensionType[] = [ EdgelessNoteBlockSpec, EdgelessSurfaceBlockSpec, EdgelessSurfaceRefBlockSpec, - FrameBlockSpec, EdgelessTextBlockSpec, ].flat(); diff --git a/blocksuite/affine/blocks/block-frame/src/frame-spec.ts b/blocksuite/affine/blocks/block-frame/src/frame-spec.ts index bc515690ce..374d2dd6a1 100644 --- a/blocksuite/affine/blocks/block-frame/src/frame-spec.ts +++ b/blocksuite/affine/blocks/block-frame/src/frame-spec.ts @@ -2,6 +2,10 @@ import { BlockViewExtension } from '@blocksuite/block-std'; import type { ExtensionType } from '@blocksuite/store'; import { literal } from 'lit/static-html.js'; +import { EdgelessFrameManager, FrameOverlay } from './frame-manager'; + export const FrameBlockSpec: ExtensionType[] = [ BlockViewExtension('affine:frame', literal`affine-frame`), + FrameOverlay, + EdgelessFrameManager, ]; diff --git a/blocksuite/affine/blocks/block-root/src/edgeless/edgeless-builtin-spec.ts b/blocksuite/affine/blocks/block-root/src/edgeless/edgeless-builtin-spec.ts index 58cc0b62d3..83b9c291c4 100644 --- a/blocksuite/affine/blocks/block-root/src/edgeless/edgeless-builtin-spec.ts +++ b/blocksuite/affine/blocks/block-root/src/edgeless/edgeless-builtin-spec.ts @@ -1,8 +1,4 @@ -import { - EdgelessFrameManager, - FrameOverlay, - PresentTool, -} from '@blocksuite/affine-block-frame'; +import { PresentTool } from '@blocksuite/affine-block-frame'; import { ConnectionOverlay } from '@blocksuite/affine-block-surface'; import { TextTool } from '@blocksuite/affine-gfx-text'; import type { ExtensionType } from '@blocksuite/store'; @@ -41,10 +37,8 @@ export const EdgelessToolExtension: ExtensionType[] = [ export const EdgelessBuiltInManager: ExtensionType[] = [ ConnectionOverlay, - FrameOverlay, MindMapIndicatorOverlay, SnapManager, - EdgelessFrameManager, EditPropsMiddlewareBuilder, ]; diff --git a/blocksuite/affine/blocks/block-surface-ref/package.json b/blocksuite/affine/blocks/block-surface-ref/package.json index b65763a578..9e5c2a1907 100644 --- a/blocksuite/affine/blocks/block-surface-ref/package.json +++ b/blocksuite/affine/blocks/block-surface-ref/package.json @@ -10,6 +10,7 @@ "author": "toeverything", "license": "MIT", "dependencies": { + "@blocksuite/affine-block-frame": "workspace:*", "@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-model": "workspace:*", diff --git a/blocksuite/affine/blocks/block-surface-ref/src/configs/slash-menu.ts b/blocksuite/affine/blocks/block-surface-ref/src/configs/slash-menu.ts index c6aabb0e5c..3684dcb797 100644 --- a/blocksuite/affine/blocks/block-surface-ref/src/configs/slash-menu.ts +++ b/blocksuite/affine/blocks/block-surface-ref/src/configs/slash-menu.ts @@ -1,11 +1,16 @@ +import { EdgelessFrameManagerIdentifier } from '@blocksuite/affine-block-frame'; import { getSurfaceBlock } from '@blocksuite/affine-block-surface'; -import type { FrameBlockModel } from '@blocksuite/affine-model'; +import { type FrameBlockModel, NoteBlockModel } from '@blocksuite/affine-model'; import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands'; +import { matchModels } from '@blocksuite/affine-shared/utils'; import { type SlashMenuActionItem, type SlashMenuConfig, SlashMenuConfigExtension, + type SlashMenuItem, } from '@blocksuite/affine-widget-slash-menu'; +import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; +import { Bound } from '@blocksuite/global/gfx'; import { FrameIcon, GroupingIcon } from '@blocksuite/icons/lit'; import { insertSurfaceRefBlockCommand } from '../commands'; @@ -15,6 +20,54 @@ const surfaceRefSlashMenuConfig: SlashMenuConfig = { items: ({ std }) => { let index = 0; + const insertBlankFrameItem: SlashMenuItem = { + name: 'Frame', + description: 'Insert a blank frame', + icon: FrameIcon(), + tooltip: { + figure: EdgelessTooltip, + caption: 'Edgeless', + }, + group: `5_Edgeless Element@${index++}`, + action: ({ std, model }) => { + const { root } = std.store; + if (!root) return; + + const pageBlock = root.children.find( + (model): model is NoteBlockModel => + matchModels(model, [NoteBlockModel]) && model.isPageBlock() + ); + if (!pageBlock) return; + + const top = pageBlock.x; + const right = pageBlock.x + pageBlock.w; + const padding = 20; + + let frameBound = Bound.fromXYWH([right + padding, top, 1600, 900]); + const gfx = std.get(GfxControllerIdentifier); + + // Find a space to insert the frame + let elementInFrameBound = gfx.grid.search(frameBound); + while (elementInFrameBound.length > 0) { + const rightElement = elementInFrameBound.reduce((a, b) => { + return a.x + a.w > b.x + b.w ? a : b; + }); + frameBound.x = rightElement.x + rightElement.w + padding; + elementInFrameBound = gfx.grid.search(frameBound); + } + + const frameMgr = std.get(EdgelessFrameManagerIdentifier); + const frame = frameMgr.createFrameOnBound(frameBound); + + std.command.exec(insertSurfaceRefBlockCommand, { + reference: frame.id, + place: 'after', + removeEmptyLine: true, + selectedModels: [model], + }); + }, + }; + const surfaceModel = getSurfaceBlock(std.store); if (!surfaceModel) return []; @@ -25,7 +78,7 @@ const surfaceRefSlashMenuConfig: SlashMenuConfig = { const frameItems = frameModels.map(frameModel => ({ name: 'Frame: ' + frameModel.props.title, icon: FrameIcon(), - group: `5_Document Group & Frame@${index++}`, + group: `5_Edgeless Element@${index++}`, tooltip: { figure: EdgelessTooltip, caption: 'Edgeless', @@ -47,7 +100,7 @@ const surfaceRefSlashMenuConfig: SlashMenuConfig = { const groupItems = groupElements.map(group => ({ name: 'Group: ' + group.title.toString(), icon: GroupingIcon(), - group: `5_Document Group & Frame@${index++}`, + group: `5_Edgeless Element@${index++}`, tooltip: { figure: EdgelessTooltip, caption: 'Edgeless', @@ -65,7 +118,7 @@ const surfaceRefSlashMenuConfig: SlashMenuConfig = { }, })); - return [...frameItems, ...groupItems]; + return [insertBlankFrameItem, ...frameItems, ...groupItems]; }, }; diff --git a/blocksuite/affine/blocks/block-surface-ref/tsconfig.json b/blocksuite/affine/blocks/block-surface-ref/tsconfig.json index 3aeb8fc2d8..6c86295069 100644 --- a/blocksuite/affine/blocks/block-surface-ref/tsconfig.json +++ b/blocksuite/affine/blocks/block-surface-ref/tsconfig.json @@ -7,6 +7,7 @@ }, "include": ["./src"], "references": [ + { "path": "../block-frame" }, { "path": "../block-surface" }, { "path": "../../components" }, { "path": "../../model" }, diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index be45b3f69b..a7c7b93216 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -336,6 +336,7 @@ export const PackageList = [ location: 'blocksuite/affine/blocks/block-surface-ref', name: '@blocksuite/affine-block-surface-ref', workspaceDependencies: [ + 'blocksuite/affine/blocks/block-frame', 'blocksuite/affine/blocks/block-surface', 'blocksuite/affine/components', 'blocksuite/affine/model', diff --git a/yarn.lock b/yarn.lock index d808a24c5b..3252fa336b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2692,6 +2692,7 @@ __metadata: version: 0.0.0-use.local resolution: "@blocksuite/affine-block-surface-ref@workspace:blocksuite/affine/blocks/block-surface-ref" dependencies: + "@blocksuite/affine-block-frame": "workspace:*" "@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-model": "workspace:*"