refactor(editor): inner toolbar surface-ref block with extension (#11246)

This PR refactor `surface-ref` toolbar with `ToolbarExtension`
This commit is contained in:
L-Sun
2025-03-28 05:48:24 +00:00
parent 69f393fe2f
commit af91a0217f
22 changed files with 551 additions and 542 deletions

View File

@@ -29,6 +29,7 @@ import {
EmbedYoutubeBlockComponent,
getDocContentWithMaxLength,
} from '@blocksuite/affine/blocks/embed';
import { SurfaceRefBlockComponent } from '@blocksuite/affine/blocks/surface-ref';
import { toggleEmbedCardEditModal } from '@blocksuite/affine/components/embed-card-modal';
import {
notifyLinkedDocClearedAliases,
@@ -51,6 +52,7 @@ import {
EmbedIframeBlockModel,
EmbedLinkedDocModel,
EmbedSyncedDocModel,
SurfaceRefBlockSchema,
} from '@blocksuite/affine/model';
import { getSelectedModelsCommand } from '@blocksuite/affine/shared/commands';
import { ImageSelection } from '@blocksuite/affine/shared/selection';
@@ -70,6 +72,7 @@ import {
import { matchModels } from '@blocksuite/affine/shared/utils';
import type { ExtensionType } from '@blocksuite/affine/store';
import {
ArrowDownSmallIcon,
CopyAsImgaeIcon,
CopyIcon,
EditIcon,
@@ -481,7 +484,8 @@ function createOpenDocActions(
target:
| EmbedLinkedDocBlockComponent
| EmbedSyncedDocBlockComponent
| AffineReference,
| AffineReference
| SurfaceRefBlockComponent,
isSameDoc: boolean,
actions = openDocActions.map(
({ type: mode, label, icon, enabled: when }, i) => ({
@@ -569,6 +573,131 @@ function createEdgelessOpenDocActionGroup(
};
}
function createSurfaceRefToolbarConfig(baseUrl?: string): ToolbarModuleConfig {
return {
actions: [
{
id: 'b.open-surface-ref',
when: ctx =>
!!ctx.getCurrentBlockByType(SurfaceRefBlockComponent)?.referenceModel,
content: ctx => {
const surfaceRefBlock = ctx.getCurrentBlockByType(
SurfaceRefBlockComponent
);
if (!surfaceRefBlock) return null;
const actions = createOpenDocActions(ctx, surfaceRefBlock, false)
.map(action => ({
...action,
...action.generate(ctx),
}))
.map(action => {
if (action.id.endsWith('open-in-active-view')) {
action.label =
I18n['com.affine.peek-view-controls.open-doc-in-edgeless']();
}
return action;
});
if (!actions.length) return null;
const styles = styleMap({
gap: 4,
});
return html`${keyed(
surfaceRefBlock,
html`<editor-menu-button
aria-label="Open"
.contentPadding=${'8px'}
.button=${html`<editor-icon-button
.iconSize=${'16px'}
.iconContainerPadding=${4}
>
${OpenInNewIcon()} ${ArrowDownSmallIcon()}
</editor-icon-button>`}
>
<div data-orientation="vertical" style=${styles}>
${repeat(
actions,
action => action.id,
({ label, icon, run, disabled }) => html`
<editor-menu-action
aria-label=${ifDefined(label)}
?disabled=${disabled}
@click=${() => {
run?.(ctx);
}}
>
${icon}<span class="label">${label}</span>
</editor-menu-action>
`
)}
</div>
</editor-menu-button>`
)}`;
},
},
{
id: 'a.clipboard',
placement: ActionPlacement.More,
actions: [
{
id: 'copy-link-to-surface-ref',
label: 'Copy original link',
icon: LinkIcon(),
when: ctx =>
!!ctx.getCurrentBlockByType(SurfaceRefBlockComponent)
?.referenceModel,
run: ctx => {
const surfaceRefBlock = ctx.getCurrentBlockByType(
SurfaceRefBlockComponent
);
if (!surfaceRefBlock) return;
const refModel = surfaceRefBlock.referenceModel;
if (!refModel) return;
const { store, workspace, std } = ctx;
const pageId = store.doc.id;
const workspaceId = workspace.id;
const options: UseSharingUrl = {
workspaceId,
pageId,
mode: 'edgeless',
};
let type = '';
if (refModel instanceof GfxPrimitiveElementModel) {
options.elementIds = [refModel.id];
type = refModel.type;
} else if (refModel instanceof GfxBlockElementModel) {
options.blockIds = [refModel.id];
type = refModel.flavour;
}
const str = generateUrl({
...options,
baseUrl: baseUrl ?? location.origin,
});
if (!str) return;
copyLinkToBlockStdScopeClipboard(str, std.clipboard)
.then(ok => {
if (!ok) return;
notify.success({ title: I18n['Copied link to clipboard']() });
})
.catch(console.error);
track.doc.editor.toolbar.copyBlockToLink({ type });
},
},
],
},
],
};
}
function renderOpenDocMenu(
settings: EditorSettingExt,
ctx: ToolbarContext,
@@ -877,11 +1006,11 @@ const embedIframeToolbarConfig = {
},
actions: [
{
id: 'b.copy-link',
id: 'a.copy-link-and-edit',
actions: [
{
id: 'copy-link',
tooltip: 'Copy original link',
tooltip: 'Copy link',
icon: CopyIcon(),
run(ctx) {
const model = ctx.getCurrentBlockByType(
@@ -895,14 +1024,52 @@ const embedIframeToolbarConfig = {
toast(ctx.host, 'Copied link to clipboard');
ctx.track('CopiedLink', {
category: matchModels(model, [EmbedIframeBlockModel])
? 'embed iframe block'
category: matchModels(model, [BookmarkBlockModel])
? 'bookmark'
: 'link',
type: 'card view',
control: 'copy link',
});
},
},
{
id: 'edit',
tooltip: 'Edit',
icon: EditIcon(),
run(ctx) {
const component = ctx.getCurrentBlockByType(
EmbedIframeBlockComponent
);
if (!component) return;
ctx.hide();
const model = component.model;
const abortController = new AbortController();
abortController.signal.onabort = () => ctx.show();
toggleEmbedCardEditModal(
ctx.host,
model,
'card',
undefined,
undefined,
(_std, _component, props) => {
ctx.store.updateBlock(model, props);
component.requestUpdate();
},
abortController
);
ctx.track('OpenedAliasPopup', {
category: matchModels(model, [BookmarkBlockModel])
? 'bookmark'
: 'link',
type: 'card view',
control: 'edit',
});
},
},
],
},
],
@@ -1052,5 +1219,12 @@ export const createCustomToolbarExtension = (
when: ctx => ctx.getSurfaceModels().length === 1,
},
}),
ToolbarModuleExtension({
id: BlockFlavourIdentifier(
`custom:${SurfaceRefBlockSchema.model.flavour}`
),
config: createSurfaceRefToolbarConfig(baseUrl),
}),
];
};

View File

@@ -10,7 +10,6 @@ import {
} from '@blocksuite/affine/blocks/code';
import { imageToolbarWidget } from '@blocksuite/affine/blocks/image';
import { ParagraphBlockConfigExtension } from '@blocksuite/affine/blocks/paragraph';
import { surfaceRefToolbarWidget } from '@blocksuite/affine/blocks/surface-ref';
import type {
Container,
ServiceIdentifier,
@@ -136,7 +135,6 @@ export function enableMobileExtension(
): void {
specBuilder.omit(codeToolbarWidget);
specBuilder.omit(imageToolbarWidget);
specBuilder.omit(surfaceRefToolbarWidget);
specBuilder.omit(toolbarWidget);
specBuilder.omit(SlashMenuExtension);
specBuilder.extend([

View File

@@ -204,6 +204,7 @@ const DetailPageImpl = memo(function DetailPageImpl() {
workbench.openDoc(
{
docId: pageId,
mode: params?.mode,
blockIds: params?.blockIds,
elementIds: params?.elementIds,
},