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 Jan 28, 2025
1 parent b5270e5 commit 68f9b9e
Show file tree
Hide file tree
Showing 45 changed files with 1,975 additions and 88 deletions.
24 changes: 18 additions & 6 deletions blocksuite/affine/block-attachment/src/attachment-spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
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 { AttachmentBlockNotionHtmlAdapterExtension } from './adapters/notion-html';
import {
AttachmentBlockService,
AttachmentDropOption,
} from './attachment-service.js';
} from './attachment-service';
import { builtinToolbarConfig } from './configs/toolbar';
import {
AttachmentEmbedConfigExtension,
AttachmentEmbedService,
} from './embed.js';
} from './embed';

const Flavour = 'affine:attachment';

export const AttachmentBlockSpec: ExtensionType[] = [
FlavourExtension('affine:attachment'),
FlavourExtension(Flavour),
AttachmentBlockService,
BlockViewExtension('affine:attachment', model => {
BlockViewExtension(Flavour, model => {
return model.parent?.flavour === 'affine:surface'
? literal`affine-edgeless-attachment`
: literal`affine-attachment`;
Expand All @@ -24,4 +32,8 @@ export const AttachmentBlockSpec: ExtensionType[] = [
AttachmentEmbedConfigExtension(),
AttachmentEmbedService,
AttachmentBlockNotionHtmlAdapterExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier(Flavour),
config: builtinToolbarConfig,
}),
];
155 changes: 155 additions & 0 deletions blocksuite/affine/block-attachment/src/configs/toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { AttachmentBlockSchema } from '@blocksuite/affine-model';
import {
ActionPlacement,
type ToolbarAction,
type ToolbarActionGroup,
type ToolbarModuleConfig,
} from '@blocksuite/affine-shared/services';
import { BlockSelection } from '@blocksuite/block-std';
import {
ArrowDownSmallIcon,
CaptionIcon,
CopyIcon,
DeleteIcon,
DownloadIcon,
DuplicateIcon,
EditIcon,
ResetIcon,
} from '@blocksuite/icons/lit';
import { html } from 'lit';
import { repeat } from 'lit/directives/repeat.js';
import { styleMap } from 'lit/directives/style-map.js';

// 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) {},
},
{
id: 'embed-view',
label: 'Embed view',
run(_cx) {},
},
],
content(cx) {
const model = cx.getFirstBlockModelBy(
BlockSelection,
AttachmentBlockSchema
);
if (!model) return null;

const { embed } = model;
const viewType = embed ? 'embed' : 'card';
const embeded = true;
// const embedded = cx.std.get(AttachmentEmbedProvider)
// .embedded(model, )

return html`
<editor-menu-button
.contentPadding="${'8px'}"
.button=${html`
<editor-icon-button
aria-label="Switch view"
.justify="${'space-between'}"
.labelHeight="${'20px'}"
.iconContainerWidth="${'110px'}"
>
<span
class="label"
style=${styleMap({ textTransform: 'capitalize' })}
>${viewType} view</span
>
${ArrowDownSmallIcon()}
</editor-icon-button>
`}
>
<div data-size="small" data-orientation="vertical">
${repeat(
this.actions,
action => action.id,
({ id, label, run }) => html`
<editor-menu-action
aria-label=${label}
data-testid=${`link-to-${id}`}
?data-selected=${id.startsWith(viewType)}
?disabled="${id.startsWith('embed') && embeded};"
@click=${() => run?.(cx)}
>
${label}
</editor-menu-action>
`
)}
</div>
</editor-menu-button>
`;
},
} satisfies ToolbarActionGroup<ToolbarAction>,
{
id: 'download',
tooltip: 'Download',
icon: DownloadIcon(),
run(_cx) {},
},
{
id: 'caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(_cx) {},
},
{
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) {},
},
],
},
{
id: 'delete',
placement: ActionPlacement.More,
actions: [
{
id: 'delete',
label: 'Delete',
icon: DeleteIcon(),
run(_cx) {},
},
],
},
],
} as const satisfies ToolbarModuleConfig;
17 changes: 13 additions & 4 deletions blocksuite/affine/block-bookmark/src/bookmark-spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import {
BlockFlavourIdentifier,
BlockViewExtension,
CommandExtension,
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 { commands } from './commands/index.js';
import { BookmarkBlockAdapterExtensions } from './adapters/extension';
import { commands } from './commands/index';
import { builtinToolbarConfig } from './configs/toolbar';

const Flavour = 'affine:bookmark';

export const BookmarkBlockSpec: ExtensionType[] = [
FlavourExtension('affine:bookmark'),
FlavourExtension(Flavour),
CommandExtension(commands),
BlockViewExtension('affine:bookmark', model => {
BlockViewExtension(Flavour, model => {
return model.parent?.flavour === 'affine:surface'
? literal`affine-edgeless-bookmark`
: literal`affine-bookmark`;
}),
BookmarkBlockAdapterExtensions,
ToolbarModuleExtension({
id: BlockFlavourIdentifier(Flavour),
config: builtinToolbarConfig,
}),
].flat();
118 changes: 118 additions & 0 deletions blocksuite/affine/block-bookmark/src/configs/toolbar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
import {
ActionPlacement,
type ToolbarActionGroup,
type ToolbarModuleConfig,
} from '@blocksuite/affine-shared/services';
import { getHostName } from '@blocksuite/affine-shared/utils';
import { BlockSelection } from '@blocksuite/block-std';
import {
CaptionIcon,
CopyIcon,
DeleteIcon,
DuplicateIcon,
PaletteIcon,
ResetIcon,
} from '@blocksuite/icons/lit';
import { html } from 'lit';

export const builtinToolbarConfig = {
actions: [
{
id: 'preview',
content(cx) {
const model = cx.getFirstBlockModelBy(
BlockSelection,
BookmarkBlockSchema
);
if (!model) return null;

const { url } = model;

return html`
<a
class="affine-link-preview"
rel="noopener noreferrer"
target="_blank"
href=${url}
>
<span>${getHostName(url)}</span>
</a>
`;
},
},
{
id: 'conversions',
actions: [
{
id: 'inline-view',
label: 'Inline view',
run(_cx) {},
},
{
id: 'card-view',
label: 'Card view',
run(_cx) {},
},
],
content(_cx) {
this.actions;
return null;
},
} satisfies ToolbarActionGroup,
{
id: 'style',
tooltip: 'Card style',
icon: PaletteIcon(),
run(_cx) {},
},
{
id: 'caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(_cx) {},
},
{
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) {},
},
],
},
{
id: 'delete',
placement: ActionPlacement.More,
actions: [
{
id: 'delete',
label: 'Delete',
icon: DeleteIcon(),
run(_cx) {},
},
],
},
],
} as const satisfies ToolbarModuleConfig;
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
import { EmbedFigmaBlockSchema } from '@blocksuite/affine-model';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import {
BlockServiceIdentifier,
BlockViewExtension,
FlavourExtension,
} from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store';
import { literal } from 'lit/static-html.js';

import { EmbedFigmaBlockAdapterExtensions } from './adapters/extension.js';
import { EmbedFigmaBlockService } from './embed-figma-service.js';
import { builtinToolbarConfigForExternal } from '../configs/toolbar';
import { EmbedFigmaBlockAdapterExtensions } from './adapters/extension';
import { EmbedFigmaBlockService } from './embed-figma-service';

const flavour = EmbedFigmaBlockSchema.model.flavour as BlockSuite.Flavour;

export const EmbedFigmaBlockSpec: ExtensionType[] = [
FlavourExtension('affine:embed-figma'),
FlavourExtension(flavour),
EmbedFigmaBlockService,
BlockViewExtension('affine:embed-figma', model => {
BlockViewExtension(flavour, model => {
return model.parent?.flavour === 'affine:surface'
? literal`affine-embed-edgeless-figma-block`
: literal`affine-embed-figma-block`;
}),
EmbedFigmaBlockAdapterExtensions,
ToolbarModuleExtension({
id: BlockServiceIdentifier(flavour),
config: builtinToolbarConfigForExternal,
}),
].flat();
Loading

0 comments on commit 68f9b9e

Please sign in to comment.