mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-18 10:31:50 +08:00
refactor(editor): linked doc slash menu config extension (#10682)
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
|
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
|
||||||
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
|
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
|
||||||
import { SlashMenuConfigExtension } from '@blocksuite/affine-widget-slash-menu';
|
|
||||||
import {
|
import {
|
||||||
BlockFlavourIdentifier,
|
BlockFlavourIdentifier,
|
||||||
BlockViewExtension,
|
BlockViewExtension,
|
||||||
@@ -10,7 +9,7 @@ import type { ExtensionType } from '@blocksuite/store';
|
|||||||
import { literal } from 'lit/static-html.js';
|
import { literal } from 'lit/static-html.js';
|
||||||
|
|
||||||
import { BookmarkBlockAdapterExtensions } from './adapters/extension';
|
import { BookmarkBlockAdapterExtensions } from './adapters/extension';
|
||||||
import { bookmarkSlashMenuConfig } from './configs/slash-menu';
|
import { BookmarkSlashMenuConfigExtension } from './configs/slash-menu';
|
||||||
import { builtinToolbarConfig } from './configs/toolbar';
|
import { builtinToolbarConfig } from './configs/toolbar';
|
||||||
|
|
||||||
const flavour = BookmarkBlockSchema.model.flavour;
|
const flavour = BookmarkBlockSchema.model.flavour;
|
||||||
@@ -27,5 +26,5 @@ export const BookmarkBlockSpec: ExtensionType[] = [
|
|||||||
id: BlockFlavourIdentifier(flavour),
|
id: BlockFlavourIdentifier(flavour),
|
||||||
config: builtinToolbarConfig,
|
config: builtinToolbarConfig,
|
||||||
}),
|
}),
|
||||||
SlashMenuConfigExtension(flavour, bookmarkSlashMenuConfig),
|
BookmarkSlashMenuConfigExtension,
|
||||||
].flat();
|
].flat();
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
|
import { toggleEmbedCardCreateModal } from '@blocksuite/affine-components/embed-card-modal';
|
||||||
import { type SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
|
import { BookmarkBlockSchema } from '@blocksuite/affine-model';
|
||||||
|
import {
|
||||||
|
type SlashMenuConfig,
|
||||||
|
SlashMenuConfigIdentifier,
|
||||||
|
} from '@blocksuite/affine-widget-slash-menu';
|
||||||
import { LinkIcon } from '@blocksuite/icons/lit';
|
import { LinkIcon } from '@blocksuite/icons/lit';
|
||||||
|
import type { ExtensionType } from '@blocksuite/store';
|
||||||
|
|
||||||
import { LinkTooltip } from './tooltips';
|
import { LinkTooltip } from './tooltips';
|
||||||
|
|
||||||
export const bookmarkSlashMenuConfig: SlashMenuConfig = {
|
const bookmarkSlashMenuConfig: SlashMenuConfig = {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
name: 'Link',
|
name: 'Link',
|
||||||
@@ -40,3 +45,13 @@ export const bookmarkSlashMenuConfig: SlashMenuConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const BookmarkSlashMenuConfigIdentifier = SlashMenuConfigIdentifier(
|
||||||
|
BookmarkBlockSchema.model.flavour
|
||||||
|
);
|
||||||
|
|
||||||
|
export const BookmarkSlashMenuConfigExtension: ExtensionType = {
|
||||||
|
setup: di => {
|
||||||
|
di.addImpl(BookmarkSlashMenuConfigIdentifier, bookmarkSlashMenuConfig);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export * from './bookmark-block';
|
|||||||
export * from './bookmark-spec';
|
export * from './bookmark-spec';
|
||||||
export * from './commands';
|
export * from './commands';
|
||||||
export * from './components';
|
export * from './components';
|
||||||
|
export { BookmarkSlashMenuConfigIdentifier } from './configs/slash-menu';
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
||||||
|
import {
|
||||||
|
getInlineEditorByModel,
|
||||||
|
insertContent,
|
||||||
|
} from '@blocksuite/affine-rich-text';
|
||||||
|
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
||||||
|
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
||||||
|
import {
|
||||||
|
type SlashMenuConfig,
|
||||||
|
SlashMenuConfigIdentifier,
|
||||||
|
} from '@blocksuite/affine-widget-slash-menu';
|
||||||
|
import { LinkedPageIcon, PlusIcon } from '@blocksuite/icons/lit';
|
||||||
|
import { type ExtensionType } from '@blocksuite/store';
|
||||||
|
|
||||||
|
import { LinkDocTooltip, NewDocTooltip } from './tooltips';
|
||||||
|
|
||||||
|
const linkedDocSlashMenuConfig: SlashMenuConfig = {
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'New Doc',
|
||||||
|
description: 'Start a new document.',
|
||||||
|
icon: PlusIcon(),
|
||||||
|
tooltip: {
|
||||||
|
figure: NewDocTooltip,
|
||||||
|
caption: 'New Doc',
|
||||||
|
},
|
||||||
|
group: '3_Page@0',
|
||||||
|
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',
|
||||||
|
description: 'Link to another document.',
|
||||||
|
icon: LinkedPageIcon(),
|
||||||
|
tooltip: {
|
||||||
|
figure: LinkDocTooltip,
|
||||||
|
caption: 'Link Doc',
|
||||||
|
},
|
||||||
|
searchAlias: ['dual link'],
|
||||||
|
group: '3_Page@1',
|
||||||
|
when: ({ std, model }) => {
|
||||||
|
const root = model.doc.root;
|
||||||
|
if (!root) return false;
|
||||||
|
const linkedDocWidget = std.view.getWidget(
|
||||||
|
'affine-linked-doc-widget',
|
||||||
|
root.id
|
||||||
|
);
|
||||||
|
if (!linkedDocWidget) return false;
|
||||||
|
|
||||||
|
return model.doc.schema.flavourSchemaMap.has('affine:embed-linked-doc');
|
||||||
|
},
|
||||||
|
action: ({ model, std }) => {
|
||||||
|
const root = model.doc.root;
|
||||||
|
if (!root) return;
|
||||||
|
const linkedDocWidget = std.view.getWidget(
|
||||||
|
'affine-linked-doc-widget',
|
||||||
|
root.id
|
||||||
|
);
|
||||||
|
if (!linkedDocWidget) return;
|
||||||
|
// TODO(@L-Sun): make linked-doc-widget as extension
|
||||||
|
// @ts-expect-error same as above
|
||||||
|
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
|
||||||
|
// @ts-expect-error same as above
|
||||||
|
linkedDocWidget.show({ addTriggerKey: true });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LinkedDocSlashMenuConfigIdentifier = SlashMenuConfigIdentifier(
|
||||||
|
EmbedLinkedDocBlockSchema.model.flavour
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LinkedDocSlashMenuConfigExtension: ExtensionType = {
|
||||||
|
setup: di => {
|
||||||
|
di.addImpl(LinkedDocSlashMenuConfigIdentifier, linkedDocSlashMenuConfig);
|
||||||
|
},
|
||||||
|
};
|
||||||
+13
@@ -1,4 +1,17 @@
|
|||||||
import { html } from 'lit';
|
import { html } from 'lit';
|
||||||
|
// prettier-ignore
|
||||||
|
export const NewDocTooltip = html`<svg width="170" height="68" viewBox="0 0 170 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="170" height="68" rx="2" fill="white"/>
|
||||||
|
<mask id="mask0_16460_991" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="170" height="68">
|
||||||
|
<rect width="170" height="68" rx="2" fill="white"/>
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_16460_991)">
|
||||||
|
<text fill="#8E8D91" xml:space="preserve" style="white-space: pre" font-family="Inter" font-size="22" font-weight="600" letter-spacing="0px"><tspan x="8" y="27.5">Title</tspan></text>
|
||||||
|
<text fill="#8E8D91" xml:space="preserve" style="white-space: pre" font-family="Inter" font-size="10" letter-spacing="0px"><tspan x="8" y="44.6364">Type '/' for commands</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
export const LinkDocTooltip = html`<svg width="170" height="68" viewBox="0 0 170 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
export const LinkDocTooltip = html`<svg width="170" height="68" viewBox="0 0 170 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect width="170" height="68" rx="2" fill="white"/>
|
<rect width="170" height="68" rx="2" fill="white"/>
|
||||||
@@ -8,6 +8,7 @@ import type { ExtensionType } from '@blocksuite/store';
|
|||||||
import { literal } from 'lit/static-html.js';
|
import { literal } from 'lit/static-html.js';
|
||||||
|
|
||||||
import { EmbedLinkedDocBlockAdapterExtensions } from './adapters/extension';
|
import { EmbedLinkedDocBlockAdapterExtensions } from './adapters/extension';
|
||||||
|
import { LinkedDocSlashMenuConfigExtension } from './configs/slash-menu';
|
||||||
import { builtinToolbarConfig } from './configs/toolbar';
|
import { builtinToolbarConfig } from './configs/toolbar';
|
||||||
|
|
||||||
const flavour = EmbedLinkedDocBlockSchema.model.flavour;
|
const flavour = EmbedLinkedDocBlockSchema.model.flavour;
|
||||||
@@ -23,4 +24,5 @@ export const EmbedLinkedDocBlockSpec: ExtensionType[] = [
|
|||||||
id: BlockServiceIdentifier(flavour),
|
id: BlockServiceIdentifier(flavour),
|
||||||
config: builtinToolbarConfig,
|
config: builtinToolbarConfig,
|
||||||
}),
|
}),
|
||||||
|
LinkedDocSlashMenuConfigExtension,
|
||||||
].flat();
|
].flat();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './adapters';
|
export * from './adapters';
|
||||||
export * from './commands';
|
export * from './commands';
|
||||||
|
export { LinkedDocSlashMenuConfigIdentifier } from './configs/slash-menu';
|
||||||
export * from './embed-linked-doc-block';
|
export * from './embed-linked-doc-block';
|
||||||
export * from './embed-linked-doc-spec';
|
export * from './embed-linked-doc-spec';
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
// TODO(@L-Sun): remove these utils
|
|
||||||
export function formatDate(date: Date) {
|
|
||||||
// yyyy-mm-dd
|
|
||||||
const year = date.getFullYear();
|
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
||||||
const day = date.getDate().toString().padStart(2, '0');
|
|
||||||
const strTime = `${year}-${month}-${day}`;
|
|
||||||
return strTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatTime(date: Date) {
|
|
||||||
// mm-dd hh:mm
|
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
||||||
const day = date.getDate().toString().padStart(2, '0');
|
|
||||||
const hours = date.getHours().toString().padStart(2, '0');
|
|
||||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
||||||
const strTime = `${month}-${day} ${hours}:${minutes}`;
|
|
||||||
return strTime;
|
|
||||||
}
|
|
||||||
@@ -101,7 +101,6 @@ import { cssVarV2 } from '@toeverything/theme/v2';
|
|||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
|
|
||||||
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
import type { PageRootBlockComponent } from '../../page/page-root-block.js';
|
||||||
import { formatDate, formatTime } from '../../utils/misc.js';
|
|
||||||
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
import type { AffineLinkedDocWidget } from '../linked-doc/index.js';
|
||||||
import {
|
import {
|
||||||
FigmaDuotoneIcon,
|
FigmaDuotoneIcon,
|
||||||
@@ -110,6 +109,7 @@ import {
|
|||||||
TextBackgroundDuotoneIcon,
|
TextBackgroundDuotoneIcon,
|
||||||
TextColorIcon,
|
TextColorIcon,
|
||||||
} from './icons.js';
|
} from './icons.js';
|
||||||
|
import { formatDate, formatTime } from './utils.js';
|
||||||
|
|
||||||
export type KeyboardToolbarConfig = {
|
export type KeyboardToolbarConfig = {
|
||||||
items: KeyboardToolbarItem[];
|
items: KeyboardToolbarItem[];
|
||||||
|
|||||||
@@ -22,3 +22,22 @@ export function isKeyboardToolPanelConfig(
|
|||||||
): item is KeyboardToolPanelConfig {
|
): item is KeyboardToolPanelConfig {
|
||||||
return 'groups' in item;
|
return 'groups' in item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatDate(date: Date) {
|
||||||
|
// yyyy-mm-dd
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const day = date.getDate().toString().padStart(2, '0');
|
||||||
|
const strTime = `${year}-${month}-${day}`;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatTime(date: Date) {
|
||||||
|
// mm-dd hh:mm
|
||||||
|
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
const day = date.getDate().toString().padStart(2, '0');
|
||||||
|
const hours = date.getHours().toString().padStart(2, '0');
|
||||||
|
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||||
|
const strTime = `${month}-${day} ${hours}:${minutes}`;
|
||||||
|
return strTime;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,20 +1,13 @@
|
|||||||
import { toast } from '@blocksuite/affine-components/toast';
|
import { toast } from '@blocksuite/affine-components/toast';
|
||||||
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
|
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
|
||||||
import {
|
import { insertContent } from '@blocksuite/affine-rich-text';
|
||||||
getInlineEditorByModel,
|
|
||||||
insertContent,
|
|
||||||
} from '@blocksuite/affine-rich-text';
|
|
||||||
import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
|
||||||
import { createDefaultDoc } from '@blocksuite/affine-shared/utils';
|
|
||||||
import {
|
import {
|
||||||
ArrowDownBigIcon,
|
ArrowDownBigIcon,
|
||||||
ArrowUpBigIcon,
|
ArrowUpBigIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
DualLinkIcon,
|
DualLinkIcon,
|
||||||
LinkedPageIcon,
|
|
||||||
NowIcon,
|
NowIcon,
|
||||||
PlusIcon,
|
|
||||||
TodayIcon,
|
TodayIcon,
|
||||||
TomorrowIcon,
|
TomorrowIcon,
|
||||||
YesterdayIcon,
|
YesterdayIcon,
|
||||||
@@ -38,67 +31,6 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
|
|||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
name: 'New Doc',
|
|
||||||
description: 'Start a new document.',
|
|
||||||
icon: PlusIcon(),
|
|
||||||
tooltip: slashMenuToolTips['New Doc'],
|
|
||||||
group: '3_Page@0',
|
|
||||||
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',
|
|
||||||
description: 'Link to another document.',
|
|
||||||
icon: LinkedPageIcon(),
|
|
||||||
tooltip: slashMenuToolTips['Linked Doc'],
|
|
||||||
searchAlias: ['dual link'],
|
|
||||||
group: '3_Page@1',
|
|
||||||
when: ({ std, model }) => {
|
|
||||||
const root = model.doc.root;
|
|
||||||
if (!root) return false;
|
|
||||||
const linkedDocWidget = std.view.getWidget(
|
|
||||||
'affine-linked-doc-widget',
|
|
||||||
root.id
|
|
||||||
);
|
|
||||||
if (!linkedDocWidget) return false;
|
|
||||||
|
|
||||||
return model.doc.schema.flavourSchemaMap.has(
|
|
||||||
'affine:embed-linked-doc'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
action: ({ model, std }) => {
|
|
||||||
const root = model.doc.root;
|
|
||||||
if (!root) return;
|
|
||||||
const linkedDocWidget = std.view.getWidget(
|
|
||||||
'affine-linked-doc-widget',
|
|
||||||
root.id
|
|
||||||
);
|
|
||||||
if (!linkedDocWidget) return;
|
|
||||||
// TODO(@L-Sun): make linked-doc-widget as extension
|
|
||||||
// @ts-expect-error same as above
|
|
||||||
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
|
|
||||||
// @ts-expect-error same as above
|
|
||||||
linkedDocWidget.show({ addTriggerKey: true });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Today',
|
name: 'Today',
|
||||||
icon: TodayIcon(),
|
icon: TodayIcon(),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export const AFFINE_SLASH_MENU_WIDGET = 'affine-slash-menu-widget';
|
export const AFFINE_SLASH_MENU_WIDGET = 'affine-slash-menu-widget';
|
||||||
export const AFFINE_SLASH_MENU_TRIGGER_KEY = '/';
|
export const AFFINE_SLASH_MENU_TRIGGER_KEY = '/';
|
||||||
export const AFFINE_SLASH_MENU_TOOLTIP_TIMEOUT = 800;
|
export const AFFINE_SLASH_MENU_TOOLTIP_TIMEOUT = 800;
|
||||||
// TODO(@L-Sun): Move this to styles.ts
|
|
||||||
export const AFFINE_SLASH_MENU_MAX_HEIGHT = 334;
|
export const AFFINE_SLASH_MENU_MAX_HEIGHT = 334;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export class SlashMenuExtension extends Extension {
|
|||||||
|
|
||||||
di.add(this, [StdIdentifier]);
|
di.add(this, [StdIdentifier]);
|
||||||
|
|
||||||
// TODO(@L-Sun): remove this after moving all configs to corresponding extensions
|
|
||||||
SlashMenuConfigExtension('default', defaultSlashMenuConfig).setup(di);
|
SlashMenuConfigExtension('default', defaultSlashMenuConfig).setup(di);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ export class SlashMenuExtension extends Extension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SlashMenuConfigIdentifier = createIdentifier<SlashMenuConfig>(
|
export const SlashMenuConfigIdentifier = createIdentifier<SlashMenuConfig>(
|
||||||
`${AFFINE_SLASH_MENU_WIDGET}-config`
|
`${AFFINE_SLASH_MENU_WIDGET}-config`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
export { AFFINE_SLASH_MENU_WIDGET } from './consts';
|
export { AFFINE_SLASH_MENU_WIDGET } from './consts';
|
||||||
// TODO(@L-Sun): narrow the scope of the exported symbols
|
|
||||||
export * from './extensions';
|
export * from './extensions';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
// TODO(@L-Sun): remove this when refactoring quick search
|
|
||||||
export * from './widget';
|
|
||||||
|
|||||||
@@ -1,26 +1,14 @@
|
|||||||
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 { LinkDocTooltip } from './link-doc';
|
|
||||||
import { MoveDownTooltip } from './move-down';
|
import { MoveDownTooltip } from './move-down';
|
||||||
import { MoveUpTooltip } from './move-up';
|
import { MoveUpTooltip } from './move-up';
|
||||||
import { NewDocTooltip } from './new-doc';
|
|
||||||
import { NowTooltip } from './now';
|
import { NowTooltip } from './now';
|
||||||
import { TodayTooltip } from './today';
|
import { TodayTooltip } from './today';
|
||||||
import { TomorrowTooltip } from './tomorrow';
|
import { TomorrowTooltip } from './tomorrow';
|
||||||
import { YesterdayTooltip } from './yesterday';
|
import { YesterdayTooltip } from './yesterday';
|
||||||
|
|
||||||
export const slashMenuToolTips: Record<string, SlashMenuTooltip> = {
|
export const slashMenuToolTips: Record<string, SlashMenuTooltip> = {
|
||||||
'New Doc': {
|
|
||||||
figure: NewDocTooltip,
|
|
||||||
caption: 'New Doc',
|
|
||||||
},
|
|
||||||
|
|
||||||
'Linked Doc': {
|
|
||||||
figure: LinkDocTooltip,
|
|
||||||
caption: 'Link Doc',
|
|
||||||
},
|
|
||||||
|
|
||||||
Today: {
|
Today: {
|
||||||
figure: TodayTooltip,
|
figure: TodayTooltip,
|
||||||
caption: 'Today',
|
caption: 'Today',
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { html } from 'lit';
|
|
||||||
// prettier-ignore
|
|
||||||
export const NewDocTooltip = html`<svg width="170" height="68" viewBox="0 0 170 68" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="170" height="68" rx="2" fill="white"/>
|
|
||||||
<mask id="mask0_16460_991" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="170" height="68">
|
|
||||||
<rect width="170" height="68" rx="2" fill="white"/>
|
|
||||||
</mask>
|
|
||||||
<g mask="url(#mask0_16460_991)">
|
|
||||||
<text fill="#8E8D91" xml:space="preserve" style="white-space: pre" font-family="Inter" font-size="22" font-weight="600" letter-spacing="0px"><tspan x="8" y="27.5">Title</tspan></text>
|
|
||||||
<text fill="#8E8D91" xml:space="preserve" style="white-space: pre" font-family="Inter" font-size="10" letter-spacing="0px"><tspan x="8" y="44.6364">Type '/' for commands</tspan></text>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
@@ -12,7 +12,7 @@ export type SlashMenuTooltip = {
|
|||||||
caption: string;
|
caption: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SlashMenuItemBase = {
|
type SlashMenuItemBase = {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
icon?: TemplateResult;
|
icon?: TemplateResult;
|
||||||
@@ -24,10 +24,6 @@ export type SlashMenuItemBase = {
|
|||||||
*/
|
*/
|
||||||
group?: `${number}_${string}@${number}`;
|
group?: `${number}_${string}@${number}`;
|
||||||
|
|
||||||
// TODO(@L-Sun): move this field to SlashMenuActionItem when refactoring search
|
|
||||||
/**
|
|
||||||
* The alias of the menu item for search.
|
|
||||||
*/
|
|
||||||
searchAlias?: string[];
|
searchAlias?: string[];
|
||||||
/**
|
/**
|
||||||
* The condition to show the menu item.
|
* The condition to show the menu item.
|
||||||
@@ -38,6 +34,10 @@ export type SlashMenuItemBase = {
|
|||||||
export type SlashMenuActionItem = SlashMenuItemBase & {
|
export type SlashMenuActionItem = SlashMenuItemBase & {
|
||||||
action: (ctx: SlashMenuContext) => void;
|
action: (ctx: SlashMenuContext) => void;
|
||||||
tooltip?: SlashMenuTooltip;
|
tooltip?: SlashMenuTooltip;
|
||||||
|
/**
|
||||||
|
* The alias of the menu item for search.
|
||||||
|
*/
|
||||||
|
searchAlias?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SlashMenuSubMenu = SlashMenuItemBase & {
|
export type SlashMenuSubMenu = SlashMenuItemBase & {
|
||||||
@@ -47,7 +47,6 @@ export type SlashMenuSubMenu = SlashMenuItemBase & {
|
|||||||
export type SlashMenuItem = SlashMenuActionItem | SlashMenuSubMenu;
|
export type SlashMenuItem = SlashMenuActionItem | SlashMenuSubMenu;
|
||||||
|
|
||||||
export type SlashMenuConfig = {
|
export type SlashMenuConfig = {
|
||||||
// TODO(@L-Sun): change this type to SlashMenuItem[] and (ctx: SlashMenuContext) => SlashMenuItem[]
|
|
||||||
/**
|
/**
|
||||||
* The items in the slash menu. It can be generated dynamically with the context.
|
* The items in the slash menu. It can be generated dynamically with the context.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,14 +10,19 @@ import {
|
|||||||
import { ExternalLinksQuickSearchSession } from '@affine/core/modules/quicksearch/impls/external-links';
|
import { ExternalLinksQuickSearchSession } from '@affine/core/modules/quicksearch/impls/external-links';
|
||||||
import { JournalsQuickSearchSession } from '@affine/core/modules/quicksearch/impls/journals';
|
import { JournalsQuickSearchSession } from '@affine/core/modules/quicksearch/impls/journals';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import { LifeCycleWatcher } from '@blocksuite/affine/block-std';
|
import type {
|
||||||
import type { QuickSearchResult } from '@blocksuite/affine/blocks';
|
QuickSearchResult,
|
||||||
|
SlashMenuConfig,
|
||||||
|
SlashMenuItem,
|
||||||
|
} from '@blocksuite/affine/blocks';
|
||||||
import {
|
import {
|
||||||
AffineSlashMenuWidget,
|
BookmarkSlashMenuConfigIdentifier,
|
||||||
insertLinkByQuickSearchCommand,
|
insertLinkByQuickSearchCommand,
|
||||||
|
LinkedDocSlashMenuConfigIdentifier,
|
||||||
QuickSearchExtension,
|
QuickSearchExtension,
|
||||||
} from '@blocksuite/affine/blocks';
|
} from '@blocksuite/affine/blocks';
|
||||||
import { Text } from '@blocksuite/affine/store';
|
import type { ServiceIdentifier } from '@blocksuite/affine/global/di';
|
||||||
|
import { type ExtensionType, Text } from '@blocksuite/affine/store';
|
||||||
import type { FrameworkProvider } from '@toeverything/infra';
|
import type { FrameworkProvider } from '@toeverything/infra';
|
||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
|
|
||||||
@@ -120,56 +125,66 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
class SlashMenuQuickSearchExtension extends LifeCycleWatcher {
|
const SlashMenuQuickSearchExtension: ExtensionType = {
|
||||||
static override key = 'slash-menu-quick-search-extension';
|
setup: di => {
|
||||||
|
const overrideFn = (identifier: ServiceIdentifier<SlashMenuConfig>) => {
|
||||||
|
const prev = di.getFactory(identifier);
|
||||||
|
if (!prev) return;
|
||||||
|
|
||||||
override mounted() {
|
di.override(identifier, provider => {
|
||||||
super.mounted();
|
const prevConfig: SlashMenuConfig = prev(provider);
|
||||||
const { view } = this.std;
|
|
||||||
view.viewUpdated.on(payload => {
|
|
||||||
if (payload.type !== 'widget' || payload.method !== 'add') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const component = payload.view;
|
|
||||||
if (component instanceof AffineSlashMenuWidget) {
|
|
||||||
component.configItemTransform = item => {
|
|
||||||
if (
|
|
||||||
'action' in item &&
|
|
||||||
(item.name === 'Linked Doc' || item.name === 'Link')
|
|
||||||
) {
|
|
||||||
item.action = ({ std }) => {
|
|
||||||
const [success, { insertedLinkType }] = std.command.exec(
|
|
||||||
insertLinkByQuickSearchCommand
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!success) return;
|
if (typeof prevConfig.items === 'function') {
|
||||||
|
const prevConfigItemGenerator = prevConfig.items;
|
||||||
|
prevConfig.items = ctx =>
|
||||||
|
prevConfigItemGenerator(ctx).map(modifyFn);
|
||||||
|
} else {
|
||||||
|
prevConfig.items = prevConfig.items.map(modifyFn);
|
||||||
|
}
|
||||||
|
|
||||||
insertedLinkType
|
return prevConfig;
|
||||||
?.then(type => {
|
});
|
||||||
const flavour = type?.flavour;
|
};
|
||||||
if (!flavour) return;
|
|
||||||
|
|
||||||
if (flavour === 'affine:bookmark') {
|
overrideFn(LinkedDocSlashMenuConfigIdentifier);
|
||||||
track.doc.editor.slashMenu.bookmark();
|
overrideFn(BookmarkSlashMenuConfigIdentifier);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flavour === 'affine:embed-linked-doc') {
|
const modifyFn = (item: SlashMenuItem): SlashMenuItem => {
|
||||||
track.doc.editor.slashMenu.linkDoc({
|
if (
|
||||||
control: 'linkDoc',
|
'action' in item &&
|
||||||
});
|
(item.name === 'Linked Doc' || item.name === 'Link')
|
||||||
return;
|
) {
|
||||||
}
|
item.action = ({ std }) => {
|
||||||
})
|
const [success, { insertedLinkType }] = std.command.exec(
|
||||||
.catch(console.error);
|
insertLinkByQuickSearchCommand
|
||||||
};
|
);
|
||||||
}
|
|
||||||
return item;
|
if (!success) return;
|
||||||
|
|
||||||
|
insertedLinkType
|
||||||
|
?.then(type => {
|
||||||
|
const flavour = type?.flavour;
|
||||||
|
if (!flavour) return;
|
||||||
|
|
||||||
|
if (flavour === 'affine:bookmark') {
|
||||||
|
track.doc.editor.slashMenu.bookmark();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flavour === 'affine:embed-linked-doc') {
|
||||||
|
track.doc.editor.slashMenu.linkDoc({
|
||||||
|
control: 'linkDoc',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
return item;
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return [QuickSearch, SlashMenuQuickSearchExtension];
|
return [QuickSearch, SlashMenuQuickSearchExtension];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user