refactor(editor): improve query methods in toolbar context (#10714)
This commit is contained in:
@@ -11,10 +11,8 @@ import {
|
|||||||
ActionPlacement,
|
ActionPlacement,
|
||||||
type ToolbarAction,
|
type ToolbarAction,
|
||||||
type ToolbarActionGroup,
|
type ToolbarActionGroup,
|
||||||
type ToolbarContext,
|
|
||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { BlockSelection, SurfaceSelection } from '@blocksuite/block-std';
|
|
||||||
import { Bound } from '@blocksuite/global/gfx';
|
import { Bound } from '@blocksuite/global/gfx';
|
||||||
import {
|
import {
|
||||||
CaptionIcon,
|
CaptionIcon,
|
||||||
@@ -25,7 +23,6 @@ import {
|
|||||||
EditIcon,
|
EditIcon,
|
||||||
ResetIcon,
|
ResetIcon,
|
||||||
} from '@blocksuite/icons/lit';
|
} from '@blocksuite/icons/lit';
|
||||||
import type { SelectionConstructor } from '@blocksuite/store';
|
|
||||||
import { flip, offset } from '@floating-ui/dom';
|
import { flip, offset } from '@floating-ui/dom';
|
||||||
import { computed } from '@preact/signals-core';
|
import { computed } from '@preact/signals-core';
|
||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
@@ -44,101 +41,95 @@ const trackBaseProps = {
|
|||||||
type: 'card view',
|
type: 'card view',
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAttachmentViewDropdownMenuWith = <T extends SelectionConstructor>(
|
export const attachmentViewDropdownMenu = {
|
||||||
t: T
|
id: 'b.conversions',
|
||||||
) => {
|
actions: [
|
||||||
return {
|
{
|
||||||
id: 'b.conversions',
|
id: 'card',
|
||||||
actions: [
|
label: 'Card view',
|
||||||
{
|
run(ctx) {
|
||||||
id: 'card',
|
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||||
label: 'Card view',
|
if (!model) return;
|
||||||
run(ctx) {
|
|
||||||
const model = ctx.getCurrentModelByType(t, AttachmentBlockModel);
|
|
||||||
if (!model) return;
|
|
||||||
|
|
||||||
const style = defaultAttachmentProps.style!;
|
const style = defaultAttachmentProps.style!;
|
||||||
const width = EMBED_CARD_WIDTH[style];
|
const width = EMBED_CARD_WIDTH[style];
|
||||||
const height = EMBED_CARD_HEIGHT[style];
|
const height = EMBED_CARD_HEIGHT[style];
|
||||||
const bound = Bound.deserialize(model.xywh);
|
const bound = Bound.deserialize(model.xywh);
|
||||||
bound.w = width;
|
bound.w = width;
|
||||||
bound.h = height;
|
bound.h = height;
|
||||||
|
|
||||||
ctx.store.updateBlock(model, {
|
ctx.store.updateBlock(model, {
|
||||||
style,
|
style,
|
||||||
embed: false,
|
embed: false,
|
||||||
xywh: bound.serialize(),
|
xywh: bound.serialize(),
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'embed',
|
|
||||||
label: 'Embed view',
|
|
||||||
run(ctx) {
|
|
||||||
const model = ctx.getCurrentModelByType(t, AttachmentBlockModel);
|
|
||||||
if (!model) return;
|
|
||||||
|
|
||||||
// Clears
|
|
||||||
ctx.reset();
|
|
||||||
ctx.select('note');
|
|
||||||
|
|
||||||
ctx.std.get(AttachmentEmbedProvider).convertTo(model);
|
|
||||||
|
|
||||||
ctx.track('SelectedView', {
|
|
||||||
...trackBaseProps,
|
|
||||||
control: 'select view',
|
|
||||||
type: 'embed view',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
content(ctx) {
|
|
||||||
const model = ctx.getCurrentModelByType(t, AttachmentBlockModel);
|
|
||||||
if (!model) return null;
|
|
||||||
|
|
||||||
const embedProvider = ctx.std.get(AttachmentEmbedProvider);
|
|
||||||
const actions = this.actions.map(action => ({ ...action }));
|
|
||||||
const viewType$ = computed(() => {
|
|
||||||
const [cardAction, embedAction] = actions;
|
|
||||||
const embed = model.props.embed$.value ?? false;
|
|
||||||
|
|
||||||
cardAction.disabled = !embed;
|
|
||||||
embedAction.disabled = embed && embedProvider.embedded(model);
|
|
||||||
|
|
||||||
return embed ? embedAction.label : cardAction.label;
|
|
||||||
});
|
|
||||||
const toggle = (e: CustomEvent<boolean>) => {
|
|
||||||
const opened = e.detail;
|
|
||||||
if (!opened) return;
|
|
||||||
|
|
||||||
ctx.track('OpenedViewSelector', {
|
|
||||||
...trackBaseProps,
|
|
||||||
control: 'switch view',
|
|
||||||
});
|
});
|
||||||
};
|
},
|
||||||
|
|
||||||
return html`${keyed(
|
|
||||||
model,
|
|
||||||
html`<affine-view-dropdown-menu
|
|
||||||
.actions=${actions}
|
|
||||||
.context=${ctx}
|
|
||||||
.toggle=${toggle}
|
|
||||||
.viewType$=${viewType$}
|
|
||||||
></affine-view-dropdown-menu>`
|
|
||||||
)}`;
|
|
||||||
},
|
},
|
||||||
} satisfies ToolbarActionGroup<ToolbarAction>;
|
{
|
||||||
};
|
id: 'embed',
|
||||||
|
label: 'Embed view',
|
||||||
|
run(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||||
|
if (!model) return;
|
||||||
|
|
||||||
|
// Clears
|
||||||
|
ctx.reset();
|
||||||
|
ctx.select('note');
|
||||||
|
|
||||||
|
ctx.std.get(AttachmentEmbedProvider).convertTo(model);
|
||||||
|
|
||||||
|
ctx.track('SelectedView', {
|
||||||
|
...trackBaseProps,
|
||||||
|
control: 'select view',
|
||||||
|
type: 'embed view',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
content(ctx) {
|
||||||
|
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
|
const embedProvider = ctx.std.get(AttachmentEmbedProvider);
|
||||||
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
|
const viewType$ = computed(() => {
|
||||||
|
const [cardAction, embedAction] = actions;
|
||||||
|
const embed = model.props.embed$.value ?? false;
|
||||||
|
|
||||||
|
cardAction.disabled = !embed;
|
||||||
|
embedAction.disabled = embed && embedProvider.embedded(model);
|
||||||
|
|
||||||
|
return embed ? embedAction.label : cardAction.label;
|
||||||
|
});
|
||||||
|
const toggle = (e: CustomEvent<boolean>) => {
|
||||||
|
const opened = e.detail;
|
||||||
|
if (!opened) return;
|
||||||
|
|
||||||
|
ctx.track('OpenedViewSelector', {
|
||||||
|
...trackBaseProps,
|
||||||
|
control: 'switch view',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return html`${keyed(
|
||||||
|
model,
|
||||||
|
html`<affine-view-dropdown-menu
|
||||||
|
.actions=${actions}
|
||||||
|
.context=${ctx}
|
||||||
|
.toggle=${toggle}
|
||||||
|
.viewType$=${viewType$}
|
||||||
|
></affine-view-dropdown-menu>`
|
||||||
|
)}`;
|
||||||
|
},
|
||||||
|
} satisfies ToolbarActionGroup<ToolbarAction>;
|
||||||
|
|
||||||
export const builtinToolbarConfig = {
|
export const builtinToolbarConfig = {
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
id: 'a.rename',
|
id: 'a.rename',
|
||||||
content(cx) {
|
content(cx) {
|
||||||
const component = cx.getCurrentBlockComponentBy(
|
const block = cx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||||
AttachmentBlockComponent
|
if (!block) return null;
|
||||||
);
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
abortController.signal.onabort = () => cx.show();
|
abortController.signal.onabort = () => cx.show();
|
||||||
@@ -152,12 +143,12 @@ export const builtinToolbarConfig = {
|
|||||||
|
|
||||||
createLitPortal({
|
createLitPortal({
|
||||||
template: RenameModal({
|
template: RenameModal({
|
||||||
model: component.model,
|
model: block.model,
|
||||||
editorHost: cx.host,
|
editorHost: cx.host,
|
||||||
abortController,
|
abortController,
|
||||||
}),
|
}),
|
||||||
computePosition: {
|
computePosition: {
|
||||||
referenceElement: component,
|
referenceElement: block,
|
||||||
placement: 'top-start',
|
placement: 'top-start',
|
||||||
middleware: [flip(), offset(4)],
|
middleware: [flip(), offset(4)],
|
||||||
},
|
},
|
||||||
@@ -170,16 +161,14 @@ export const builtinToolbarConfig = {
|
|||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
createAttachmentViewDropdownMenuWith(BlockSelection),
|
attachmentViewDropdownMenu,
|
||||||
{
|
{
|
||||||
id: 'c.download',
|
id: 'c.download',
|
||||||
tooltip: 'Download',
|
tooltip: 'Download',
|
||||||
icon: DownloadIcon(),
|
icon: DownloadIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||||
AttachmentBlockComponent
|
block?.download();
|
||||||
);
|
|
||||||
component?.download();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -187,10 +176,8 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||||
AttachmentBlockComponent
|
block?.captionEditor?.show();
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -208,10 +195,8 @@ export const builtinToolbarConfig = {
|
|||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
// TODO(@fundon): unify `clone` method
|
// TODO(@fundon): unify `clone` method
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||||
AttachmentBlockComponent
|
block?.copy();
|
||||||
);
|
|
||||||
component?.copy();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -219,9 +204,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockComponentBy(
|
const model = ctx.getCurrentModelByType(AttachmentBlockModel);
|
||||||
AttachmentBlockComponent
|
|
||||||
)?.model;
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
// TODO(@fundon): unify `duplicate` method
|
// TODO(@fundon): unify `duplicate` method
|
||||||
@@ -241,10 +224,8 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
icon: ResetIcon(),
|
icon: ResetIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(AttachmentBlockComponent);
|
||||||
AttachmentBlockComponent
|
block?.refreshData();
|
||||||
);
|
|
||||||
component?.refreshData();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -257,7 +238,7 @@ export const builtinToolbarConfig = {
|
|||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentModel();
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model.id);
|
||||||
|
|
||||||
// Clears
|
// Clears
|
||||||
ctx.select('note');
|
ctx.select('note');
|
||||||
@@ -266,7 +247,3 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as const satisfies ToolbarModuleConfig;
|
} as const satisfies ToolbarModuleConfig;
|
||||||
|
|
||||||
export const attachmentViewDropdownMenu = (ctx: ToolbarContext) => {
|
|
||||||
return createAttachmentViewDropdownMenuWith(SurfaceSelection).content(ctx);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ export const builtinToolbarConfig = {
|
|||||||
{
|
{
|
||||||
id: 'a.preview',
|
id: 'a.preview',
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -57,10 +54,7 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'inline',
|
id: 'inline',
|
||||||
label: 'Inline view',
|
label: 'Inline view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { title, caption, url } = model.props;
|
const { title, caption, url } = model.props;
|
||||||
@@ -98,10 +92,7 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'embed',
|
id: 'embed',
|
||||||
label: 'Embed view',
|
label: 'Embed view',
|
||||||
disabled(ctx) {
|
disabled(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return true;
|
if (!model) return true;
|
||||||
|
|
||||||
const url = model.props.url;
|
const url = model.props.url;
|
||||||
@@ -121,10 +112,7 @@ export const builtinToolbarConfig = {
|
|||||||
return !canEmbedAsIframe && options?.viewType !== 'embed';
|
return !canEmbedAsIframe && options?.viewType !== 'embed';
|
||||||
},
|
},
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { caption, url, style } = model.props;
|
const { caption, url, style } = model.props;
|
||||||
@@ -189,10 +177,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({ ...action }));
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
@@ -230,10 +215,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
BlockSelection,
|
|
||||||
BookmarkBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({
|
const actions = this.actions.map(action => ({
|
||||||
@@ -275,10 +257,8 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(BookmarkBlockComponent);
|
||||||
BookmarkBlockComponent
|
block?.captionEditor?.show();
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -295,7 +275,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -310,7 +290,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -328,10 +308,8 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
icon: ResetIcon(),
|
icon: ResetIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(BookmarkBlockComponent);
|
||||||
BookmarkBlockComponent
|
block?.refreshData();
|
||||||
);
|
|
||||||
component?.refreshData();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -341,7 +319,7 @@ export const builtinToolbarConfig = {
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
{
|
{
|
||||||
id: 'a.preview',
|
id: 'a.preview',
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return null;
|
if (!model || !isExternalEmbedModel(model)) return null;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -72,7 +72,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
id: 'inline',
|
id: 'inline',
|
||||||
label: 'Inline view',
|
label: 'Inline view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
const { title, caption, url: link } = model.props;
|
const { title, caption, url: link } = model.props;
|
||||||
@@ -105,7 +105,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
id: 'card',
|
id: 'card',
|
||||||
label: 'Card view',
|
label: 'Card view',
|
||||||
disabled(ctx) {
|
disabled(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return true;
|
if (!model || !isExternalEmbedModel(model)) return true;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -116,7 +116,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
return options?.viewType === 'card';
|
return options?.viewType === 'card';
|
||||||
},
|
},
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
const { url, caption } = model.props;
|
const { url, caption } = model.props;
|
||||||
@@ -165,7 +165,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
id: 'embed',
|
id: 'embed',
|
||||||
label: 'Embed view',
|
label: 'Embed view',
|
||||||
disabled(ctx) {
|
disabled(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return false;
|
if (!model || !isExternalEmbedModel(model)) return false;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -176,7 +176,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
return options?.viewType === 'embed';
|
return options?.viewType === 'embed';
|
||||||
},
|
},
|
||||||
when(ctx) {
|
when(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return false;
|
if (!model || !isExternalEmbedModel(model)) return false;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -187,7 +187,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
return options?.viewType === 'embed';
|
return options?.viewType === 'embed';
|
||||||
},
|
},
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
const { url, caption } = model.props;
|
const { url, caption } = model.props;
|
||||||
@@ -231,7 +231,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModel();
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return null;
|
if (!model || !isExternalEmbedModel(model)) return null;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -277,10 +277,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedGithubModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedGithubModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({
|
const actions = this.actions.map(action => ({
|
||||||
@@ -322,10 +319,8 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(klass);
|
const block = ctx.getCurrentBlockByType(klass);
|
||||||
if (!component) return;
|
block?.captionEditor?.show();
|
||||||
|
|
||||||
component.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -342,7 +337,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -357,7 +352,7 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -375,8 +370,8 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
icon: ResetIcon(),
|
icon: ResetIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(klass);
|
const block = ctx.getCurrentBlockByType(klass);
|
||||||
component?.refreshData();
|
block?.refreshData();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -386,10 +381,10 @@ export function createBuiltinToolbarConfigForExternal(
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model || !isExternalEmbedModel(model)) return;
|
if (!model || !isExternalEmbedModel(model)) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model.id);
|
||||||
|
|
||||||
// Clears
|
// Clears
|
||||||
ctx.select('note');
|
ctx.select('note');
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockSelection } from '@blocksuite/block-std';
|
|
||||||
import {
|
import {
|
||||||
CaptionIcon,
|
CaptionIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
@@ -36,10 +35,8 @@ export const builtinToolbarConfig = {
|
|||||||
icon: ExpandFullIcon(),
|
icon: ExpandFullIcon(),
|
||||||
tooltip: 'Open this doc',
|
tooltip: 'Open this doc',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedHtmlBlockComponent);
|
||||||
EmbedHtmlBlockComponent
|
block?.open();
|
||||||
);
|
|
||||||
component?.open();
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,7 +52,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(BlockSelection, EmbedHtmlModel);
|
const model = ctx.getCurrentModelByType(EmbedHtmlModel);
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map<ToolbarAction>(action => ({
|
const actions = this.actions.map<ToolbarAction>(action => ({
|
||||||
@@ -97,10 +94,8 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedHtmlBlockComponent);
|
||||||
EmbedHtmlBlockComponent
|
block?.captionEditor?.show();
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -117,7 +112,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedHtmlModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -132,7 +127,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedHtmlModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -151,7 +146,7 @@ export const builtinToolbarConfig = {
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedHtmlModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model);
|
||||||
|
|||||||
@@ -40,10 +40,7 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'inline',
|
id: 'inline',
|
||||||
label: 'Inline view',
|
label: 'Inline view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedIframeBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { title, caption, url } = model.props;
|
const { title, caption, url } = model.props;
|
||||||
@@ -76,10 +73,7 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'card',
|
id: 'card',
|
||||||
label: 'Card view',
|
label: 'Card view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedIframeBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { url, caption } = model.props;
|
const { url, caption } = model.props;
|
||||||
@@ -119,10 +113,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedIframeBlockModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({ ...action }));
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
@@ -152,9 +143,7 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
|
||||||
EmbedIframeBlockComponent
|
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
component?.captionEditor?.show();
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
@@ -172,7 +161,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockBy(BlockSelection)?.model;
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -187,7 +176,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockBy(BlockSelection)?.model;
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -205,9 +194,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
icon: ResetIcon(),
|
icon: ResetIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const component = ctx.getCurrentBlockByType(EmbedIframeBlockComponent);
|
||||||
EmbedIframeBlockComponent
|
|
||||||
);
|
|
||||||
component?.refreshData().catch(console.error);
|
component?.refreshData().catch(console.error);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -218,7 +205,7 @@ export const builtinToolbarConfig = {
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockBy(BlockSelection)?.model;
|
const model = ctx.getCurrentModelByType(EmbedIframeBlockModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
getBlockProps,
|
getBlockProps,
|
||||||
referenceToNode,
|
referenceToNode,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockSelection } from '@blocksuite/block-std';
|
|
||||||
import {
|
import {
|
||||||
CaptionIcon,
|
CaptionIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
@@ -37,12 +36,10 @@ export const builtinToolbarConfig = {
|
|||||||
{
|
{
|
||||||
id: 'a.doc-title',
|
id: 'a.doc-title',
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedLinkedDocBlockComponent);
|
||||||
EmbedLinkedDocBlockComponent
|
if (!block) return null;
|
||||||
);
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
const model = component.model;
|
const model = block.model;
|
||||||
if (!model.props.title) return null;
|
if (!model.props.title) return null;
|
||||||
|
|
||||||
const originalTitle =
|
const originalTitle =
|
||||||
@@ -50,7 +47,7 @@ export const builtinToolbarConfig = {
|
|||||||
|
|
||||||
return html`<affine-linked-doc-title
|
return html`<affine-linked-doc-title
|
||||||
.title=${originalTitle}
|
.title=${originalTitle}
|
||||||
.open=${(event: MouseEvent) => component.open({ event })}
|
.open=${(event: MouseEvent) => block.open({ event })}
|
||||||
></affine-linked-doc-title>`;
|
></affine-linked-doc-title>`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -61,10 +58,10 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'inline',
|
id: 'inline',
|
||||||
label: 'Inline view',
|
label: 'Inline view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedLinkedDocBlockComponent
|
EmbedLinkedDocBlockComponent
|
||||||
);
|
);
|
||||||
component?.covertToInline();
|
block?.covertToInline();
|
||||||
|
|
||||||
// Clears
|
// Clears
|
||||||
ctx.select('note');
|
ctx.select('note');
|
||||||
@@ -86,14 +83,14 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'embed',
|
id: 'embed',
|
||||||
label: 'Embed view',
|
label: 'Embed view',
|
||||||
disabled(ctx) {
|
disabled(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedLinkedDocBlockComponent
|
EmbedLinkedDocBlockComponent
|
||||||
);
|
);
|
||||||
if (!component) return true;
|
if (!block) return true;
|
||||||
|
|
||||||
if (component.closest('affine-embed-synced-doc-block')) return true;
|
if (block.closest('affine-embed-synced-doc-block')) return true;
|
||||||
|
|
||||||
const model = component.model;
|
const model = block.model;
|
||||||
|
|
||||||
// same doc
|
// same doc
|
||||||
if (model.props.pageId === ctx.store.id) return true;
|
if (model.props.pageId === ctx.store.id) return true;
|
||||||
@@ -104,10 +101,10 @@ export const builtinToolbarConfig = {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedLinkedDocBlockComponent
|
EmbedLinkedDocBlockComponent
|
||||||
);
|
);
|
||||||
component?.convertToEmbed();
|
block?.convertToEmbed();
|
||||||
|
|
||||||
ctx.track('SelectedView', {
|
ctx.track('SelectedView', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -118,10 +115,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedLinkedDocModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({ ...action }));
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
@@ -159,10 +153,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedLinkedDocModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({
|
const actions = this.actions.map(action => ({
|
||||||
@@ -203,10 +194,8 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedLinkedDocBlockComponent);
|
||||||
EmbedLinkedDocBlockComponent
|
block?.captionEditor?.show();
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
|
||||||
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -223,7 +212,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -238,7 +227,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -257,7 +246,7 @@ export const builtinToolbarConfig = {
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
type ToolbarModuleConfig,
|
type ToolbarModuleConfig,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
import { getBlockProps } from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockSelection } from '@blocksuite/block-std';
|
|
||||||
import {
|
import {
|
||||||
ArrowDownSmallIcon,
|
ArrowDownSmallIcon,
|
||||||
CaptionIcon,
|
CaptionIcon,
|
||||||
@@ -49,10 +48,8 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedSyncedDocBlockComponent);
|
||||||
EmbedSyncedDocBlockComponent
|
if (!block) return null;
|
||||||
);
|
|
||||||
if (!component) return null;
|
|
||||||
|
|
||||||
const actions = this.actions
|
const actions = this.actions
|
||||||
.map<ToolbarAction>(action => {
|
.map<ToolbarAction>(action => {
|
||||||
@@ -64,11 +61,11 @@ export const builtinToolbarConfig = {
|
|||||||
return {
|
return {
|
||||||
...action,
|
...action,
|
||||||
disabled: shouldOpenInActiveView
|
disabled: shouldOpenInActiveView
|
||||||
? component.model.props.pageId === ctx.store.id
|
? block.model.props.pageId === ctx.store.id
|
||||||
: false,
|
: false,
|
||||||
when: allowed,
|
when: allowed,
|
||||||
run: (_ctx: ToolbarContext) =>
|
run: (_ctx: ToolbarContext) =>
|
||||||
component.open({
|
block.open({
|
||||||
openMode: action.id as OpenDocMode,
|
openMode: action.id as OpenDocMode,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -115,10 +112,10 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'inline',
|
id: 'inline',
|
||||||
label: 'Inline view',
|
label: 'Inline view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedSyncedDocBlockComponent
|
EmbedSyncedDocBlockComponent
|
||||||
);
|
);
|
||||||
component?.covertToInline();
|
block?.covertToInline();
|
||||||
|
|
||||||
// Clears
|
// Clears
|
||||||
ctx.select('note');
|
ctx.select('note');
|
||||||
@@ -135,10 +132,10 @@ export const builtinToolbarConfig = {
|
|||||||
id: 'card',
|
id: 'card',
|
||||||
label: 'Card view',
|
label: 'Card view',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedSyncedDocBlockComponent
|
EmbedSyncedDocBlockComponent
|
||||||
);
|
);
|
||||||
component?.convertToCard();
|
block?.convertToCard();
|
||||||
|
|
||||||
ctx.track('SelectedView', {
|
ctx.track('SelectedView', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
@@ -154,10 +151,7 @@ export const builtinToolbarConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedSyncedDocModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedSyncedDocModel
|
|
||||||
);
|
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
|
||||||
const actions = this.actions.map(action => ({ ...action }));
|
const actions = this.actions.map(action => ({ ...action }));
|
||||||
@@ -188,10 +182,8 @@ export const builtinToolbarConfig = {
|
|||||||
tooltip: 'Caption',
|
tooltip: 'Caption',
|
||||||
icon: CaptionIcon(),
|
icon: CaptionIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(EmbedSyncedDocBlockComponent);
|
||||||
EmbedSyncedDocBlockComponent
|
block?.captionEditor?.show();
|
||||||
);
|
|
||||||
component?.captionEditor?.show();
|
|
||||||
ctx.track('OpenedCaptionEditor', {
|
ctx.track('OpenedCaptionEditor', {
|
||||||
...trackBaseProps,
|
...trackBaseProps,
|
||||||
control: 'add caption',
|
control: 'add caption',
|
||||||
@@ -207,7 +199,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedSyncedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const slice = Slice.fromModels(ctx.store, [model]);
|
const slice = Slice.fromModels(ctx.store, [model]);
|
||||||
@@ -222,7 +214,7 @@ export const builtinToolbarConfig = {
|
|||||||
label: 'Duplicate',
|
label: 'Duplicate',
|
||||||
icon: DuplicateIcon(),
|
icon: DuplicateIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedSyncedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { flavour, parent } = model;
|
const { flavour, parent } = model;
|
||||||
@@ -241,7 +233,7 @@ export const builtinToolbarConfig = {
|
|||||||
icon: DeleteIcon(),
|
icon: DeleteIcon(),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelByType(EmbedSyncedDocModel);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
ctx.store.deleteBlock(model);
|
ctx.store.deleteBlock(model);
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export class EdgelessChangeAttachmentButton extends WithDisposable(LitElement) {
|
|||||||
`,
|
`,
|
||||||
|
|
||||||
// TODO(@fundon): should remove it when refactoring the element toolbar
|
// TODO(@fundon): should remove it when refactoring the element toolbar
|
||||||
attachmentViewDropdownMenu(new ToolbarContext(this.std)),
|
attachmentViewDropdownMenu.content(new ToolbarContext(this.std)),
|
||||||
|
|
||||||
html`
|
html`
|
||||||
<editor-icon-button
|
<editor-icon-button
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import type { Placement } from '@floating-ui/dom';
|
import type { Placement } from '@floating-ui/dom';
|
||||||
|
|
||||||
import type { ToolbarActions } from './action';
|
import type { ToolbarActions } from './action';
|
||||||
|
import type { ToolbarContext } from './context';
|
||||||
|
|
||||||
export type ToolbarModuleConfig = {
|
export type ToolbarModuleConfig = {
|
||||||
actions: ToolbarActions;
|
actions: ToolbarActions;
|
||||||
|
|
||||||
|
when?: ((ctx: ToolbarContext) => boolean) | boolean;
|
||||||
|
|
||||||
placement?: Extract<Placement, 'top' | 'top-start'>;
|
placement?: Extract<Placement, 'top' | 'top-start'>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ import {
|
|||||||
type BlockStdScope,
|
type BlockStdScope,
|
||||||
SurfaceSelection,
|
SurfaceSelection,
|
||||||
} from '@blocksuite/block-std';
|
} from '@blocksuite/block-std';
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
import {
|
||||||
|
GfxControllerIdentifier,
|
||||||
|
type GfxElementModelView,
|
||||||
|
type GfxModel,
|
||||||
|
} from '@blocksuite/block-std/gfx';
|
||||||
import { nextTick } from '@blocksuite/global/utils';
|
import { nextTick } from '@blocksuite/global/utils';
|
||||||
import type {
|
import type {
|
||||||
BaseSelection,
|
BaseSelection,
|
||||||
Block,
|
BlockModel,
|
||||||
SelectionConstructor,
|
SelectionConstructor,
|
||||||
} from '@blocksuite/store';
|
} from '@blocksuite/store';
|
||||||
|
|
||||||
import { matchModels } from '../../utils';
|
|
||||||
import { DocModeProvider } from '../doc-mode-service';
|
import { DocModeProvider } from '../doc-mode-service';
|
||||||
import { TelemetryProvider, type TelemetryService } from '../telemetry-service';
|
import { TelemetryProvider, type TelemetryService } from '../telemetry-service';
|
||||||
import { ThemeProvider } from '../theme-service';
|
import { ThemeProvider } from '../theme-service';
|
||||||
@@ -106,60 +109,99 @@ abstract class ToolbarContextBase {
|
|||||||
return this.toolbarRegistry.flags;
|
return this.toolbarRegistry.flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get flavour$() {
|
||||||
|
return this.toolbarRegistry.flavour$;
|
||||||
|
}
|
||||||
|
|
||||||
get message$() {
|
get message$() {
|
||||||
return this.toolbarRegistry.message$;
|
return this.toolbarRegistry.message$;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentElement() {
|
get elementsMap$() {
|
||||||
const selection = this.selection.find(SurfaceSelection);
|
return this.toolbarRegistry.elementsMap$;
|
||||||
return selection?.elements.length
|
|
||||||
? this.gfx.getElementById(selection.elements[0])
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentBlock(): Block | null {
|
get hasSelectedSurfaceModels() {
|
||||||
return this.getCurrentBlockBy();
|
return (
|
||||||
|
this.flavour$.peek().includes('surface') &&
|
||||||
|
this.elementsMap$.peek().size > 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentBlockComponent(): BlockComponent | null {
|
getSurfaceElementsByType<M extends abstract new (...args: any) => any>(
|
||||||
|
klass: M
|
||||||
|
) {
|
||||||
|
if (this.hasSelectedSurfaceModels) {
|
||||||
|
const elements = this.elementsMap$.peek().get(this.flavour$.peek());
|
||||||
|
if (elements?.length) {
|
||||||
|
return elements.filter(e => this.matchModel(e, klass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentBlockBy<T extends SelectionConstructor>(type: T) {
|
||||||
|
const selection = this.selection.find(type);
|
||||||
|
if (!selection) return null;
|
||||||
|
if (selection.is(SurfaceSelection)) {
|
||||||
|
const elementId = selection.elements[0];
|
||||||
|
const model = this.gfx.getElementById(elementId);
|
||||||
|
if (!model) return null;
|
||||||
|
return this.gfx.view.get(model.id) ?? null;
|
||||||
|
}
|
||||||
|
const model = this.store.getBlock(selection.blockId);
|
||||||
|
if (!model) return null;
|
||||||
|
return this.view.getBlock(model.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentBlock() {
|
||||||
|
return this.hasSelectedSurfaceModels
|
||||||
|
? this.getCurrentBlockBy(SurfaceSelection)
|
||||||
|
: this.getCurrentBlockBy(BlockSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentBlockByType<K extends abstract new (...args: any) => any>(
|
||||||
|
klass: K
|
||||||
|
) {
|
||||||
const block = this.getCurrentBlock();
|
const block = this.getCurrentBlock();
|
||||||
return block && this.view.getBlock(block.id);
|
return this.matchBlock(block, klass) ? block : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentModel() {
|
matchBlock<K extends abstract new (...args: any) => any>(
|
||||||
return this.getCurrentBlock()?.model ?? null;
|
component: GfxElementModelView | BlockComponent | null,
|
||||||
}
|
klass: K
|
||||||
|
): component is InstanceType<K> {
|
||||||
getCurrentBlockBy<T extends SelectionConstructor>(type?: T): Block | null {
|
return component instanceof klass;
|
||||||
const selection = this.selection.find(type ?? BlockSelection);
|
|
||||||
return (selection && this.store.getBlock(selection.blockId)) ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentModelBy<T extends SelectionConstructor>(type: T) {
|
getCurrentModelBy<T extends SelectionConstructor>(type: T) {
|
||||||
return this.getCurrentBlockBy<T>(type)?.model ?? null;
|
const selection = this.selection.find(type);
|
||||||
|
if (!selection) return null;
|
||||||
|
if (selection.is(SurfaceSelection)) {
|
||||||
|
const elementId = selection.elements[0];
|
||||||
|
return elementId ? this.gfx.getElementById(elementId) : null;
|
||||||
|
}
|
||||||
|
return this.store.getBlock(selection.blockId)?.model ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentModelByType<
|
getCurrentModel() {
|
||||||
T extends SelectionConstructor,
|
return this.hasSelectedSurfaceModels
|
||||||
M extends Parameters<typeof matchModels>[1][number],
|
? this.getCurrentModelBy(SurfaceSelection)
|
||||||
>(type: T, klass: M) {
|
: this.getCurrentModelBy(BlockSelection);
|
||||||
const model = this.getCurrentModelBy(type);
|
|
||||||
return matchModels(model, [klass]) ? model : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentBlockComponentBy<K extends abstract new (...args: any) => any>(
|
getCurrentModelByType<M extends abstract new (...args: any) => any>(
|
||||||
|
klass: M
|
||||||
|
) {
|
||||||
|
const model = this.getCurrentModel();
|
||||||
|
return this.matchModel(model, klass) ? model : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchModel<K extends abstract new (...args: any) => any>(
|
||||||
|
model: GfxModel | BlockModel | null,
|
||||||
klass: K
|
klass: K
|
||||||
): InstanceType<K> | null {
|
): model is InstanceType<K> {
|
||||||
const block = this.getCurrentBlockBy();
|
return model instanceof klass;
|
||||||
const component = block && this.view.getBlock(block.id);
|
|
||||||
return this.blockComponentIs(component, klass) ? component : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockComponentIs<K extends abstract new (...args: any) => any>(
|
|
||||||
component: BlockComponent | null,
|
|
||||||
...classes: K[]
|
|
||||||
): component is InstanceType<K> {
|
|
||||||
return classes.some(k => component instanceof k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select(group: string, selections: BaseSelection[] = []) {
|
select(group: string, selections: BaseSelection[] = []) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { type BlockStdScope, StdIdentifier } from '@blocksuite/block-std';
|
import { type BlockStdScope, StdIdentifier } from '@blocksuite/block-std';
|
||||||
|
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
||||||
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
||||||
import { Extension, type ExtensionType } from '@blocksuite/store';
|
import { Extension, type ExtensionType } from '@blocksuite/store';
|
||||||
import { signal } from '@preact/signals-core';
|
import { signal } from '@preact/signals-core';
|
||||||
@@ -22,12 +23,16 @@ export function ToolbarModuleExtension(module: ToolbarModule): ExtensionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ToolbarRegistryExtension extends Extension {
|
export class ToolbarRegistryExtension extends Extension {
|
||||||
|
flavour$ = signal<string>('affine:note');
|
||||||
|
|
||||||
message$ = signal<{
|
message$ = signal<{
|
||||||
flavour: string;
|
flavour: string;
|
||||||
element: Element;
|
element: Element;
|
||||||
setFloating: (element?: Element) => void;
|
setFloating: (element?: Element) => void;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
|
elementsMap$ = signal<Map<string, GfxModel[]>>(new Map());
|
||||||
|
|
||||||
flags = new Flags();
|
flags = new Flags();
|
||||||
|
|
||||||
constructor(readonly std: BlockStdScope) {
|
constructor(readonly std: BlockStdScope) {
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
flavour$ = signal('affine:note');
|
|
||||||
|
|
||||||
placement$ = signal<Placement>('top');
|
placement$ = signal<Placement>('top');
|
||||||
|
|
||||||
sideOptions$ = signal<Partial<SideObject> | null>(null);
|
sideOptions$ = signal<Partial<SideObject> | null>(null);
|
||||||
@@ -139,7 +137,6 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
flavour$,
|
|
||||||
placement$,
|
placement$,
|
||||||
sideOptions$,
|
sideOptions$,
|
||||||
referenceElement$,
|
referenceElement$,
|
||||||
@@ -149,7 +146,7 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
host,
|
host,
|
||||||
std,
|
std,
|
||||||
} = this;
|
} = this;
|
||||||
const { flags, message$ } = toolbarRegistry;
|
const { flags, elementsMap$, flavour$, message$ } = toolbarRegistry;
|
||||||
const context = new ToolbarContext(std);
|
const context = new ToolbarContext(std);
|
||||||
|
|
||||||
// TODO(@fundon): fix toolbar position shaking when the wheel scrolls
|
// TODO(@fundon): fix toolbar position shaking when the wheel scrolls
|
||||||
@@ -303,6 +300,7 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
let elements: GfxModel[] = [];
|
let elements: GfxModel[] = [];
|
||||||
let hasLocked = false;
|
let hasLocked = false;
|
||||||
let sideOptions = null;
|
let sideOptions = null;
|
||||||
|
let paired: [string, GfxModel[]][] = [];
|
||||||
|
|
||||||
if (activated && surface) {
|
if (activated && surface) {
|
||||||
elements = elementIds
|
elements = elementIds
|
||||||
@@ -326,7 +324,10 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
e => e.flavour
|
e => e.flavour
|
||||||
);
|
);
|
||||||
|
|
||||||
const paired = toPairs(grouped);
|
paired = toPairs(grouped).map(([flavour, items]) => [
|
||||||
|
flavour,
|
||||||
|
items.map(({ model }) => model),
|
||||||
|
]);
|
||||||
|
|
||||||
if (paired.length === 1) {
|
if (paired.length === 1) {
|
||||||
flavour = paired[0][0];
|
flavour = paired[0][0];
|
||||||
@@ -350,6 +351,8 @@ export class AffineToolbarWidget extends WidgetComponent {
|
|||||||
batch(() => {
|
batch(() => {
|
||||||
flags.toggle(Flag.Surface, activated);
|
flags.toggle(Flag.Surface, activated);
|
||||||
|
|
||||||
|
elementsMap$.value = new Map(paired);
|
||||||
|
|
||||||
if (!activated || !flavour) return;
|
if (!activated || !flavour) return;
|
||||||
|
|
||||||
this.setReferenceElementWithElements(gfx, elements);
|
this.setReferenceElementWithElements(gfx, elements);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const sideMap = new Map([
|
|||||||
['affine:surface:frame', { top: 28 }],
|
['affine:surface:frame', { top: 28 }],
|
||||||
// includes group element
|
// includes group element
|
||||||
['affine:surface:group', { top: 20 }],
|
['affine:surface:group', { top: 20 }],
|
||||||
// only one shape element
|
// has only one shape element
|
||||||
['affine:surface:shape', { top: 26, bottom: -26 }],
|
['affine:surface:shape', { top: 26, bottom: -26 }],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -196,6 +196,11 @@ export function renderToolbar(
|
|||||||
.flat()
|
.flat()
|
||||||
.map(key => toolbarRegistry.modules.get(key))
|
.map(key => toolbarRegistry.modules.get(key))
|
||||||
.filter(module => !!module)
|
.filter(module => !!module)
|
||||||
|
.filter(module =>
|
||||||
|
typeof module.config.when === 'function'
|
||||||
|
? module.config.when(context)
|
||||||
|
: (module.config.when ?? true)
|
||||||
|
)
|
||||||
.map<ToolbarActions>(module => module.config.actions)
|
.map<ToolbarActions>(module => module.config.actions)
|
||||||
.flat();
|
.flat();
|
||||||
|
|
||||||
@@ -220,7 +225,7 @@ export function renderToolbar(
|
|||||||
);
|
);
|
||||||
// if (moreMenuItems.length) {
|
// if (moreMenuItems.length) {
|
||||||
// TODO(@fundon): edgeless case needs to be considered
|
// TODO(@fundon): edgeless case needs to be considered
|
||||||
const key = `${context.getCurrentModel()?.id ?? context.getCurrentElement()?.id}`;
|
const key = `${context.getCurrentModel()?.id}`;
|
||||||
|
|
||||||
primaryActionGroup.push({
|
primaryActionGroup.push({
|
||||||
id: 'more',
|
id: 'more',
|
||||||
|
|||||||
@@ -313,33 +313,34 @@ function createToolbarMoreMenuConfigV2(baseUrl?: string) {
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
id: 'block-meta-display',
|
id: 'block-meta-display',
|
||||||
when: cx => {
|
when: ctx => {
|
||||||
const featureFlag = cx.std.get(FeatureFlagService);
|
const featureFlag = ctx.std.get(FeatureFlagService);
|
||||||
const isEnabled = featureFlag.getFlag('enable_block_meta');
|
const isEnabled = featureFlag.getFlag('enable_block_meta');
|
||||||
if (!isEnabled) return false;
|
if (!isEnabled) return false;
|
||||||
|
|
||||||
// only display when one block is selected by block selection
|
// only display when one block is selected by block selection
|
||||||
const { selection, getCurrentBlockBy } = cx;
|
|
||||||
const hasBlockSelection =
|
const hasBlockSelection =
|
||||||
selection.filter(BlockSelection).length === 1;
|
ctx.selection.filter(BlockSelection).length === 1;
|
||||||
if (!hasBlockSelection) return false;
|
if (!hasBlockSelection) return false;
|
||||||
const block = getCurrentBlockBy.call(cx, BlockSelection);
|
const model = ctx.getCurrentModelBy(BlockSelection);
|
||||||
if (!block) return false;
|
if (!model) return false;
|
||||||
|
|
||||||
const createdAt = 'meta:createdAt';
|
const createdAt = 'meta:createdAt';
|
||||||
const createdBy = 'meta:createdBy';
|
const createdBy = 'meta:createdBy';
|
||||||
return (
|
return (
|
||||||
createdAt in block.model.props &&
|
'props' in model &&
|
||||||
block.model.props[createdAt] !== undefined &&
|
createdAt in model.props &&
|
||||||
createdBy in block.model.props &&
|
model.props[createdAt] !== undefined &&
|
||||||
block.model.props[createdBy] !== undefined &&
|
createdBy in model.props &&
|
||||||
typeof block.model.props[createdBy] === 'string' &&
|
model.props[createdBy] !== undefined &&
|
||||||
typeof block.model.props[createdAt] === 'number'
|
typeof model.props[createdBy] === 'string' &&
|
||||||
|
typeof model.props[createdAt] === 'number'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
content: cx => {
|
content: ctx => {
|
||||||
const model = cx.getCurrentModelBy(BlockSelection);
|
const model = ctx.getCurrentModelBy(BlockSelection);
|
||||||
if (!model) return null;
|
if (!model) return null;
|
||||||
|
if (!('props' in model)) return null;
|
||||||
const createdAt = 'meta:createdAt';
|
const createdAt = 'meta:createdAt';
|
||||||
if (!(createdAt in model.props)) return null;
|
if (!(createdAt in model.props)) return null;
|
||||||
const createdBy = 'meta:createdBy';
|
const createdBy = 'meta:createdBy';
|
||||||
@@ -347,7 +348,7 @@ function createToolbarMoreMenuConfigV2(baseUrl?: string) {
|
|||||||
const createdByUserId = model.props[createdBy] as string;
|
const createdByUserId = model.props[createdBy] as string;
|
||||||
const createdAtTimestamp = model.props[createdAt] as number;
|
const createdAtTimestamp = model.props[createdAt] as number;
|
||||||
const date = new Date(createdAtTimestamp);
|
const date = new Date(createdAtTimestamp);
|
||||||
const userProvider = cx.std.get(UserProvider);
|
const userProvider = ctx.std.get(UserProvider);
|
||||||
userProvider.revalidateUserInfo(createdByUserId);
|
userProvider.revalidateUserInfo(createdByUserId);
|
||||||
const userSignal = userProvider.userInfo$(createdByUserId);
|
const userSignal = userProvider.userInfo$(createdByUserId);
|
||||||
const isLoadingSignal = userProvider.isLoading$(createdByUserId);
|
const isLoadingSignal = userProvider.isLoading$(createdByUserId);
|
||||||
@@ -415,7 +416,7 @@ function createExternalLinkableToolbarConfig(
|
|||||||
tooltip: 'Copy link',
|
tooltip: 'Copy link',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockComponentBy(klass)?.model;
|
const model = ctx.getCurrentBlockByType(klass)?.model;
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { url } = model.props;
|
const { url } = model.props;
|
||||||
@@ -440,12 +441,12 @@ function createExternalLinkableToolbarConfig(
|
|||||||
tooltip: 'Edit',
|
tooltip: 'Edit',
|
||||||
icon: EditIcon(),
|
icon: EditIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(klass);
|
const block = ctx.getCurrentBlockByType(klass);
|
||||||
if (!component) return;
|
if (!block) return;
|
||||||
|
|
||||||
ctx.hide();
|
ctx.hide();
|
||||||
|
|
||||||
const model = component.model;
|
const model = block.model;
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
abortController.signal.onabort = () => ctx.show();
|
abortController.signal.onabort = () => ctx.show();
|
||||||
|
|
||||||
@@ -457,7 +458,7 @@ function createExternalLinkableToolbarConfig(
|
|||||||
undefined,
|
undefined,
|
||||||
(_std, _component, props) => {
|
(_std, _component, props) => {
|
||||||
ctx.store.updateBlock(model, props);
|
ctx.store.updateBlock(model, props);
|
||||||
component.requestUpdate();
|
block.requestUpdate();
|
||||||
},
|
},
|
||||||
abortController
|
abortController
|
||||||
);
|
);
|
||||||
@@ -514,8 +515,8 @@ function createOpenDocActionGroup(
|
|||||||
id: 'A.open-doc',
|
id: 'A.open-doc',
|
||||||
actions: openDocActions,
|
actions: openDocActions,
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(klass);
|
const block = ctx.getCurrentBlockByType(klass);
|
||||||
if (!component) return null;
|
if (!block) return null;
|
||||||
|
|
||||||
const actions = this.actions
|
const actions = this.actions
|
||||||
.map<ToolbarAction>(action => {
|
.map<ToolbarAction>(action => {
|
||||||
@@ -528,15 +529,14 @@ function createOpenDocActionGroup(
|
|||||||
return {
|
return {
|
||||||
...action,
|
...action,
|
||||||
disabled: shouldOpenInActiveView
|
disabled: shouldOpenInActiveView
|
||||||
? component.model.props.pageId === ctx.store.id
|
? block.model.props.pageId === ctx.store.id
|
||||||
: false,
|
: false,
|
||||||
when:
|
when:
|
||||||
allowed &&
|
allowed && (shouldOpenInCenterPeek ? isPeekable(block) : true),
|
||||||
(shouldOpenInCenterPeek ? isPeekable(component) : true),
|
|
||||||
run: shouldOpenInCenterPeek
|
run: shouldOpenInCenterPeek
|
||||||
? (_ctx: ToolbarContext) => peek(component)
|
? (_ctx: ToolbarContext) => peek(block)
|
||||||
: (_ctx: ToolbarContext) =>
|
: (_ctx: ToolbarContext) =>
|
||||||
component.open({
|
block.open({
|
||||||
openMode: action.id as OpenDocMode,
|
openMode: action.id as OpenDocMode,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -589,10 +589,7 @@ const embedLinkedDocToolbarConfig = {
|
|||||||
tooltip: 'Copy link',
|
tooltip: 'Copy link',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedLinkedDocModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedLinkedDocModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { pageId, params } = model.props;
|
const { pageId, params } = model.props;
|
||||||
@@ -621,21 +618,21 @@ const embedLinkedDocToolbarConfig = {
|
|||||||
tooltip: 'Edit',
|
tooltip: 'Edit',
|
||||||
icon: EditIcon(),
|
icon: EditIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedLinkedDocBlockComponent
|
EmbedLinkedDocBlockComponent
|
||||||
);
|
);
|
||||||
if (!component) return;
|
if (!block) return;
|
||||||
|
|
||||||
ctx.hide();
|
ctx.hide();
|
||||||
|
|
||||||
const model = component.model;
|
const model = block.model;
|
||||||
const doc = ctx.workspace.getDoc(model.props.pageId);
|
const doc = ctx.workspace.getDoc(model.props.pageId);
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
abortController.signal.onabort = () => ctx.show();
|
abortController.signal.onabort = () => ctx.show();
|
||||||
|
|
||||||
toggleEmbedCardEditModal(
|
toggleEmbedCardEditModal(
|
||||||
ctx.host,
|
ctx.host,
|
||||||
component.model,
|
model,
|
||||||
'card',
|
'card',
|
||||||
doc
|
doc
|
||||||
? {
|
? {
|
||||||
@@ -644,12 +641,12 @@ const embedLinkedDocToolbarConfig = {
|
|||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
std => {
|
std => {
|
||||||
component.refreshData();
|
block.refreshData();
|
||||||
notifyLinkedDocClearedAliases(std);
|
notifyLinkedDocClearedAliases(std);
|
||||||
},
|
},
|
||||||
(_std, _component, props) => {
|
(_std, _component, props) => {
|
||||||
ctx.store.updateBlock(model, props);
|
ctx.store.updateBlock(model, props);
|
||||||
component.requestUpdate();
|
block.requestUpdate();
|
||||||
},
|
},
|
||||||
abortController
|
abortController
|
||||||
);
|
);
|
||||||
@@ -681,10 +678,7 @@ const embedSyncedDocToolbarConfig = {
|
|||||||
tooltip: 'Copy link',
|
tooltip: 'Copy link',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentModelByType(
|
const model = ctx.getCurrentModelByType(EmbedSyncedDocModel);
|
||||||
BlockSelection,
|
|
||||||
EmbedSyncedDocModel
|
|
||||||
);
|
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const { pageId, params } = model.props;
|
const { pageId, params } = model.props;
|
||||||
@@ -713,14 +707,14 @@ const embedSyncedDocToolbarConfig = {
|
|||||||
tooltip: 'Edit',
|
tooltip: 'Edit',
|
||||||
icon: EditIcon(),
|
icon: EditIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const block = ctx.getCurrentBlockByType(
|
||||||
EmbedSyncedDocBlockComponent
|
EmbedSyncedDocBlockComponent
|
||||||
);
|
);
|
||||||
if (!component) return;
|
if (!block) return;
|
||||||
|
|
||||||
ctx.hide();
|
ctx.hide();
|
||||||
|
|
||||||
const model = component.model;
|
const model = block.model;
|
||||||
const doc = ctx.workspace.getDoc(model.props.pageId);
|
const doc = ctx.workspace.getDoc(model.props.pageId);
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
abortController.signal.onabort = () => ctx.show();
|
abortController.signal.onabort = () => ctx.show();
|
||||||
@@ -732,7 +726,7 @@ const embedSyncedDocToolbarConfig = {
|
|||||||
doc ? { title: doc.meta?.title } : undefined,
|
doc ? { title: doc.meta?.title } : undefined,
|
||||||
undefined,
|
undefined,
|
||||||
(std, _component, props) => {
|
(std, _component, props) => {
|
||||||
component.convertToCard(props);
|
block.convertToCard(props);
|
||||||
|
|
||||||
notifyLinkedDocSwitchedToCard(std);
|
notifyLinkedDocSwitchedToCard(std);
|
||||||
},
|
},
|
||||||
@@ -761,8 +755,7 @@ const inlineReferenceToolbarConfig = {
|
|||||||
id: 'A.open-doc',
|
id: 'A.open-doc',
|
||||||
actions: openDocActions,
|
actions: openDocActions,
|
||||||
content(ctx) {
|
content(ctx) {
|
||||||
const registry = ctx.toolbarRegistry;
|
const target = ctx.message$.peek()?.element;
|
||||||
const target = registry.message$.peek()?.element;
|
|
||||||
if (!(target instanceof AffineReference)) return null;
|
if (!(target instanceof AffineReference)) return null;
|
||||||
|
|
||||||
const actions = this.actions
|
const actions = this.actions
|
||||||
@@ -917,7 +910,7 @@ const embedIframeToolbarConfig = {
|
|||||||
tooltip: 'Copy link',
|
tooltip: 'Copy link',
|
||||||
icon: CopyIcon(),
|
icon: CopyIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const model = ctx.getCurrentBlockComponentBy(
|
const model = ctx.getCurrentBlockByType(
|
||||||
EmbedIframeBlockComponent
|
EmbedIframeBlockComponent
|
||||||
)?.model;
|
)?.model;
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
@@ -928,9 +921,6 @@ const embedIframeToolbarConfig = {
|
|||||||
toast(ctx.host, 'Copied link to clipboard');
|
toast(ctx.host, 'Copied link to clipboard');
|
||||||
|
|
||||||
ctx.track('CopiedLink', {
|
ctx.track('CopiedLink', {
|
||||||
segment: 'doc',
|
|
||||||
page: 'doc editor',
|
|
||||||
module: 'toolbar',
|
|
||||||
category: matchModels(model, [BookmarkBlockModel])
|
category: matchModels(model, [BookmarkBlockModel])
|
||||||
? 'bookmark'
|
? 'bookmark'
|
||||||
: 'link',
|
: 'link',
|
||||||
@@ -944,7 +934,7 @@ const embedIframeToolbarConfig = {
|
|||||||
tooltip: 'Edit',
|
tooltip: 'Edit',
|
||||||
icon: EditIcon(),
|
icon: EditIcon(),
|
||||||
run(ctx) {
|
run(ctx) {
|
||||||
const component = ctx.getCurrentBlockComponentBy(
|
const component = ctx.getCurrentBlockByType(
|
||||||
EmbedIframeBlockComponent
|
EmbedIframeBlockComponent
|
||||||
);
|
);
|
||||||
if (!component) return;
|
if (!component) return;
|
||||||
@@ -969,9 +959,6 @@ const embedIframeToolbarConfig = {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.track('OpenedAliasPopup', {
|
ctx.track('OpenedAliasPopup', {
|
||||||
segment: 'doc',
|
|
||||||
page: 'doc editor',
|
|
||||||
module: 'toolbar',
|
|
||||||
category: matchModels(model, [BookmarkBlockModel])
|
category: matchModels(model, [BookmarkBlockModel])
|
||||||
? 'bookmark'
|
? 'bookmark'
|
||||||
: 'link',
|
: 'link',
|
||||||
|
|||||||
Reference in New Issue
Block a user