feat(editor): update embed iframe toolbar config (#11221)

part of [BS-2843](https://linear.app/affine-design/issue/BS-2843/iframe-embed-block-占位态)
This commit is contained in:
donteatfriedrice
2025-03-27 04:17:30 +00:00
parent e763061bd6
commit 0c73fde44a
3 changed files with 104 additions and 94 deletions

View File

@@ -102,7 +102,7 @@ export class EmbedIframeLinkInputPopup extends EmbedIframeLinkInputBase {
outline: none; outline: none;
} }
.link-input::placeholder { .link-input::placeholder {
color: var(--affine-placeholder-color); color: ${unsafeCSSVarV2('text/placeholder')};
} }
} }

View File

@@ -24,30 +24,77 @@ import {
CopyIcon, CopyIcon,
DeleteIcon, DeleteIcon,
DuplicateIcon, DuplicateIcon,
LinkedPageIcon,
OpenInNewIcon,
ResetIcon, ResetIcon,
} from '@blocksuite/icons/lit'; } from '@blocksuite/icons/lit';
import { type ExtensionType, Slice, Text } from '@blocksuite/store'; import {
type ExtensionType,
Slice,
Text,
toDraftModel,
} from '@blocksuite/store';
import { computed, signal } from '@preact/signals-core'; import { computed, signal } from '@preact/signals-core';
import { html } from 'lit'; import { html } from 'lit';
import { keyed } from 'lit/directives/keyed.js'; import { keyed } from 'lit/directives/keyed.js';
import * as Y from 'yjs'; import * as Y from 'yjs';
import {
convertSelectedBlocksToLinkedDoc,
getTitleFromSelectedModels,
notifyDocCreated,
promptDocTitle,
} from '../../common/render-linked-doc';
import { EmbedIframeBlockComponent } from '../embed-iframe-block'; import { EmbedIframeBlockComponent } from '../embed-iframe-block';
const trackBaseProps = { const trackBaseProps = {
category: 'embed iframe block', category: 'embed iframe block',
}; };
const showWhenUrlExists = (ctx: ToolbarContext) => {
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
if (!model) return false;
return !!model.props.url;
};
const openLinkAction = (id: string): ToolbarAction => {
return {
id,
when: showWhenUrlExists,
tooltip: 'Original',
icon: OpenInNewIcon(),
run(ctx) {
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
component?.open();
},
};
};
const captionAction = (id: string): ToolbarAction => {
return {
id,
when: showWhenUrlExists,
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
component?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
};
};
export const builtinToolbarConfig = { export const builtinToolbarConfig = {
actions: [ actions: [
openLinkAction('a.open-link'),
{ {
id: 'b.conversions', id: 'c.conversions',
when: (ctx: ToolbarContext) => { when: showWhenUrlExists,
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
if (!model) return false;
return !!model.props.url;
},
actions: [ actions: [
{ {
id: 'inline', id: 'inline',
@@ -155,24 +202,48 @@ export const builtinToolbarConfig = {
)}`; )}`;
}, },
} satisfies ToolbarActionGroup<ToolbarAction>, } satisfies ToolbarActionGroup<ToolbarAction>,
captionAction('d.caption'),
{ {
id: 'c.caption', id: 'e.convert-to-linked-doc',
when: (ctx: ToolbarContext) => { tooltip: 'Create Linked Doc',
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel); icon: LinkedPageIcon(),
if (!model) return false;
return !!model.props.url;
},
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) { run(ctx) {
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent); const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
component?.captionEditor?.show(); if (!model) return;
ctx.track('OpenedCaptionEditor', { const { store, std, selection, track } = ctx;
...trackBaseProps, selection.clear();
control: 'add caption',
}); const draftedModels = [model].map(toDraftModel);
const autofill = getTitleFromSelectedModels(draftedModels);
promptDocTitle(std, autofill)
.then(async title => {
if (title === null) return;
await convertSelectedBlocksToLinkedDoc(
std,
store,
draftedModels,
title
);
notifyDocCreated(std, store);
track('DocCreated', {
segment: 'doc',
page: 'doc editor',
module: 'toolbar',
control: 'create linked doc',
type: 'embed-linked-doc',
});
track('LinkedDocCreated', {
segment: 'doc',
page: 'doc editor',
module: 'toolbar',
control: 'create linked doc',
type: 'embed-linked-doc',
});
})
.catch(console.error);
}, },
}, },
{ {
@@ -243,14 +314,10 @@ export const builtinToolbarConfig = {
export const builtinSurfaceToolbarConfig = { export const builtinSurfaceToolbarConfig = {
actions: [ actions: [
openLinkAction('a.open-link'),
{ {
id: 'b.conversions', id: 'c.conversions',
when: (ctx: ToolbarContext) => { when: showWhenUrlExists,
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
if (!model) return false;
return !!model.props.url;
},
actions: [ actions: [
{ {
id: 'card', id: 'card',
@@ -324,28 +391,9 @@ export const builtinSurfaceToolbarConfig = {
)}`; )}`;
}, },
} satisfies ToolbarActionGroup<ToolbarAction>, } satisfies ToolbarActionGroup<ToolbarAction>,
captionAction('d.caption'),
{ {
id: 'c.caption', id: 'e.scale',
when: (ctx: ToolbarContext) => {
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
if (!model) return false;
return !!model.props.url;
},
tooltip: 'Caption',
icon: CaptionIcon(),
run(ctx) {
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
component?.captionEditor?.show();
ctx.track('OpenedCaptionEditor', {
...trackBaseProps,
control: 'add caption',
});
},
},
{
id: 'd.scale',
content(ctx) { content(ctx) {
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel); const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
if (!model) return null; if (!model) return null;

View File

@@ -877,11 +877,11 @@ const embedIframeToolbarConfig = {
}, },
actions: [ actions: [
{ {
id: 'a.copy-link-and-edit', id: 'b.copy-link',
actions: [ actions: [
{ {
id: 'copy-link', id: 'copy-link',
tooltip: 'Copy link', tooltip: 'Copy original link',
icon: CopyIcon(), icon: CopyIcon(),
run(ctx) { run(ctx) {
const model = ctx.getCurrentBlockByType( const model = ctx.getCurrentBlockByType(
@@ -895,52 +895,14 @@ const embedIframeToolbarConfig = {
toast(ctx.host, 'Copied link to clipboard'); toast(ctx.host, 'Copied link to clipboard');
ctx.track('CopiedLink', { ctx.track('CopiedLink', {
category: matchModels(model, [BookmarkBlockModel]) category: matchModels(model, [EmbedIframeBlockModel])
? 'bookmark' ? 'embed iframe block'
: 'link', : 'link',
type: 'card view', type: 'card view',
control: 'copy link', control: 'copy link',
}); });
}, },
}, },
{
id: 'edit',
tooltip: 'Edit',
icon: EditIcon(),
run(ctx) {
const component = ctx.getCurrentBlockByType(
EmbedIframeBlockComponent
);
if (!component) return;
ctx.hide();
const model = component.model;
const abortController = new AbortController();
abortController.signal.onabort = () => ctx.show();
toggleEmbedCardEditModal(
ctx.host,
model,
'card',
undefined,
undefined,
(_std, _component, props) => {
ctx.store.updateBlock(model, props);
component.requestUpdate();
},
abortController
);
ctx.track('OpenedAliasPopup', {
category: matchModels(model, [BookmarkBlockModel])
? 'bookmark'
: 'link',
type: 'card view',
control: 'edit',
});
},
},
], ],
}, },
], ],