refactor(editor): edgeless attacment toolbar config extension (#10710)
This commit is contained in:
@@ -1,18 +1,13 @@
|
||||
import { AttachmentBlockSchema } from '@blocksuite/affine-model';
|
||||
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
|
||||
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
|
||||
import {
|
||||
BlockFlavourIdentifier,
|
||||
BlockViewExtension,
|
||||
FlavourExtension,
|
||||
} from '@blocksuite/block-std';
|
||||
import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
import { literal } from 'lit/static-html.js';
|
||||
|
||||
import { AttachmentBlockNotionHtmlAdapterExtension } from './adapters/notion-html.js';
|
||||
import { AttachmentDropOption } from './attachment-service.js';
|
||||
import { attachmentSlashMenuConfig } from './configs/slash-menu.js';
|
||||
import { builtinToolbarConfig } from './configs/toolbar';
|
||||
import { createBuiltinToolbarConfigExtension } from './configs/toolbar';
|
||||
import {
|
||||
AttachmentEmbedConfigExtension,
|
||||
AttachmentEmbedService,
|
||||
@@ -31,9 +26,6 @@ export const AttachmentBlockSpec: ExtensionType[] = [
|
||||
AttachmentEmbedConfigExtension(),
|
||||
AttachmentEmbedService,
|
||||
AttachmentBlockNotionHtmlAdapterExtension,
|
||||
ToolbarModuleExtension({
|
||||
id: BlockFlavourIdentifier(flavour),
|
||||
config: builtinToolbarConfig,
|
||||
}),
|
||||
createBuiltinToolbarConfigExtension(flavour),
|
||||
SlashMenuConfigExtension(flavour, attachmentSlashMenuConfig),
|
||||
];
|
||||
].flat();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLitPortal } from '@blocksuite/affine-components/portal';
|
||||
import {
|
||||
AttachmentBlockModel,
|
||||
defaultAttachmentProps,
|
||||
type EmbedCardStyle,
|
||||
} from '@blocksuite/affine-model';
|
||||
import {
|
||||
EMBED_CARD_HEIGHT,
|
||||
@@ -12,7 +13,9 @@ import {
|
||||
type ToolbarAction,
|
||||
type ToolbarActionGroup,
|
||||
type ToolbarModuleConfig,
|
||||
ToolbarModuleExtension,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
|
||||
import { Bound } from '@blocksuite/global/gfx';
|
||||
import {
|
||||
CaptionIcon,
|
||||
@@ -23,6 +26,7 @@ import {
|
||||
EditIcon,
|
||||
ResetIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
import { flip, offset } from '@floating-ui/dom';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { html } from 'lit';
|
||||
@@ -34,9 +38,6 @@ import { AttachmentEmbedProvider } from '../embed';
|
||||
import { cloneAttachmentProperties } from '../utils';
|
||||
|
||||
const trackBaseProps = {
|
||||
segment: 'doc',
|
||||
page: 'doc editor',
|
||||
module: 'toolbar',
|
||||
category: 'attachment',
|
||||
type: 'card view',
|
||||
};
|
||||
@@ -54,14 +55,14 @@ export const attachmentViewDropdownMenu = {
|
||||
const style = defaultAttachmentProps.style!;
|
||||
const width = EMBED_CARD_WIDTH[style];
|
||||
const height = EMBED_CARD_HEIGHT[style];
|
||||
const bound = Bound.deserialize(model.xywh);
|
||||
bound.w = width;
|
||||
bound.h = height;
|
||||
const bounds = Bound.deserialize(model.xywh);
|
||||
bounds.w = width;
|
||||
bounds.h = height;
|
||||
|
||||
ctx.store.updateBlock(model, {
|
||||
style,
|
||||
embed: false,
|
||||
xywh: bound.serialize(),
|
||||
xywh: bounds.serialize(),
|
||||
});
|
||||
},
|
||||
},
|
||||
@@ -72,9 +73,11 @@ export const attachmentViewDropdownMenu = {
|
||||
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||
if (!model) return;
|
||||
|
||||
// Clears
|
||||
ctx.reset();
|
||||
ctx.select('note');
|
||||
if (!ctx.hasSelectedSurfaceModels) {
|
||||
// Clears
|
||||
ctx.reset();
|
||||
ctx.select('note');
|
||||
}
|
||||
|
||||
ctx.std.get(AttachmentEmbedProvider).convertTo(model);
|
||||
|
||||
@@ -101,7 +104,8 @@ export const attachmentViewDropdownMenu = {
|
||||
|
||||
return embed ? embedAction.label : cardAction.label;
|
||||
});
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
e.stopPropagation();
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -114,16 +118,41 @@ export const attachmentViewDropdownMenu = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-view-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.viewType$=${viewType$}
|
||||
></affine-view-dropdown-menu>`
|
||||
)}`;
|
||||
},
|
||||
} satisfies ToolbarActionGroup<ToolbarAction>;
|
||||
} as const satisfies ToolbarActionGroup<ToolbarAction>;
|
||||
|
||||
export const builtinToolbarConfig = {
|
||||
const downloadAction = {
|
||||
id: 'c.download',
|
||||
tooltip: 'Download',
|
||||
icon: DownloadIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||
block?.download();
|
||||
},
|
||||
} as const satisfies ToolbarAction;
|
||||
|
||||
const captionAction = {
|
||||
id: 'd.caption',
|
||||
tooltip: 'Caption',
|
||||
icon: CaptionIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||
block?.captionEditor?.show();
|
||||
|
||||
ctx.track('OpenedCaptionEditor', {
|
||||
...trackBaseProps,
|
||||
control: 'add caption',
|
||||
});
|
||||
},
|
||||
} as const satisfies ToolbarAction;
|
||||
|
||||
const builtinToolbarConfig = {
|
||||
actions: [
|
||||
{
|
||||
id: 'a.rename',
|
||||
@@ -162,29 +191,8 @@ export const builtinToolbarConfig = {
|
||||
},
|
||||
},
|
||||
attachmentViewDropdownMenu,
|
||||
{
|
||||
id: 'c.download',
|
||||
tooltip: 'Download',
|
||||
icon: DownloadIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||
block?.download();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'd.caption',
|
||||
tooltip: 'Caption',
|
||||
icon: CaptionIcon(),
|
||||
run(ctx) {
|
||||
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||
block?.captionEditor?.show();
|
||||
|
||||
ctx.track('OpenedCaptionEditor', {
|
||||
...trackBaseProps,
|
||||
control: 'add caption',
|
||||
});
|
||||
},
|
||||
},
|
||||
downloadAction,
|
||||
captionAction,
|
||||
{
|
||||
placement: ActionPlacement.More,
|
||||
id: 'a.clipboard',
|
||||
@@ -247,3 +255,96 @@ export const builtinToolbarConfig = {
|
||||
},
|
||||
],
|
||||
} as const satisfies ToolbarModuleConfig;
|
||||
|
||||
const builtinSurfaceToolbarConfig = {
|
||||
actions: [
|
||||
attachmentViewDropdownMenu,
|
||||
{
|
||||
id: 'c.style',
|
||||
actions: [
|
||||
{
|
||||
id: 'horizontalThin',
|
||||
label: 'Horizontal style',
|
||||
},
|
||||
{
|
||||
id: 'cubeThick',
|
||||
label: 'Vertical style',
|
||||
},
|
||||
],
|
||||
content(ctx) {
|
||||
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||
if (!model) return null;
|
||||
|
||||
const actions = this.actions.map(action => ({
|
||||
...action,
|
||||
run: ({ store }) => {
|
||||
const style = action.id as EmbedCardStyle;
|
||||
const bounds = Bound.deserialize(model.xywh);
|
||||
bounds.w = EMBED_CARD_WIDTH[style];
|
||||
bounds.h = EMBED_CARD_HEIGHT[style];
|
||||
const xywh = bounds.serialize();
|
||||
|
||||
store.updateBlock(model, { style, xywh });
|
||||
|
||||
ctx.track('SelectedCardStyle', {
|
||||
...trackBaseProps,
|
||||
page: 'whiteboard editor',
|
||||
control: 'select card style',
|
||||
type: style,
|
||||
});
|
||||
},
|
||||
})) satisfies ToolbarAction[];
|
||||
const style$ = model.props.style$;
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
e.stopPropagation();
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
ctx.track('OpenedCardStyleSelector', {
|
||||
...trackBaseProps,
|
||||
page: 'whiteboard editor',
|
||||
control: 'switch card style',
|
||||
});
|
||||
};
|
||||
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-card-style-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.style$=${style$}
|
||||
></affine-card-style-dropdown-menu>`
|
||||
)}`;
|
||||
},
|
||||
} satisfies ToolbarActionGroup<ToolbarAction>,
|
||||
{
|
||||
...downloadAction,
|
||||
id: 'd.download',
|
||||
},
|
||||
{
|
||||
...captionAction,
|
||||
id: 'e.caption',
|
||||
},
|
||||
],
|
||||
|
||||
when: ctx => ctx.getSurfaceModelsByType(AttachmentBlockModel).length === 1,
|
||||
} as const satisfies ToolbarModuleConfig;
|
||||
|
||||
export const createBuiltinToolbarConfigExtension = (
|
||||
flavour: string
|
||||
): ExtensionType[] => {
|
||||
const name = flavour.split(':').pop();
|
||||
|
||||
return [
|
||||
ToolbarModuleExtension({
|
||||
id: BlockFlavourIdentifier(flavour),
|
||||
config: builtinToolbarConfig,
|
||||
}),
|
||||
|
||||
ToolbarModuleExtension({
|
||||
id: BlockFlavourIdentifier(`affine:surface:${name}`),
|
||||
config: builtinSurfaceToolbarConfig,
|
||||
}),
|
||||
];
|
||||
};
|
||||
|
||||
@@ -181,7 +181,7 @@ export const builtinToolbarConfig = {
|
||||
if (!model) return null;
|
||||
|
||||
const actions = this.actions.map(action => ({ ...action }));
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -194,9 +194,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-view-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.viewType$=${signal(actions[1].label)}
|
||||
></affine-view-dropdown-menu>`
|
||||
)}`;
|
||||
@@ -231,7 +231,7 @@ export const builtinToolbarConfig = {
|
||||
},
|
||||
})) satisfies ToolbarAction[];
|
||||
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -244,9 +244,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-card-style-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.style$=${model.props.style$}
|
||||
></affine-card-style-dropdown-menu>`
|
||||
)}`;
|
||||
|
||||
@@ -242,8 +242,7 @@ export function createBuiltinToolbarConfigForExternal(
|
||||
const viewType$ = signal(
|
||||
`${viewType === 'card' ? 'Card' : 'Embed'} view`
|
||||
);
|
||||
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -256,9 +255,9 @@ export function createBuiltinToolbarConfigForExternal(
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-view-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.viewType$=${viewType$}
|
||||
></affine-view-dropdown-menu>`
|
||||
)}`;
|
||||
@@ -293,7 +292,7 @@ export function createBuiltinToolbarConfigForExternal(
|
||||
},
|
||||
})) satisfies ToolbarAction[];
|
||||
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -306,9 +305,9 @@ export function createBuiltinToolbarConfigForExternal(
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-card-style-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.style$=${model.props.style$}
|
||||
></affine-card-style-dropdown-menu>`
|
||||
)}`;
|
||||
|
||||
@@ -67,8 +67,7 @@ export const builtinToolbarConfig = {
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -81,9 +80,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-card-style-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.style=${model.props.style$}
|
||||
></affine-card-style-dropdown-menu>`
|
||||
)}`;
|
||||
|
||||
@@ -119,7 +119,7 @@ export const builtinToolbarConfig = {
|
||||
if (!model) return null;
|
||||
|
||||
const actions = this.actions.map(action => ({ ...action }));
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -132,9 +132,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-view-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.viewType$=${signal(actions[1].label)}
|
||||
></affine-view-dropdown-menu>`
|
||||
)}`;
|
||||
@@ -168,7 +168,7 @@ export const builtinToolbarConfig = {
|
||||
});
|
||||
},
|
||||
})) satisfies ToolbarAction[];
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -181,9 +181,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-card-style-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.style$=${model.props.style$}
|
||||
></affine-card-style-dropdown-menu>`
|
||||
)}`;
|
||||
|
||||
@@ -155,8 +155,7 @@ export const builtinToolbarConfig = {
|
||||
if (!model) return null;
|
||||
|
||||
const actions = this.actions.map(action => ({ ...action }));
|
||||
|
||||
const toggle = (e: CustomEvent<boolean>) => {
|
||||
const onToggle = (e: CustomEvent<boolean>) => {
|
||||
const opened = e.detail;
|
||||
if (!opened) return;
|
||||
|
||||
@@ -169,9 +168,9 @@ export const builtinToolbarConfig = {
|
||||
return html`${keyed(
|
||||
model,
|
||||
html`<affine-view-dropdown-menu
|
||||
@toggle=${onToggle}
|
||||
.actions=${actions}
|
||||
.context=${ctx}
|
||||
.toggle=${toggle}
|
||||
.viewType$=${signal(actions[2].label)}
|
||||
></affine-view-dropdown-menu>`
|
||||
)}`;
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import type { ToolbarModuleConfig } from '@blocksuite/affine-shared/services';
|
||||
|
||||
export const builtinAttachmentToolbarConfig = {
|
||||
actions: [
|
||||
{
|
||||
id: 'a.test',
|
||||
label: 'Attachment',
|
||||
run() {},
|
||||
},
|
||||
],
|
||||
} as const satisfies ToolbarModuleConfig;
|
||||
@@ -2,7 +2,6 @@ import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
|
||||
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { builtinAttachmentToolbarConfig } from './attachment';
|
||||
import { builtinBookmarkToolbarConfig } from './bookmark';
|
||||
import { builtinBrushToolbarConfig } from './brush';
|
||||
import { builtinConnectorToolbarConfig } from './connector';
|
||||
@@ -17,11 +16,6 @@ import { builtinShapeToolbarConfig } from './shape';
|
||||
import { builtinTextToolbarConfig } from './text';
|
||||
|
||||
export const EdgelessElementToolbarExtension: ExtensionType[] = [
|
||||
ToolbarModuleExtension({
|
||||
id: BlockFlavourIdentifier('affine:surface:attachment'),
|
||||
config: builtinAttachmentToolbarConfig,
|
||||
}),
|
||||
|
||||
ToolbarModuleExtension({
|
||||
id: BlockFlavourIdentifier('affine:surface:bookmark'),
|
||||
config: builtinBookmarkToolbarConfig,
|
||||
|
||||
Reference in New Issue
Block a user