refactor(editor): embed slash menu config extension (#10679)

This commit is contained in:
L-Sun
2025-03-07 08:21:19 +00:00
parent 37a13032ed
commit 8d9746e0cc
22 changed files with 203 additions and 192 deletions
@@ -18,6 +18,7 @@
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/affine-widget-slash-menu": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.2.1",
@@ -0,0 +1,39 @@
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { FigmaDuotoneIcon } from '@blocksuite/icons/lit';
import { FigmaTooltip } from './tooltips';
export const embedFigmaSlashMenuConfig: SlashMenuConfig = {
items: [
{
name: 'Figma',
description: 'Embed a Figma document.',
icon: FigmaDuotoneIcon(),
tooltip: {
figure: FigmaTooltip,
caption: 'Figma',
},
group: '4_Content & Media@7',
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-figma'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'Figma',
'The added Figma link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error);
},
},
],
};
@@ -1,4 +1,5 @@
import { html } from 'lit';
// prettier-ignore
export const FigmaTooltip = html`<svg width="170" height="106" viewBox="0 0 170 106" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="170" height="106" rx="2" fill="white"/>
@@ -1,5 +1,6 @@
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
import {
BlockServiceIdentifier,
BlockViewExtension,
@@ -10,6 +11,7 @@ import { literal } from 'lit/static-html.js';
import { createBuiltinToolbarConfigForExternal } from '../configs/toolbar';
import { EmbedFigmaBlockAdapterExtensions } from './adapters/extension';
import { embedFigmaSlashMenuConfig } from './configs/slash-menu';
import { EmbedFigmaBlockComponent } from './embed-figma-block';
import { EmbedFigmaBlockOptionConfig } from './embed-figma-service';
@@ -28,4 +30,5 @@ export const EmbedFigmaBlockSpec: ExtensionType[] = [
id: BlockServiceIdentifier(flavour),
config: createBuiltinToolbarConfigForExternal(EmbedFigmaBlockComponent),
}),
SlashMenuConfigExtension(flavour, embedFigmaSlashMenuConfig),
].flat();
@@ -0,0 +1,39 @@
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { GithubDuotoneIcon } from '@blocksuite/icons/lit';
import { GithubRepoTooltip } from './tooltips';
export const embedGithubSlashMenuConfig: SlashMenuConfig = {
items: [
{
name: 'GitHub',
description: 'Link to a GitHub repository.',
icon: GithubDuotoneIcon(),
tooltip: {
figure: GithubRepoTooltip,
caption: 'GitHub Repo',
},
group: '4_Content & Media@6',
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-github'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'GitHub',
'The added GitHub issue or pull request link will be displayed as a card view.',
{ mode: 'page', parentModel, index }
);
if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error);
},
},
],
};
@@ -1,4 +1,5 @@
import { html } from 'lit';
// prettier-ignore
export const GithubRepoTooltip = html`<svg width="170" height="68" viewBox="0 0 170 68" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="170" height="68" rx="2" fill="white"/>
@@ -1,5 +1,6 @@
import { EmbedGithubBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
import {
BlockServiceIdentifier,
BlockViewExtension,
@@ -10,6 +11,7 @@ import { literal } from 'lit/static-html.js';
import { createBuiltinToolbarConfigForExternal } from '../configs/toolbar';
import { EmbedGithubBlockAdapterExtensions } from './adapters/extension';
import { embedGithubSlashMenuConfig } from './configs/slash-menu';
import { EmbedGithubBlockComponent } from './embed-github-block';
import {
EmbedGithubBlockOptionConfig,
@@ -32,4 +34,5 @@ export const EmbedGithubBlockSpec: ExtensionType[] = [
id: BlockServiceIdentifier(flavour),
config: createBuiltinToolbarConfigForExternal(EmbedGithubBlockComponent),
}),
SlashMenuConfigExtension(flavour, embedGithubSlashMenuConfig),
].flat();
@@ -0,0 +1,32 @@
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { LoomLogoDuotoneIcon } from '@blocksuite/icons/lit';
export const embedLoomSlashMenuConfig: SlashMenuConfig = {
items: [
{
name: 'Loom',
icon: LoomLogoDuotoneIcon(),
group: '4_Content & Media@8',
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-loom'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'Loom',
'The added Loom video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error);
},
},
],
};
@@ -1,5 +1,6 @@
import { EmbedLoomBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
import {
BlockServiceIdentifier,
BlockViewExtension,
@@ -10,6 +11,7 @@ import { literal } from 'lit/static-html.js';
import { createBuiltinToolbarConfigForExternal } from '../configs/toolbar';
import { EmbedLoomBlockAdapterExtensions } from './adapters/extension';
import { embedLoomSlashMenuConfig } from './configs/slash-menu';
import { EmbedLoomBlockComponent } from './embed-loom-block';
import {
EmbedLoomBlockOptionConfig,
@@ -32,4 +34,5 @@ export const EmbedLoomBlockSpec: ExtensionType[] = [
id: BlockServiceIdentifier(flavour),
config: createBuiltinToolbarConfigForExternal(EmbedLoomBlockComponent),
}),
SlashMenuConfigExtension(flavour, embedLoomSlashMenuConfig),
].flat();
@@ -0,0 +1,39 @@
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import type { SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
import { YoutubeDuotoneIcon } from '@blocksuite/icons/lit';
import { YoutubeVideoTooltip } from './tooltips';
export const embedYoutubeSlashMenuConfig: SlashMenuConfig = {
items: [
{
name: 'YouTube',
description: 'Embed a YouTube video.',
icon: YoutubeDuotoneIcon(),
tooltip: {
figure: YoutubeVideoTooltip,
caption: 'YouTube Video',
},
group: '4_Content & Media@5',
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-youtube'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'YouTube',
'The added YouTube video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
if (model.text?.length === 0) std.store.deleteBlock(model);
})().catch(console.error);
},
},
],
};
@@ -1,4 +1,5 @@
import { html } from 'lit';
// prettier-ignore
export const YoutubeVideoTooltip = html`<svg width="170" height="106" viewBox="0 0 170 106" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g clip-path="url(#clip0_1_2)">
@@ -1,5 +1,6 @@
import { EmbedYoutubeBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
import {
BlockServiceIdentifier,
BlockViewExtension,
@@ -10,6 +11,7 @@ import { literal } from 'lit/static-html.js';
import { createBuiltinToolbarConfigForExternal } from '../configs/toolbar';
import { EmbedYoutubeBlockAdapterExtensions } from './adapters/extension';
import { embedYoutubeSlashMenuConfig } from './configs/slash-menu';
import { EmbedYoutubeBlockComponent } from './embed-youtube-block';
import {
EmbedYoutubeBlockOptionConfig,
@@ -32,4 +34,5 @@ export const EmbedYoutubeBlockSpec: ExtensionType[] = [
id: BlockServiceIdentifier(flavour),
config: createBuiltinToolbarConfigForExternal(EmbedYoutubeBlockComponent),
}),
SlashMenuConfigExtension('affine:embed-youtube', embedYoutubeSlashMenuConfig),
].flat();
@@ -12,6 +12,7 @@
{ "path": "../model" },
{ "path": "../rich-text" },
{ "path": "../shared" },
{ "path": "../widget-slash-menu" },
{ "path": "../../framework/block-std" },
{ "path": "../../framework/global" },
{ "path": "../../framework/inline" },
@@ -13,7 +13,6 @@
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-embed": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-block-surface-ref": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
@@ -1,6 +1,5 @@
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
import { insertSurfaceRefBlockCommand } from '@blocksuite/affine-block-surface-ref';
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
import { toast } from '@blocksuite/affine-components/toast';
import type {
FrameBlockModel,
@@ -19,25 +18,21 @@ import {
CopyIcon,
DeleteIcon,
DualLinkIcon,
FigmaDuotoneIcon,
FrameIcon,
GithubDuotoneIcon,
GroupingIcon,
LinkedPageIcon,
LoomLogoDuotoneIcon,
NowIcon,
PlusIcon,
TodayIcon,
TomorrowIcon,
YesterdayIcon,
YoutubeDuotoneIcon,
} from '@blocksuite/icons/lit';
import type { DeltaInsert } from '@blocksuite/inline';
import { Slice, Text } from '@blocksuite/store';
import { slashMenuToolTips } from './tooltips';
import type { SlashMenuActionItem, SlashMenuConfig } from './types';
import { formatDate, formatTime, tryRemoveEmptyLine } from './utils';
import { formatDate, formatTime } from './utils';
// TODO(@L-Sun): This counter temporarily added variables for refactoring.
let index = 0;
@@ -107,117 +102,6 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
},
},
// ---------------------------------------------------------
// { groupName: 'Content & Media' },
{
name: 'YouTube',
description: 'Embed a YouTube video.',
icon: YoutubeDuotoneIcon(),
tooltip: slashMenuToolTips['YouTube'],
group: `4_Content & Media@${index++}`,
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-youtube'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'YouTube',
'The added YouTube video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
tryRemoveEmptyLine(model);
})().catch(console.error);
},
},
{
name: 'GitHub',
description: 'Link to a GitHub repository.',
icon: GithubDuotoneIcon(),
tooltip: slashMenuToolTips['Github'],
group: `4_Content & Media@${index++}`,
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-github'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'GitHub',
'The added GitHub issue or pull request link will be displayed as a card view.',
{ mode: 'page', parentModel, index }
);
tryRemoveEmptyLine(model);
})().catch(console.error);
},
},
// TODO: X Twitter
{
name: 'Figma',
description: 'Embed a Figma document.',
icon: FigmaDuotoneIcon(),
tooltip: slashMenuToolTips['Figma'],
group: `4_Content & Media@${index++}`,
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-figma'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'Figma',
'The added Figma link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
tryRemoveEmptyLine(model);
})().catch(console.error);
},
},
{
name: 'Loom',
icon: LoomLogoDuotoneIcon(),
group: `4_Content & Media@${index++}`,
when: ({ model }) =>
model.doc.schema.flavourSchemaMap.has('affine:embed-loom'),
action: ({ std, model }) => {
(async () => {
const { host } = std;
const parentModel = host.doc.getParent(model);
if (!parentModel) {
return;
}
const index = parentModel.children.indexOf(model) + 1;
await toggleEmbedCardCreateModal(
host,
'Loom',
'The added Loom video link will be displayed as an embed view.',
{ mode: 'page', parentModel, index }
);
tryRemoveEmptyLine(model);
})().catch(console.error);
},
},
// TODO(@L-Sun): Linear
// ---------------------------------------------------------
({ std, model }) => {
const { host } = std;
@@ -2,9 +2,6 @@ import type { SlashMenuTooltip } from '../types';
import { CopyTooltip } from './copy';
import { DeleteTooltip } from './delete';
import { EdgelessTooltip } from './edgeless';
import { FigmaTooltip } from './figma';
import { GithubRepoTooltip } from './github-repo';
import { LinearTooltip } from './linear';
import { LinkDocTooltip } from './link-doc';
import { MoveDownTooltip } from './move-down';
import { MoveUpTooltip } from './move-up';
@@ -12,9 +9,7 @@ import { NewDocTooltip } from './new-doc';
import { NowTooltip } from './now';
import { TodayTooltip } from './today';
import { TomorrowTooltip } from './tomorrow';
import { TweetTooltip } from './tweet';
import { YesterdayTooltip } from './yesterday';
import { YoutubeVideoTooltip } from './youtube-video';
export const slashMenuToolTips: Record<string, SlashMenuTooltip> = {
'New Doc': {
@@ -27,31 +22,6 @@ export const slashMenuToolTips: Record<string, SlashMenuTooltip> = {
caption: 'Link Doc',
},
Github: {
figure: GithubRepoTooltip,
caption: 'GitHub Repo',
},
YouTube: {
figure: YoutubeVideoTooltip,
caption: 'YouTube Video',
},
'X (Twitter)': {
figure: TweetTooltip,
caption: 'Tweet',
},
Figma: {
figure: FigmaTooltip,
caption: 'Figma',
},
Linear: {
figure: LinearTooltip,
caption: 'Linear',
},
Today: {
figure: TodayTooltip,
caption: 'Today',
File diff suppressed because one or more lines are too long
@@ -1,5 +1,3 @@
import type { BlockModel } from '@blocksuite/store';
import type {
SlashMenuActionItem,
SlashMenuConfig,
@@ -84,12 +82,6 @@ export function mergeSlashMenuConfigs(
};
}
export function tryRemoveEmptyLine(model: BlockModel) {
if (model.text?.length === 0) {
model.doc.deleteBlock(model);
}
}
export function formatDate(date: Date) {
// yyyy-mm-dd
const year = date.getFullYear();
@@ -7,7 +7,6 @@
},
"include": ["./src"],
"references": [
{ "path": "../block-embed" },
{ "path": "../block-surface" },
{ "path": "../block-surface-ref" },
{ "path": "../components" },
+1 -1
View File
@@ -142,6 +142,7 @@ export const PackageList = [
'blocksuite/affine/model',
'blocksuite/affine/rich-text',
'blocksuite/affine/shared',
'blocksuite/affine/widget-slash-menu',
'blocksuite/framework/block-std',
'blocksuite/framework/global',
'blocksuite/framework/inline',
@@ -494,7 +495,6 @@ export const PackageList = [
location: 'blocksuite/affine/widget-slash-menu',
name: '@blocksuite/affine-widget-slash-menu',
workspaceDependencies: [
'blocksuite/affine/block-embed',
'blocksuite/affine/block-surface',
'blocksuite/affine/block-surface-ref',
'blocksuite/affine/components',
+1 -1
View File
@@ -2426,6 +2426,7 @@ __metadata:
"@blocksuite/affine-model": "workspace:*"
"@blocksuite/affine-rich-text": "workspace:*"
"@blocksuite/affine-shared": "workspace:*"
"@blocksuite/affine-widget-slash-menu": "workspace:*"
"@blocksuite/block-std": "workspace:*"
"@blocksuite/global": "workspace:*"
"@blocksuite/icons": "npm:^2.2.1"
@@ -3039,7 +3040,6 @@ __metadata:
version: 0.0.0-use.local
resolution: "@blocksuite/affine-widget-slash-menu@workspace:blocksuite/affine/widget-slash-menu"
dependencies:
"@blocksuite/affine-block-embed": "workspace:*"
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-block-surface-ref": "workspace:*"
"@blocksuite/affine-components": "workspace:*"