Files
AFFiNE-Mirror/blocksuite/affine/blocks/image/src/configs/toolbar.ts
T
L-Sun 1d865f16fe feat(editor): comment for edgeless element (#13098)
#### PR Dependency Tree


* **PR #13098** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added support for comments on graphical elements, allowing users to
comment on both blocks and graphical elements within surfaces.
* Enhanced comment previews to include graphical elements in selection
summaries.
* Improved editor navigation to focus on commented graphical elements in
addition to blocks and inline texts.

* **Bug Fixes**
* Updated comment highlighting and management to consistently use the
new comment manager across all block and element types.

* **Refactor**
* Renamed and extended the comment manager to handle both block and
element comments.
* Streamlined toolbar configurations by removing outdated comment button
entries and adding a consolidated comment button in the root toolbar.

* **Tests**
* Disabled the mock comment provider integration in the test editor
environment to refine testing setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-07-08 10:33:09 +00:00

166 lines
4.0 KiB
TypeScript

import { ImageBlockModel } from '@blocksuite/affine-model';
import {
ActionPlacement,
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import {
BookmarkIcon,
CaptionIcon,
CopyIcon,
DeleteIcon,
DownloadIcon,
DuplicateIcon,
} from '@blocksuite/icons/lit';
import { BlockFlavourIdentifier } from '@blocksuite/std';
import type { ExtensionType } from '@blocksuite/store';
import { ImageBlockComponent } from '../image-block';
import { ImageEdgelessBlockComponent } from '../image-edgeless-block';
import { duplicate } from '../utils';
const trackBaseProps = {
category: 'image',
type: 'card view',
};
const builtinToolbarConfig = {
actions: [
{
id: 'a.download',
tooltip: 'Download',
icon: DownloadIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
block?.download();
},
},
{
id: 'b.caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
block?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
},
{
placement: ActionPlacement.More,
id: 'a.clipboard',
actions: [
{
id: 'a.copy',
label: 'Copy',
icon: CopyIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
block?.copy();
},
},
{
id: 'b.duplicate',
label: 'Duplicate',
icon: DuplicateIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
if (!block) return;
duplicate(block);
},
},
],
},
{
placement: ActionPlacement.More,
id: 'b.conversions',
actions: [
{
id: 'a.turn-into-card-view',
label: 'Turn into card view',
icon: BookmarkIcon(),
when(ctx) {
const supported =
ctx.store.schema.flavourSchemaMap.has('affine:attachment');
if (!supported) return false;
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
return Boolean(block?.blobUrl);
},
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
block?.convertToCardView();
},
},
],
},
{
placement: ActionPlacement.More,
id: 'c.delete',
label: 'Delete',
icon: DeleteIcon(),
variant: 'destructive',
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageBlockComponent);
if (!block) return;
ctx.store.deleteBlock(block.model);
},
},
],
placement: 'inner',
} as const satisfies ToolbarModuleConfig;
const builtinSurfaceToolbarConfig = {
actions: [
{
id: 'a.download',
tooltip: 'Download',
icon: DownloadIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageEdgelessBlockComponent);
block?.download();
},
},
{
id: 'b.caption',
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const block = ctx.getCurrentBlockByType(ImageEdgelessBlockComponent);
block?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
},
],
when: ctx => ctx.getSurfaceModelsByType(ImageBlockModel).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,
}),
];
};