Skip to content

Commit

Permalink
feat(editor): add toolbar registry extension
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Feb 5, 2025
1 parent 7579570 commit 77d0bd0
Show file tree
Hide file tree
Showing 54 changed files with 2,525 additions and 71 deletions.
20 changes: 16 additions & 4 deletions blocksuite/affine/block-attachment/src/attachment-spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import {
BlockFlavourIdentifier,
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 { builtinToolbarConfig } from './configs/toolbar';
import {
AttachmentEmbedConfigExtension,
AttachmentEmbedService,
} from './embed.js';
} from './embed';

const flavour = 'affine:attachment';

export const AttachmentBlockSpec: ExtensionType[] = [
FlavourExtension('affine:attachment'),
BlockViewExtension('affine:attachment', model => {
FlavourExtension(flavour),
BlockViewExtension(flavour, model => {
return model.parent?.flavour === 'affine:surface'
? literal`affine-edgeless-attachment`
: literal`affine-attachment`;
Expand All @@ -20,4 +28,8 @@ export const AttachmentBlockSpec: ExtensionType[] = [
AttachmentEmbedConfigExtension(),
AttachmentEmbedService,
AttachmentBlockNotionHtmlAdapterExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier(flavour),
config: builtinToolbarConfig,
}),
];
186 changes: 186 additions & 0 deletions blocksuite/affine/block-attachment/src/configs/toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {
type AttachmentBlockModel,
AttachmentBlockSchema,
defaultAttachmentProps,
} from '@blocksuite/affine-model';
import {
EMBED_CARD_HEIGHT,
EMBED_CARD_WIDTH,
} from '@blocksuite/affine-shared/consts';
import {
ActionPlacement,
type ToolbarAction,
type ToolbarActionGroup,
type ToolbarModuleConfig,
} from '@blocksuite/affine-shared/services';
import { BlockSelection } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/utils';
import {
CaptionIcon,
CopyIcon,
DeleteIcon,
DownloadIcon,
DuplicateIcon,
EditIcon,
ResetIcon,
} from '@blocksuite/icons/lit';
import { computed } from '@preact/signals-core';
import { html } from 'lit';

import { AttachmentBlockComponent } from '../attachment-block';
import { AttachmentEmbedProvider } from '../embed';

export const builtinToolbarConfig = {
actions: [
{
id: 'rename',
tooltip: 'Rename',
icon: EditIcon(),
run(_cx) {},
},
{
id: 'conversions',
actions: [
{
id: 'card-view',
label: 'Card view',
run(cx) {
const model = cx.getCurrentBlockModelBy(
BlockSelection,
AttachmentBlockSchema
);
if (!model) return;

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;

cx.store.updateBlock(model, {
style,
embed: false,
xywh: bound.serialize(),
});
},
},
{
id: 'embed-view',
label: 'Embed view',
run(cx) {
const model = cx.getCurrentBlockModelBy(
BlockSelection,
AttachmentBlockSchema
);
if (!model) return;

cx.std
.get(AttachmentEmbedProvider)
.convertTo(model as AttachmentBlockModel);
},
},
],
content(cx) {
const model = cx.getCurrentBlockModelBy(
BlockSelection,
AttachmentBlockSchema
);
if (!model) return null;

const actions = this.actions.map(action => ({ ...action }));

return html`<affine-view-dropdown
.actions=${actions}
.context=${cx}
.viewType$=${computed(() => {
const [cardAction, embedAction] = actions;
const embed = model.embed$.value ?? false;
cardAction.disabled = !embed;
embedAction.disabled =
embed &&
cx.std
.get(AttachmentEmbedProvider)
.embedded(model as AttachmentBlockModel);
return embed ? embedAction.label : cardAction.label;
})}
></affine-view-dropdown>`;
},
} satisfies ToolbarActionGroup<ToolbarAction>,
{
id: 'download',
tooltip: 'Download',
icon: DownloadIcon(),
run(cx) {
const component = cx.getCurrentBlockComponentBy(
BlockSelection,
AttachmentBlockComponent
);
component?.download();
},
},
{
id: 'caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(cx) {
const component = cx.getCurrentBlockComponentBy(
BlockSelection,
AttachmentBlockComponent
);
component?.captionEditor?.show();
},
},
{
id: 'clipboard',
placement: ActionPlacement.More,
actions: [
{
id: 'copy',
label: 'Copy',
icon: CopyIcon(),
run(_cx) {},
},
{
id: 'duplicate',
label: 'Duplicate',
icon: DuplicateIcon(),
run(_cx) {},
},
],
},
{
id: 'refresh',
placement: ActionPlacement.More,
actions: [
{
id: 'reload',
label: 'Reload',
icon: ResetIcon(),
run(cx) {
const component = cx.getCurrentBlockComponentBy(
BlockSelection,
AttachmentBlockComponent
);
component?.refreshData();
},
},
],
},
{
id: 'delete',
placement: ActionPlacement.More,
actions: [
{
id: 'delete',
label: 'Delete',
icon: DeleteIcon(),
variant: 'destructive',
run(_cx) {},
},
],
},
],
} as const satisfies ToolbarModuleConfig;
2 changes: 1 addition & 1 deletion blocksuite/affine/block-attachment/src/embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class AttachmentEmbedService extends Extension {
// Converts to embed view.
convertTo(model: AttachmentBlockModel, maxFileSize = this._maxFileSize) {
const config = this.values.find(config => config.check(model, maxFileSize));
if (!config || !config.action) {
if (!config?.action) {
model.doc.updateBlock(model, { embed: true });
return;
}
Expand Down
1 change: 1 addition & 0 deletions blocksuite/affine/block-bookmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@toeverything/theme": "^1.1.7",
"lit": "^3.2.0",
"minimatch": "^10.0.1",
"yjs": "^13.6.23",
"zod": "^3.23.8"
},
"exports": {
Expand Down
20 changes: 16 additions & 4 deletions blocksuite/affine/block-bookmark/src/bookmark-spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import {
BlockFlavourIdentifier,
BlockViewExtension,
FlavourExtension,
} from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store';
import { literal } from 'lit/static-html.js';

import { BookmarkBlockAdapterExtensions } from './adapters/extension.js';
import { BookmarkBlockAdapterExtensions } from './adapters/extension';
import { builtinToolbarConfig } from './configs/toolbar';

const flavour = 'affine:bookmark';

export const BookmarkBlockSpec: ExtensionType[] = [
FlavourExtension('affine:bookmark'),
BlockViewExtension('affine:bookmark', model => {
FlavourExtension(flavour),
BlockViewExtension(flavour, model => {
return model.parent?.flavour === 'affine:surface'
? literal`affine-edgeless-bookmark`
: literal`affine-bookmark`;
}),
BookmarkBlockAdapterExtensions,
ToolbarModuleExtension({
id: BlockFlavourIdentifier(flavour),
config: builtinToolbarConfig,
}),
].flat();
Loading

0 comments on commit 77d0bd0

Please sign in to comment.