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:
@@ -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')};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user