refactor(editor): surface-ref slash menu config extension (#10681)
This commit is contained in:
@@ -17,9 +17,10 @@
|
|||||||
"@blocksuite/affine-components": "workspace:*",
|
"@blocksuite/affine-components": "workspace:*",
|
||||||
"@blocksuite/affine-model": "workspace:*",
|
"@blocksuite/affine-model": "workspace:*",
|
||||||
"@blocksuite/affine-shared": "workspace:*",
|
"@blocksuite/affine-shared": "workspace:*",
|
||||||
|
"@blocksuite/affine-widget-slash-menu": "workspace:*",
|
||||||
"@blocksuite/block-std": "workspace:*",
|
"@blocksuite/block-std": "workspace:*",
|
||||||
"@blocksuite/global": "workspace:*",
|
"@blocksuite/global": "workspace:*",
|
||||||
"@blocksuite/icons": "^2.2.3",
|
"@blocksuite/icons": "^2.2.4",
|
||||||
"@blocksuite/inline": "workspace:*",
|
"@blocksuite/inline": "workspace:*",
|
||||||
"@blocksuite/store": "workspace:*",
|
"@blocksuite/store": "workspace:*",
|
||||||
"@lit/context": "^1.1.2",
|
"@lit/context": "^1.1.2",
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||||
|
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
||||||
|
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
|
||||||
|
import {
|
||||||
|
type SlashMenuActionItem,
|
||||||
|
type SlashMenuConfig,
|
||||||
|
SlashMenuConfigExtension,
|
||||||
|
} from '@blocksuite/affine-widget-slash-menu';
|
||||||
|
import { FrameIcon, GroupingIcon } from '@blocksuite/icons/lit';
|
||||||
|
|
||||||
|
import { insertSurfaceRefBlockCommand } from '../commands';
|
||||||
|
import { EdgelessTooltip } from './tooltips';
|
||||||
|
|
||||||
|
const surfaceRefSlashMenuConfig: SlashMenuConfig = {
|
||||||
|
items: ({ std }) => {
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
const surfaceModel = getSurfaceBlock(std.store);
|
||||||
|
if (!surfaceModel) return [];
|
||||||
|
|
||||||
|
const frameModels = std.store
|
||||||
|
.getBlocksByFlavour('affine:frame')
|
||||||
|
.map(block => block.model as FrameBlockModel);
|
||||||
|
|
||||||
|
const frameItems = frameModels.map<SlashMenuActionItem>(frameModel => ({
|
||||||
|
name: 'Frame: ' + frameModel.title,
|
||||||
|
icon: FrameIcon(),
|
||||||
|
group: `5_Document Group & Frame@${index++}`,
|
||||||
|
tooltip: {
|
||||||
|
figure: EdgelessTooltip,
|
||||||
|
caption: 'Edgeless',
|
||||||
|
},
|
||||||
|
action: ({ std }) => {
|
||||||
|
std.command
|
||||||
|
.chain()
|
||||||
|
.pipe(getSelectedModelsCommand)
|
||||||
|
.pipe(insertSurfaceRefBlockCommand, {
|
||||||
|
reference: frameModel.id,
|
||||||
|
place: 'after',
|
||||||
|
removeEmptyLine: true,
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const groupElements = surfaceModel.getElementsByType('group');
|
||||||
|
const groupItems = groupElements.map<SlashMenuActionItem>(group => ({
|
||||||
|
name: 'Group: ' + group.title.toString(),
|
||||||
|
icon: GroupingIcon(),
|
||||||
|
group: `5_Document Group & Frame@${index++}`,
|
||||||
|
tooltip: {
|
||||||
|
figure: EdgelessTooltip,
|
||||||
|
caption: 'Edgeless',
|
||||||
|
},
|
||||||
|
action: ({ std }) => {
|
||||||
|
std.command
|
||||||
|
.chain()
|
||||||
|
.pipe(getSelectedModelsCommand)
|
||||||
|
.pipe(insertSurfaceRefBlockCommand, {
|
||||||
|
reference: group.id,
|
||||||
|
place: 'after',
|
||||||
|
removeEmptyLine: true,
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [...frameItems, ...groupItems];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SurfaceRefSlashMenuConfigExtension = SlashMenuConfigExtension(
|
||||||
|
'affine:surface-ref',
|
||||||
|
surfaceRefSlashMenuConfig
|
||||||
|
);
|
||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
import type { ExtensionType } from '@blocksuite/store';
|
import type { ExtensionType } from '@blocksuite/store';
|
||||||
import { literal } from 'lit/static-html.js';
|
import { literal } from 'lit/static-html.js';
|
||||||
|
|
||||||
|
import { SurfaceRefSlashMenuConfigExtension } from './configs/slash-menu';
|
||||||
|
|
||||||
export const surfaceRefToolbarWidget = WidgetViewExtension(
|
export const surfaceRefToolbarWidget = WidgetViewExtension(
|
||||||
'affine:surface-ref',
|
'affine:surface-ref',
|
||||||
'surfaceToolbar',
|
'surfaceToolbar',
|
||||||
@@ -16,6 +18,7 @@ export const PageSurfaceRefBlockSpec: ExtensionType[] = [
|
|||||||
FlavourExtension('affine:surface-ref'),
|
FlavourExtension('affine:surface-ref'),
|
||||||
BlockViewExtension('affine:surface-ref', literal`affine-surface-ref`),
|
BlockViewExtension('affine:surface-ref', literal`affine-surface-ref`),
|
||||||
surfaceRefToolbarWidget,
|
surfaceRefToolbarWidget,
|
||||||
|
SurfaceRefSlashMenuConfigExtension,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const EdgelessSurfaceRefBlockSpec: ExtensionType[] = [
|
export const EdgelessSurfaceRefBlockSpec: ExtensionType[] = [
|
||||||
@@ -24,4 +27,5 @@ export const EdgelessSurfaceRefBlockSpec: ExtensionType[] = [
|
|||||||
'affine:surface-ref',
|
'affine:surface-ref',
|
||||||
literal`affine-edgeless-surface-ref`
|
literal`affine-edgeless-surface-ref`
|
||||||
),
|
),
|
||||||
|
SurfaceRefSlashMenuConfigExtension,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
{ "path": "../components" },
|
{ "path": "../components" },
|
||||||
{ "path": "../model" },
|
{ "path": "../model" },
|
||||||
{ "path": "../shared" },
|
{ "path": "../shared" },
|
||||||
|
{ "path": "../widget-slash-menu" },
|
||||||
{ "path": "../../framework/block-std" },
|
{ "path": "../../framework/block-std" },
|
||||||
{ "path": "../../framework/global" },
|
{ "path": "../../framework/global" },
|
||||||
{ "path": "../../framework/inline" },
|
{ "path": "../../framework/inline" },
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
"author": "toeverything",
|
"author": "toeverything",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blocksuite/affine-block-surface": "workspace:*",
|
|
||||||
"@blocksuite/affine-block-surface-ref": "workspace:*",
|
|
||||||
"@blocksuite/affine-components": "workspace:*",
|
"@blocksuite/affine-components": "workspace:*",
|
||||||
"@blocksuite/affine-rich-text": "workspace:*",
|
"@blocksuite/affine-rich-text": "workspace:*",
|
||||||
"@blocksuite/affine-shared": "workspace:*",
|
"@blocksuite/affine-shared": "workspace:*",
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
|
||||||
import { insertSurfaceRefBlockCommand } from '@blocksuite/affine-block-surface-ref';
|
|
||||||
import { toast } from '@blocksuite/affine-components/toast';
|
import { toast } from '@blocksuite/affine-components/toast';
|
||||||
import type {
|
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
|
||||||
FrameBlockModel,
|
|
||||||
ParagraphBlockModel,
|
|
||||||
} from '@blocksuite/affine-model';
|
|
||||||
import {
|
import {
|
||||||
getInlineEditorByModel,
|
getInlineEditorByModel,
|
||||||
insertContent,
|
insertContent,
|
||||||
} from '@blocksuite/affine-rich-text';
|
} from '@blocksuite/affine-rich-text';
|
||||||
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
|
|
||||||
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
||||||
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
||||||
import {
|
import {
|
||||||
@@ -18,8 +12,6 @@ import {
|
|||||||
CopyIcon,
|
CopyIcon,
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
DualLinkIcon,
|
DualLinkIcon,
|
||||||
FrameIcon,
|
|
||||||
GroupingIcon,
|
|
||||||
LinkedPageIcon,
|
LinkedPageIcon,
|
||||||
NowIcon,
|
NowIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
@@ -31,289 +23,228 @@ import type { DeltaInsert } from '@blocksuite/inline';
|
|||||||
import { Slice, Text } from '@blocksuite/store';
|
import { Slice, Text } from '@blocksuite/store';
|
||||||
|
|
||||||
import { slashMenuToolTips } from './tooltips';
|
import { slashMenuToolTips } from './tooltips';
|
||||||
import type { SlashMenuActionItem, SlashMenuConfig } from './types';
|
import type { SlashMenuConfig } from './types';
|
||||||
import { formatDate, formatTime } from './utils';
|
import { formatDate, formatTime } from './utils';
|
||||||
|
|
||||||
// TODO(@L-Sun): This counter temporarily added variables for refactoring.
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
export const defaultSlashMenuConfig: SlashMenuConfig = {
|
export const defaultSlashMenuConfig: SlashMenuConfig = {
|
||||||
disableWhen: ({ model }) => {
|
disableWhen: ({ model }) => {
|
||||||
return model.flavour === 'affine:code';
|
return model.flavour === 'affine:code';
|
||||||
},
|
},
|
||||||
items: ({ std, model }) => [
|
items: () => {
|
||||||
{
|
const now = new Date();
|
||||||
name: 'New Doc',
|
const tomorrow = new Date();
|
||||||
description: 'Start a new document.',
|
const yesterday = new Date();
|
||||||
icon: PlusIcon(),
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
tooltip: slashMenuToolTips['New Doc'],
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
group: `3_Page@${index++}`,
|
|
||||||
when: ({ model }) =>
|
return [
|
||||||
model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc'),
|
{
|
||||||
action: ({ std, model }) => {
|
name: 'New Doc',
|
||||||
const newDoc = createDefaultDoc(std.host.doc.workspace);
|
description: 'Start a new document.',
|
||||||
insertContent(std.host, model, REFERENCE_NODE, {
|
icon: PlusIcon(),
|
||||||
reference: {
|
tooltip: slashMenuToolTips['New Doc'],
|
||||||
type: 'LinkedPage',
|
group: '3_Page@0',
|
||||||
pageId: newDoc.id,
|
when: ({ model }) =>
|
||||||
},
|
model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc'),
|
||||||
});
|
action: ({ std, model }) => {
|
||||||
|
const newDoc = createDefaultDoc(std.host.doc.workspace);
|
||||||
|
insertContent(std.host, model, REFERENCE_NODE, {
|
||||||
|
reference: {
|
||||||
|
type: 'LinkedPage',
|
||||||
|
pageId: newDoc.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Linked Doc',
|
||||||
name: 'Linked Doc',
|
description: 'Link to another document.',
|
||||||
description: 'Link to another document.',
|
icon: LinkedPageIcon(),
|
||||||
icon: LinkedPageIcon(),
|
tooltip: slashMenuToolTips['Linked Doc'],
|
||||||
tooltip: slashMenuToolTips['Linked Doc'],
|
searchAlias: ['dual link'],
|
||||||
searchAlias: ['dual link'],
|
group: '3_Page@1',
|
||||||
group: `3_Page@${index++}`,
|
when: ({ std, model }) => {
|
||||||
when: ({ std, model }) => {
|
const root = model.doc.root;
|
||||||
const root = model.doc.root;
|
if (!root) return false;
|
||||||
if (!root) return false;
|
const linkedDocWidget = std.view.getWidget(
|
||||||
const linkedDocWidget = std.view.getWidget(
|
'affine-linked-doc-widget',
|
||||||
'affine-linked-doc-widget',
|
root.id
|
||||||
root.id
|
);
|
||||||
);
|
if (!linkedDocWidget) return false;
|
||||||
if (!linkedDocWidget) return false;
|
|
||||||
|
|
||||||
return model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc');
|
return model.doc.schema.flavourSchemaMap.has(
|
||||||
},
|
'affine:embed-linked-doc'
|
||||||
action: ({ model, std }) => {
|
);
|
||||||
const root = model.doc.root;
|
},
|
||||||
if (!root) return;
|
action: ({ model, std }) => {
|
||||||
const linkedDocWidget = std.view.getWidget(
|
const root = model.doc.root;
|
||||||
'affine-linked-doc-widget',
|
if (!root) return;
|
||||||
root.id
|
const linkedDocWidget = std.view.getWidget(
|
||||||
);
|
'affine-linked-doc-widget',
|
||||||
if (!linkedDocWidget) return;
|
root.id
|
||||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
);
|
||||||
// @ts-expect-error same as above
|
if (!linkedDocWidget) return;
|
||||||
const triggerKey = linkedDocWidget.config.triggerKeys[0];
|
|
||||||
|
|
||||||
insertContent(std.host, model, triggerKey);
|
|
||||||
|
|
||||||
const inlineEditor = getInlineEditorByModel(std.host, model);
|
|
||||||
// Wait for range to be updated
|
|
||||||
inlineEditor?.slots.inlineRangeSync.once(() => {
|
|
||||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||||
// @ts-expect-error same as above
|
// @ts-expect-error same as above
|
||||||
linkedDocWidget.show({ addTriggerKey: true });
|
const triggerKey = linkedDocWidget.config.triggerKeys[0];
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
insertContent(std.host, model, triggerKey);
|
||||||
...(() => {
|
|
||||||
const { host } = std;
|
|
||||||
|
|
||||||
const surfaceModel = getSurfaceBlock(host.doc);
|
const inlineEditor = getInlineEditorByModel(std.host, model);
|
||||||
if (!surfaceModel) return [];
|
// Wait for range to be updated
|
||||||
|
inlineEditor?.slots.inlineRangeSync.once(() => {
|
||||||
const parent = host.doc.getParent(model);
|
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||||
if (!parent) return [];
|
// @ts-expect-error same as above
|
||||||
|
linkedDocWidget.show({ addTriggerKey: true });
|
||||||
const frameModels = host.doc
|
|
||||||
.getBlocksByFlavour('affine:frame')
|
|
||||||
.map(block => block.model as FrameBlockModel);
|
|
||||||
|
|
||||||
const frameItems = frameModels.map<SlashMenuActionItem>(frameModel => ({
|
|
||||||
name: 'Frame: ' + frameModel.title,
|
|
||||||
icon: FrameIcon(),
|
|
||||||
group: `5_Document Group & Frame@${index++}`,
|
|
||||||
action: ({ std }) => {
|
|
||||||
std.command
|
|
||||||
.chain()
|
|
||||||
.pipe(getSelectedModelsCommand)
|
|
||||||
.pipe(insertSurfaceRefBlockCommand, {
|
|
||||||
reference: frameModel.id,
|
|
||||||
place: 'after',
|
|
||||||
removeEmptyLine: true,
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const groupElements = surfaceModel.getElementsByType('group');
|
|
||||||
const groupItems = groupElements.map<SlashMenuActionItem>(group => ({
|
|
||||||
name: 'Group: ' + group.title.toString(),
|
|
||||||
icon: GroupingIcon(),
|
|
||||||
group: `5_Document Group & Frame@${index++}`,
|
|
||||||
action: ({ std }) => {
|
|
||||||
std.command
|
|
||||||
.chain()
|
|
||||||
.pipe(getSelectedModelsCommand)
|
|
||||||
.pipe(insertSurfaceRefBlockCommand, {
|
|
||||||
reference: group.id,
|
|
||||||
place: 'after',
|
|
||||||
removeEmptyLine: true,
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
return [...frameItems, ...groupItems];
|
|
||||||
})(),
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
...((): SlashMenuActionItem[] => {
|
|
||||||
const now = new Date();
|
|
||||||
const tomorrow = new Date();
|
|
||||||
const yesterday = new Date();
|
|
||||||
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: 'Today',
|
|
||||||
icon: TodayIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Today'],
|
|
||||||
description: formatDate(now),
|
|
||||||
group: `6_Date@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
insertContent(std.host, model, formatDate(now));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tomorrow',
|
|
||||||
icon: TomorrowIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Tomorrow'],
|
|
||||||
description: formatDate(tomorrow),
|
|
||||||
group: `6_Date@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
const tomorrow = new Date();
|
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
||||||
insertContent(std.host, model, formatDate(tomorrow));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Yesterday',
|
|
||||||
icon: YesterdayIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Yesterday'],
|
|
||||||
description: formatDate(yesterday),
|
|
||||||
group: `6_Date@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
const yesterday = new Date();
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
insertContent(std.host, model, formatDate(yesterday));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Now',
|
|
||||||
icon: NowIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Now'],
|
|
||||||
description: formatTime(now),
|
|
||||||
group: `6_Date@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
insertContent(std.host, model, formatTime(now));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
})(),
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
// { groupName: 'Actions' },
|
|
||||||
{
|
|
||||||
name: 'Move Up',
|
|
||||||
description: 'Shift this line up.',
|
|
||||||
icon: ArrowUpBigIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Move Up'],
|
|
||||||
group: `8_Actions@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
const { host } = std;
|
|
||||||
const previousSiblingModel = host.doc.getPrev(model);
|
|
||||||
if (!previousSiblingModel) return;
|
|
||||||
|
|
||||||
const parentModel = host.doc.getParent(previousSiblingModel);
|
|
||||||
if (!parentModel) return;
|
|
||||||
|
|
||||||
host.doc.moveBlocks([model], parentModel, previousSiblingModel, true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Move Down',
|
|
||||||
description: 'Shift this line down.',
|
|
||||||
icon: ArrowDownBigIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Move Down'],
|
|
||||||
group: `8_Actions@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
const { host } = std;
|
|
||||||
const nextSiblingModel = host.doc.getNext(model);
|
|
||||||
if (!nextSiblingModel) return;
|
|
||||||
|
|
||||||
const parentModel = host.doc.getParent(nextSiblingModel);
|
|
||||||
if (!parentModel) return;
|
|
||||||
|
|
||||||
host.doc.moveBlocks([model], parentModel, nextSiblingModel, false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Copy',
|
|
||||||
description: 'Copy this line to clipboard.',
|
|
||||||
icon: CopyIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Copy'],
|
|
||||||
group: `8_Actions@${index++}`,
|
|
||||||
action: ({ std, model }) => {
|
|
||||||
const slice = Slice.fromModels(std.store, [model]);
|
|
||||||
|
|
||||||
std.clipboard
|
|
||||||
.copy(slice)
|
|
||||||
.then(() => {
|
|
||||||
toast(std.host, 'Copied to clipboard');
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Today',
|
||||||
name: 'Duplicate',
|
icon: TodayIcon(),
|
||||||
description: 'Create a duplicate of this line.',
|
tooltip: slashMenuToolTips['Today'],
|
||||||
icon: DualLinkIcon(),
|
description: formatDate(now),
|
||||||
tooltip: slashMenuToolTips['Copy'],
|
group: '6_Date@0',
|
||||||
group: `8_Actions@${index++}`,
|
action: ({ std, model }) => {
|
||||||
action: ({ std, model }) => {
|
insertContent(std.host, model, formatDate(now));
|
||||||
if (!model.text || !(model.text instanceof Text)) {
|
},
|
||||||
console.error("Can't duplicate a block without text");
|
},
|
||||||
return;
|
{
|
||||||
}
|
name: 'Tomorrow',
|
||||||
const { host } = std;
|
icon: TomorrowIcon(),
|
||||||
const parent = host.doc.getParent(model);
|
tooltip: slashMenuToolTips['Tomorrow'],
|
||||||
if (!parent) {
|
description: formatDate(tomorrow),
|
||||||
console.error(
|
group: '6_Date@1',
|
||||||
'Failed to duplicate block! Parent not found: ' +
|
action: ({ std, model }) => {
|
||||||
model.id +
|
const tomorrow = new Date();
|
||||||
'|' +
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
model.flavour
|
insertContent(std.host, model, formatDate(tomorrow));
|
||||||
);
|
},
|
||||||
return;
|
},
|
||||||
}
|
{
|
||||||
const index = parent.children.indexOf(model);
|
name: 'Yesterday',
|
||||||
|
icon: YesterdayIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Yesterday'],
|
||||||
|
description: formatDate(yesterday),
|
||||||
|
group: '6_Date@2',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
const yesterday = new Date();
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
insertContent(std.host, model, formatDate(yesterday));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Now',
|
||||||
|
icon: NowIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Now'],
|
||||||
|
description: formatTime(now),
|
||||||
|
group: '6_Date@3',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
insertContent(std.host, model, formatTime(now));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Move Up',
|
||||||
|
description: 'Shift this line up.',
|
||||||
|
icon: ArrowUpBigIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Move Up'],
|
||||||
|
group: '8_Actions@0',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
const { host } = std;
|
||||||
|
const previousSiblingModel = host.doc.getPrev(model);
|
||||||
|
if (!previousSiblingModel) return;
|
||||||
|
|
||||||
// TODO add clone model util
|
const parentModel = host.doc.getParent(previousSiblingModel);
|
||||||
host.doc.addBlock(
|
if (!parentModel) return;
|
||||||
model.flavour as never,
|
|
||||||
{
|
host.doc.moveBlocks([model], parentModel, previousSiblingModel, true);
|
||||||
type: (model as ParagraphBlockModel).type,
|
},
|
||||||
text: new Text(model.text.toDelta() as DeltaInsert[]),
|
|
||||||
// @ts-expect-error FIXME: ts error
|
|
||||||
checked: model.checked,
|
|
||||||
},
|
|
||||||
host.doc.getParent(model),
|
|
||||||
index
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Move Down',
|
||||||
name: 'Delete',
|
description: 'Shift this line down.',
|
||||||
description: 'Remove this line permanently.',
|
icon: ArrowDownBigIcon(),
|
||||||
searchAlias: ['remove'],
|
tooltip: slashMenuToolTips['Move Down'],
|
||||||
icon: DeleteIcon(),
|
group: '8_Actions@1',
|
||||||
tooltip: slashMenuToolTips['Delete'],
|
action: ({ std, model }) => {
|
||||||
group: `8_Actions@${index++}`,
|
const { host } = std;
|
||||||
action: ({ std, model }) => {
|
const nextSiblingModel = host.doc.getNext(model);
|
||||||
std.host.doc.deleteBlock(model);
|
if (!nextSiblingModel) return;
|
||||||
|
|
||||||
|
const parentModel = host.doc.getParent(nextSiblingModel);
|
||||||
|
if (!parentModel) return;
|
||||||
|
|
||||||
|
host.doc.moveBlocks([model], parentModel, nextSiblingModel, false);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
],
|
name: 'Copy',
|
||||||
|
description: 'Copy this line to clipboard.',
|
||||||
|
icon: CopyIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Copy'],
|
||||||
|
group: '8_Actions@2',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
const slice = Slice.fromModels(std.store, [model]);
|
||||||
|
|
||||||
|
std.clipboard
|
||||||
|
.copy(slice)
|
||||||
|
.then(() => {
|
||||||
|
toast(std.host, 'Copied to clipboard');
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Duplicate',
|
||||||
|
description: 'Create a duplicate of this line.',
|
||||||
|
icon: DualLinkIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Copy'],
|
||||||
|
group: '8_Actions@3',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
if (!model.text || !(model.text instanceof Text)) {
|
||||||
|
console.error("Can't duplicate a block without text");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { host } = std;
|
||||||
|
const parent = host.doc.getParent(model);
|
||||||
|
if (!parent) {
|
||||||
|
console.error(
|
||||||
|
'Failed to duplicate block! Parent not found: ' +
|
||||||
|
model.id +
|
||||||
|
'|' +
|
||||||
|
model.flavour
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const index = parent.children.indexOf(model);
|
||||||
|
|
||||||
|
// TODO add clone model util
|
||||||
|
host.doc.addBlock(
|
||||||
|
model.flavour as never,
|
||||||
|
{
|
||||||
|
type: (model as ParagraphBlockModel).type,
|
||||||
|
text: new Text(model.text.toDelta() as DeltaInsert[]),
|
||||||
|
// @ts-expect-error FIXME: ts error
|
||||||
|
checked: model.checked,
|
||||||
|
},
|
||||||
|
host.doc.getParent(model),
|
||||||
|
index
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Delete',
|
||||||
|
description: 'Remove this line permanently.',
|
||||||
|
searchAlias: ['remove'],
|
||||||
|
icon: DeleteIcon(),
|
||||||
|
tooltip: slashMenuToolTips['Delete'],
|
||||||
|
group: '8_Actions@4',
|
||||||
|
action: ({ std, model }) => {
|
||||||
|
std.host.doc.deleteBlock(model);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { SlashMenuTooltip } from '../types';
|
import type { SlashMenuTooltip } from '../types';
|
||||||
import { CopyTooltip } from './copy';
|
import { CopyTooltip } from './copy';
|
||||||
import { DeleteTooltip } from './delete';
|
import { DeleteTooltip } from './delete';
|
||||||
import { EdgelessTooltip } from './edgeless';
|
|
||||||
import { LinkDocTooltip } from './link-doc';
|
import { LinkDocTooltip } from './link-doc';
|
||||||
import { MoveDownTooltip } from './move-down';
|
import { MoveDownTooltip } from './move-down';
|
||||||
import { MoveUpTooltip } from './move-up';
|
import { MoveUpTooltip } from './move-up';
|
||||||
@@ -61,9 +60,4 @@ export const slashMenuToolTips: Record<string, SlashMenuTooltip> = {
|
|||||||
figure: DeleteTooltip,
|
figure: DeleteTooltip,
|
||||||
caption: 'Delete',
|
caption: 'Delete',
|
||||||
},
|
},
|
||||||
|
|
||||||
'Group & Frame': {
|
|
||||||
figure: EdgelessTooltip,
|
|
||||||
caption: 'Edgeless',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
},
|
},
|
||||||
"include": ["./src"],
|
"include": ["./src"],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../block-surface" },
|
|
||||||
{ "path": "../block-surface-ref" },
|
|
||||||
{ "path": "../components" },
|
{ "path": "../components" },
|
||||||
{ "path": "../rich-text" },
|
{ "path": "../rich-text" },
|
||||||
{ "path": "../shared" },
|
{ "path": "../shared" },
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ export const PackageList = [
|
|||||||
'blocksuite/affine/components',
|
'blocksuite/affine/components',
|
||||||
'blocksuite/affine/model',
|
'blocksuite/affine/model',
|
||||||
'blocksuite/affine/shared',
|
'blocksuite/affine/shared',
|
||||||
|
'blocksuite/affine/widget-slash-menu',
|
||||||
'blocksuite/framework/block-std',
|
'blocksuite/framework/block-std',
|
||||||
'blocksuite/framework/global',
|
'blocksuite/framework/global',
|
||||||
'blocksuite/framework/inline',
|
'blocksuite/framework/inline',
|
||||||
@@ -495,8 +496,6 @@ export const PackageList = [
|
|||||||
location: 'blocksuite/affine/widget-slash-menu',
|
location: 'blocksuite/affine/widget-slash-menu',
|
||||||
name: '@blocksuite/affine-widget-slash-menu',
|
name: '@blocksuite/affine-widget-slash-menu',
|
||||||
workspaceDependencies: [
|
workspaceDependencies: [
|
||||||
'blocksuite/affine/block-surface',
|
|
||||||
'blocksuite/affine/block-surface-ref',
|
|
||||||
'blocksuite/affine/components',
|
'blocksuite/affine/components',
|
||||||
'blocksuite/affine/rich-text',
|
'blocksuite/affine/rich-text',
|
||||||
'blocksuite/affine/shared',
|
'blocksuite/affine/shared',
|
||||||
|
|||||||
@@ -2665,9 +2665,10 @@ __metadata:
|
|||||||
"@blocksuite/affine-components": "workspace:*"
|
"@blocksuite/affine-components": "workspace:*"
|
||||||
"@blocksuite/affine-model": "workspace:*"
|
"@blocksuite/affine-model": "workspace:*"
|
||||||
"@blocksuite/affine-shared": "workspace:*"
|
"@blocksuite/affine-shared": "workspace:*"
|
||||||
|
"@blocksuite/affine-widget-slash-menu": "workspace:*"
|
||||||
"@blocksuite/block-std": "workspace:*"
|
"@blocksuite/block-std": "workspace:*"
|
||||||
"@blocksuite/global": "workspace:*"
|
"@blocksuite/global": "workspace:*"
|
||||||
"@blocksuite/icons": "npm:^2.2.3"
|
"@blocksuite/icons": "npm:^2.2.4"
|
||||||
"@blocksuite/inline": "workspace:*"
|
"@blocksuite/inline": "workspace:*"
|
||||||
"@blocksuite/store": "workspace:*"
|
"@blocksuite/store": "workspace:*"
|
||||||
"@lit/context": "npm:^1.1.2"
|
"@lit/context": "npm:^1.1.2"
|
||||||
@@ -3040,8 +3041,6 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@blocksuite/affine-widget-slash-menu@workspace:blocksuite/affine/widget-slash-menu"
|
resolution: "@blocksuite/affine-widget-slash-menu@workspace:blocksuite/affine/widget-slash-menu"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@blocksuite/affine-block-surface": "workspace:*"
|
|
||||||
"@blocksuite/affine-block-surface-ref": "workspace:*"
|
|
||||||
"@blocksuite/affine-components": "workspace:*"
|
"@blocksuite/affine-components": "workspace:*"
|
||||||
"@blocksuite/affine-rich-text": "workspace:*"
|
"@blocksuite/affine-rich-text": "workspace:*"
|
||||||
"@blocksuite/affine-shared": "workspace:*"
|
"@blocksuite/affine-shared": "workspace:*"
|
||||||
|
|||||||
Reference in New Issue
Block a user