mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 08:06:24 +08:00
init: the first public commit for AFFiNE
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Virgo, PluginHooks } from '@toeverything/framework/virgo';
|
||||
import { Cascader, CascaderItemProps } from '@toeverything/components/ui';
|
||||
import { TurnIntoMenu } from './TurnIntoMenu';
|
||||
import {
|
||||
DeleteCashBinIcon,
|
||||
TurnIntoIcon,
|
||||
UngroupIcon,
|
||||
} from '@toeverything/components/icons';
|
||||
|
||||
interface LeftMenuProps {
|
||||
anchorEl?: Element;
|
||||
children?: React.ReactElement;
|
||||
onClose: () => void;
|
||||
editor?: Virgo;
|
||||
hooks: PluginHooks;
|
||||
blockId: string;
|
||||
}
|
||||
|
||||
export function LeftMenu(props: LeftMenuProps) {
|
||||
const { editor, anchorEl, hooks, blockId } = props;
|
||||
const menu: CascaderItemProps[] = [
|
||||
{
|
||||
title: 'Delete',
|
||||
callback: () => {
|
||||
editor.commands.blockCommands.removeBlock(blockId);
|
||||
},
|
||||
shortcut: 'Del',
|
||||
icon: <DeleteCashBinIcon />,
|
||||
},
|
||||
{
|
||||
title: 'Turn into',
|
||||
subItems: [],
|
||||
children: (
|
||||
<TurnIntoMenu
|
||||
editor={editor}
|
||||
hooks={hooks}
|
||||
blockId={blockId}
|
||||
onClose={() => {
|
||||
props.onClose();
|
||||
editor.selection.setSelectedNodesIds([]);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
icon: <TurnIntoIcon />,
|
||||
},
|
||||
{
|
||||
title: 'Divide Here As A New Group',
|
||||
icon: <UngroupIcon />,
|
||||
callback: () => {
|
||||
editor.commands.blockCommands.splitGroupFromBlock(blockId);
|
||||
},
|
||||
},
|
||||
].filter(v => v);
|
||||
|
||||
const [menuList, setMenuList] = useState<CascaderItemProps[]>(menu);
|
||||
|
||||
const filter_items = (
|
||||
value: string,
|
||||
menuList: CascaderItemProps[],
|
||||
filterList: CascaderItemProps[]
|
||||
) => {
|
||||
menuList.forEach(item => {
|
||||
if (item?.subItems.length === 0) {
|
||||
if (item.title.toLocaleLowerCase().indexOf(value) !== -1) {
|
||||
filterList.push(item);
|
||||
}
|
||||
} else {
|
||||
filter_items(value, item.subItems || [], filterList);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const on_filter = (
|
||||
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
const value = e.currentTarget.value;
|
||||
if (!value) {
|
||||
setMenuList(menu);
|
||||
} else {
|
||||
const filterList: CascaderItemProps[] = [];
|
||||
filter_items(value.toLocaleLowerCase(), menu, filterList);
|
||||
setMenuList(
|
||||
filterList.length > 0 ? filterList : [{ title: 'No Result' }]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{props.children}
|
||||
<Cascader
|
||||
items={menuList}
|
||||
anchorEl={anchorEl}
|
||||
placement="bottom-start"
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={() => props.onClose()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
import { useState, useEffect, FC } from 'react';
|
||||
|
||||
import {
|
||||
Virgo,
|
||||
BlockDomInfo,
|
||||
HookType,
|
||||
PluginHooks,
|
||||
BlockDropPlacement,
|
||||
} from '@toeverything/framework/virgo';
|
||||
import { Button } from '@toeverything/components/common';
|
||||
import { styled } from '@toeverything/components/ui';
|
||||
|
||||
import { LeftMenu } from './LeftMenu';
|
||||
import { debounce } from '@toeverything/utils';
|
||||
import type { Subject } from 'rxjs';
|
||||
import { HandleChildIcon } from '@toeverything/components/icons';
|
||||
import { MENU_WIDTH } from './menu-config';
|
||||
|
||||
const MENU_BUTTON_OFFSET = 12;
|
||||
|
||||
export type LineInfoSubject = Subject<
|
||||
| {
|
||||
direction: BlockDropPlacement;
|
||||
blockInfo: BlockDomInfo;
|
||||
}
|
||||
| undefined
|
||||
>;
|
||||
|
||||
export type LeftMenuProps = {
|
||||
editor: Virgo;
|
||||
hooks: PluginHooks;
|
||||
defaultVisible?: boolean;
|
||||
blockInfo: Subject<BlockDomInfo | undefined>;
|
||||
lineInfo: LineInfoSubject;
|
||||
};
|
||||
|
||||
type LineInfo = {
|
||||
direction: BlockDropPlacement;
|
||||
blockInfo: BlockDomInfo;
|
||||
};
|
||||
|
||||
function Line(props: { lineInfo: LineInfo }) {
|
||||
const { lineInfo } = props;
|
||||
if (!lineInfo || lineInfo.direction === BlockDropPlacement.none) {
|
||||
return null;
|
||||
}
|
||||
const { direction, blockInfo } = lineInfo;
|
||||
const finalDirection = direction;
|
||||
const lineStyle = {
|
||||
zIndex: 2,
|
||||
position: 'absolute' as const,
|
||||
background: '#502EC4',
|
||||
};
|
||||
|
||||
const intersectionRect = blockInfo.rect;
|
||||
|
||||
const horizontalLineStyle = {
|
||||
...lineStyle,
|
||||
width: intersectionRect.width,
|
||||
height: 2,
|
||||
left: intersectionRect.x - blockInfo.rootRect.x,
|
||||
};
|
||||
const topLineStyle = {
|
||||
...horizontalLineStyle,
|
||||
top: intersectionRect.top,
|
||||
};
|
||||
const bottomLineStyle = {
|
||||
...horizontalLineStyle,
|
||||
top: intersectionRect.bottom + 1 - blockInfo.rootRect.y,
|
||||
};
|
||||
|
||||
const verticalLineStyle = {
|
||||
...lineStyle,
|
||||
width: 2,
|
||||
height: intersectionRect.height,
|
||||
top: intersectionRect.y - blockInfo.rootRect.y,
|
||||
};
|
||||
const leftLineStyle = {
|
||||
...verticalLineStyle,
|
||||
left: intersectionRect.x - 10 - blockInfo.rootRect.x,
|
||||
};
|
||||
const rightLineStyle = {
|
||||
...verticalLineStyle,
|
||||
left: intersectionRect.right + 10 - blockInfo.rootRect.x,
|
||||
};
|
||||
const styleMap = {
|
||||
left: leftLineStyle,
|
||||
right: rightLineStyle,
|
||||
top: topLineStyle,
|
||||
bottom: bottomLineStyle,
|
||||
};
|
||||
return (
|
||||
<div className="editor-menu-line" style={styleMap[finalDirection]} />
|
||||
);
|
||||
}
|
||||
|
||||
function DragComponent(props: {
|
||||
children: React.ReactNode;
|
||||
style: React.CSSProperties;
|
||||
onDragStart: (event: React.DragEvent<Element>) => void;
|
||||
onDragEnd: (event: React.DragEvent<Element>) => void;
|
||||
}) {
|
||||
const { style, children, onDragStart, onDragEnd } = props;
|
||||
return (
|
||||
<LigoLeftMenu
|
||||
draggable
|
||||
style={style}
|
||||
onMouseMove={event => event.stopPropagation()}
|
||||
onMouseDown={event => event.stopPropagation()}
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
>
|
||||
{children}
|
||||
</LigoLeftMenu>
|
||||
);
|
||||
}
|
||||
|
||||
export const LeftMenuDraggable: FC<LeftMenuProps> = props => {
|
||||
const { editor, blockInfo, defaultVisible, hooks, lineInfo } = props;
|
||||
const [visible, setVisible] = useState(defaultVisible);
|
||||
const [anchorEl, setAnchorEl] = useState<Element>();
|
||||
|
||||
const [block, setBlock] = useState<BlockDomInfo | undefined>();
|
||||
const [line, setLine] = useState<LineInfo | undefined>(undefined);
|
||||
|
||||
const handleDragStart = (event: React.DragEvent<Element>) => {
|
||||
window.addEventListener('dragover', handleDragOverCapture, {
|
||||
capture: true,
|
||||
});
|
||||
hooks.addHook(
|
||||
HookType.ON_ROOTNODE_DRAG_OVER_CAPTURE,
|
||||
handleDragOverCapture
|
||||
);
|
||||
|
||||
const onDragStart = async (event: React.DragEvent<Element>) => {
|
||||
if (block == null) return;
|
||||
const dragImage = await editor.blockHelper.getBlockDragImg(
|
||||
block.blockId
|
||||
);
|
||||
if (dragImage) {
|
||||
event.dataTransfer.setDragImage(dragImage, -50, -10);
|
||||
editor.dragDropManager.setDragBlockInfo(event, block.blockId);
|
||||
}
|
||||
setVisible(false);
|
||||
};
|
||||
onDragStart(event);
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleDragEnd = (event: React.DragEvent<Element>) => {
|
||||
event.preventDefault();
|
||||
window.removeEventListener('dragover', handleDragOverCapture, {
|
||||
capture: true,
|
||||
});
|
||||
setLine(undefined);
|
||||
};
|
||||
|
||||
const onClick = (event: React.MouseEvent) => {
|
||||
if (block == null) return;
|
||||
const currentTarget = event.currentTarget;
|
||||
editor.selection.setSelectedNodesIds([block.blockId]);
|
||||
setVisible(true);
|
||||
setAnchorEl(currentTarget);
|
||||
};
|
||||
|
||||
/**
|
||||
* clear line info
|
||||
*/
|
||||
const handleDragOverCapture = debounce((e: MouseEvent) => {
|
||||
const { target } = e;
|
||||
if (
|
||||
target instanceof HTMLElement &&
|
||||
(!target.closest('[data-block-id]') ||
|
||||
!editor.container.contains(target))
|
||||
) {
|
||||
setLine(undefined);
|
||||
}
|
||||
}, 10);
|
||||
|
||||
useEffect(() => {
|
||||
const sub = blockInfo.subscribe(block => {
|
||||
setBlock(block);
|
||||
if (block != null) {
|
||||
setVisible(true);
|
||||
}
|
||||
});
|
||||
return () => sub.unsubscribe();
|
||||
}, [blockInfo, editor]);
|
||||
|
||||
useEffect(() => {
|
||||
const sub = lineInfo.subscribe(data => {
|
||||
if (data == null) {
|
||||
setLine(undefined);
|
||||
} else {
|
||||
const { direction, blockInfo } = data;
|
||||
setLine(prev => {
|
||||
if (
|
||||
prev?.blockInfo.blockId !== blockInfo.blockId ||
|
||||
prev?.direction !== direction
|
||||
) {
|
||||
return {
|
||||
direction,
|
||||
blockInfo,
|
||||
};
|
||||
} else {
|
||||
return prev;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return () => sub.unsubscribe();
|
||||
}, [editor.dragDropManager, lineInfo]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{block && (
|
||||
<DragComponent
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left:
|
||||
Math.min(
|
||||
block.rect.left -
|
||||
MENU_WIDTH -
|
||||
MENU_BUTTON_OFFSET
|
||||
) - block.rootRect.left,
|
||||
top: block.rect.top - block.rootRect.top,
|
||||
opacity: visible ? 1 : 0,
|
||||
zIndex: 1,
|
||||
}}
|
||||
onDragStart={handleDragStart}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
{
|
||||
<LeftMenu
|
||||
anchorEl={anchorEl}
|
||||
editor={props.editor}
|
||||
hooks={props.hooks}
|
||||
onClose={() => setAnchorEl(undefined)}
|
||||
blockId={block.blockId}
|
||||
>
|
||||
<Draggable onClick={onClick}>
|
||||
<HandleChildIcon />
|
||||
</Draggable>
|
||||
</LeftMenu>
|
||||
}
|
||||
</DragComponent>
|
||||
)}
|
||||
<Line lineInfo={line} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Draggable = styled(Button)({
|
||||
cursor: 'grab',
|
||||
padding: '0',
|
||||
display: 'inlineFlex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'transparent',
|
||||
width: '24px',
|
||||
height: '24px',
|
||||
':hover': {
|
||||
backgroundColor: '#edeef0',
|
||||
borderRadius: '4px',
|
||||
},
|
||||
});
|
||||
|
||||
const LigoLeftMenu = styled('div')({
|
||||
backgroundColor: 'transparent',
|
||||
marginRight: '4px',
|
||||
});
|
||||
@@ -0,0 +1,176 @@
|
||||
import { BlockDomInfo, HookType } from '@toeverything/framework/virgo';
|
||||
import React, { StrictMode } from 'react';
|
||||
import { BasePlugin } from '../../base-plugin';
|
||||
import { ignoreBlockTypes } from './menu-config';
|
||||
import { LineInfoSubject, LeftMenuDraggable } from './LeftMenuDraggable';
|
||||
import { PluginRenderRoot } from '../../utils';
|
||||
import { Subject } from 'rxjs';
|
||||
import { domToRect, last, Point } from '@toeverything/utils';
|
||||
|
||||
export class LeftMenuPlugin extends BasePlugin {
|
||||
private mousedown?: boolean;
|
||||
private root?: PluginRenderRoot;
|
||||
private preBlockId: string;
|
||||
private hideTimer: number;
|
||||
|
||||
private _blockInfo: Subject<BlockDomInfo | undefined> = new Subject();
|
||||
private _lineInfo: LineInfoSubject = new Subject();
|
||||
|
||||
public static override get pluginName(): string {
|
||||
return 'left-menu';
|
||||
}
|
||||
|
||||
public override init(): void {
|
||||
this.hooks.addHook(
|
||||
HookType.AFTER_ON_NODE_MOUSE_MOVE,
|
||||
this._handleMouseMove
|
||||
);
|
||||
this.hooks.addHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_DOWN,
|
||||
this._handleMouseDown
|
||||
);
|
||||
this.hooks.addHook(
|
||||
HookType.ON_ROOTNODE_MOUSE_LEAVE,
|
||||
this._handleRootMouseLeave,
|
||||
this
|
||||
);
|
||||
this.hooks.addHook(HookType.ON_ROOTNODE_MOUSE_UP, this._handleMouseUp);
|
||||
this.hooks.addHook(
|
||||
HookType.AFTER_ON_NODE_DRAG_OVER,
|
||||
this._handleDragOverBlockNode
|
||||
);
|
||||
this.hooks.addHook(HookType.ON_ROOT_NODE_KEYDOWN, this._handleKeyDown);
|
||||
this.hooks.addHook(HookType.ON_ROOTNODE_DROP, this._onDrop);
|
||||
}
|
||||
|
||||
private _handleRootMouseLeave() {
|
||||
this._hideLeftMenu();
|
||||
}
|
||||
private _onDrop = () => {
|
||||
this.preBlockId = '';
|
||||
this._lineInfo.next(undefined);
|
||||
};
|
||||
private _handleDragOverBlockNode = async (
|
||||
event: React.DragEvent<Element>,
|
||||
blockInfo: BlockDomInfo
|
||||
) => {
|
||||
const { type, dom, blockId } = blockInfo;
|
||||
if (this.editor.dragDropManager.isDragBlock(event)) {
|
||||
event.preventDefault();
|
||||
if (ignoreBlockTypes.includes(type)) {
|
||||
return;
|
||||
}
|
||||
const direction =
|
||||
await this.editor.dragDropManager.checkBlockDragTypes(
|
||||
event,
|
||||
dom,
|
||||
blockId
|
||||
);
|
||||
this._lineInfo.next({ direction, blockInfo });
|
||||
}
|
||||
};
|
||||
|
||||
private _handleMouseMove = async (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) => {
|
||||
if (!this.hideTimer) {
|
||||
this.hideTimer = window.setTimeout(() => {
|
||||
if (this.mousedown) {
|
||||
this._hideLeftMenu();
|
||||
return;
|
||||
}
|
||||
this.hideTimer = 0;
|
||||
}, 300);
|
||||
}
|
||||
if (this.editor.readonly) {
|
||||
this._hideLeftMenu();
|
||||
return;
|
||||
}
|
||||
if (node.blockId !== this.preBlockId) {
|
||||
if (node.dom) {
|
||||
const mousePoint = new Point(e.clientX, e.clientY);
|
||||
const children = await (
|
||||
await this.editor.getBlockById(node.blockId)
|
||||
).children();
|
||||
// if mouse point is between the first and last child do not show left menu
|
||||
if (children.length) {
|
||||
const firstChildren = children[0];
|
||||
const lastChildren = last(children);
|
||||
if (firstChildren.dom && lastChildren.dom) {
|
||||
const firstChildrenRect = domToRect(firstChildren.dom);
|
||||
const lastChildrenRect = domToRect(lastChildren.dom);
|
||||
if (
|
||||
firstChildrenRect.top < mousePoint.y &&
|
||||
lastChildrenRect.bottom > mousePoint.y
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.preBlockId = node.blockId;
|
||||
this._showLeftMenu(node);
|
||||
}
|
||||
};
|
||||
|
||||
private _handleMouseUp(
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) {
|
||||
if (this.hideTimer) {
|
||||
window.clearTimeout(this.hideTimer);
|
||||
this.hideTimer = 0;
|
||||
}
|
||||
this.mousedown = false;
|
||||
}
|
||||
|
||||
private _handleMouseDown = (
|
||||
e: React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
node: BlockDomInfo
|
||||
) => {
|
||||
this.mousedown = true;
|
||||
};
|
||||
|
||||
private _hideLeftMenu = (): void => {
|
||||
this._blockInfo.next(undefined);
|
||||
};
|
||||
|
||||
private _handleKeyDown = () => {
|
||||
this._hideLeftMenu();
|
||||
};
|
||||
|
||||
private _showLeftMenu = (blockInfo: BlockDomInfo): void => {
|
||||
if (ignoreBlockTypes.includes(blockInfo.type)) {
|
||||
return;
|
||||
}
|
||||
this._blockInfo.next(blockInfo);
|
||||
};
|
||||
|
||||
protected override on_render(): void {
|
||||
this.root = new PluginRenderRoot({
|
||||
name: LeftMenuPlugin.pluginName,
|
||||
render: (...args) => {
|
||||
return this.editor.reactRenderRoot?.render(...args);
|
||||
},
|
||||
});
|
||||
this.root.mount();
|
||||
this.root.render(
|
||||
<StrictMode>
|
||||
<LeftMenuDraggable
|
||||
key={Math.random() + ''}
|
||||
defaultVisible={true}
|
||||
editor={this.editor}
|
||||
hooks={this.hooks}
|
||||
blockInfo={this._blockInfo}
|
||||
lineInfo={this._lineInfo}
|
||||
/>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
// TODO: rxjs
|
||||
this.root?.unmount();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import { BlockFlavorKeys, Protocol } from '@toeverything/datasource/db-service';
|
||||
import { Virgo, PluginHooks } from '@toeverything/framework/virgo';
|
||||
import { CommandMenuContainer } from '../command-menu/Container';
|
||||
import { defaultCategoriesList, defaultTypeList } from '../command-menu/config';
|
||||
interface TurnIntoMenuProps {
|
||||
editor: Virgo;
|
||||
hooks: PluginHooks;
|
||||
blockId: string;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const TurnIntoMenu = ({
|
||||
blockId,
|
||||
editor,
|
||||
hooks,
|
||||
onClose,
|
||||
}: TurnIntoMenuProps) => {
|
||||
const handle_select = (type: string) => {
|
||||
if (Protocol.Block.Type[type as BlockFlavorKeys]) {
|
||||
editor.commands.blockCommands.convertBlock(
|
||||
blockId,
|
||||
type as BlockFlavorKeys
|
||||
);
|
||||
onClose && onClose();
|
||||
}
|
||||
};
|
||||
return (
|
||||
<CommandMenuContainer
|
||||
editor={editor}
|
||||
hooks={hooks}
|
||||
isShow={true}
|
||||
blockId={blockId}
|
||||
onSelected={handle_select}
|
||||
types={defaultTypeList}
|
||||
categories={defaultCategoriesList}
|
||||
style={{ position: 'relative', boxShadow: 'none', padding: '0' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
import { BlockFlavorKeys, Protocol } from '@toeverything/datasource/db-service';
|
||||
import ShortTextIcon from '@mui/icons-material/ShortText';
|
||||
import TitleIcon from '@mui/icons-material/Title';
|
||||
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
|
||||
import HorizontalRuleIcon from '@mui/icons-material/HorizontalRule';
|
||||
import NotificationsNoneIcon from '@mui/icons-material/NotificationsNone';
|
||||
import {
|
||||
CodeBlockInlineIcon,
|
||||
PagesIcon,
|
||||
} from '@toeverything/components/common';
|
||||
import ListIcon from '@mui/icons-material/List';
|
||||
export const MENU_WIDTH = 14;
|
||||
export const pageConvertIconSize = 24;
|
||||
type MenuItem = {
|
||||
name: string[];
|
||||
title: string;
|
||||
blockType: string;
|
||||
render?({ renderNode }: { renderNode: any }): void;
|
||||
icon: typeof ShortTextIcon;
|
||||
params?: Record<string, any>;
|
||||
disable?: boolean;
|
||||
};
|
||||
|
||||
const textTypeBlocks: MenuItem[] = [
|
||||
{
|
||||
name: ['text'], // name represents the search keyword
|
||||
title: 'Text',
|
||||
blockType: Protocol.Block.Type.text,
|
||||
icon: ShortTextIcon,
|
||||
},
|
||||
{
|
||||
name: ['quote'],
|
||||
title: 'Quote',
|
||||
blockType: Protocol.Block.Type.quote,
|
||||
icon: ShortTextIcon,
|
||||
},
|
||||
{
|
||||
name: ['page'],
|
||||
title: 'Page',
|
||||
blockType: Protocol.Block.Type.page,
|
||||
icon: PagesIcon as any,
|
||||
},
|
||||
{
|
||||
name: ['todo'],
|
||||
title: 'To-do list',
|
||||
blockType: Protocol.Block.Type.todo,
|
||||
icon: ListIcon,
|
||||
},
|
||||
{
|
||||
name: ['heading1'],
|
||||
title: 'Heading 1',
|
||||
blockType: Protocol.Block.Type.heading1,
|
||||
icon: TitleIcon,
|
||||
},
|
||||
{
|
||||
name: ['heading2'],
|
||||
title: 'Heading 2',
|
||||
blockType: Protocol.Block.Type.heading2,
|
||||
icon: TitleIcon,
|
||||
},
|
||||
{
|
||||
name: ['heading3'],
|
||||
title: 'Heading 3',
|
||||
blockType: Protocol.Block.Type.heading3,
|
||||
icon: TitleIcon,
|
||||
},
|
||||
{
|
||||
name: ['code'],
|
||||
title: 'Code',
|
||||
blockType: Protocol.Block.Type.code,
|
||||
icon: CodeBlockInlineIcon as any,
|
||||
},
|
||||
{
|
||||
name: ['bullet'],
|
||||
title: 'Bullet List',
|
||||
blockType: Protocol.Block.Type.bullet,
|
||||
icon: FormatListBulletedIcon,
|
||||
},
|
||||
{
|
||||
name: ['call', 'callout'],
|
||||
title: 'Callout',
|
||||
blockType: Protocol.Block.Type.callout,
|
||||
icon: NotificationsNoneIcon,
|
||||
},
|
||||
{
|
||||
name: ['div', 'divider'],
|
||||
title: 'Divider',
|
||||
blockType: Protocol.Block.Type.divider,
|
||||
icon: HorizontalRuleIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export const addMenuList = [...textTypeBlocks].filter(v => v);
|
||||
|
||||
export const textConvertMenuList = textTypeBlocks;
|
||||
|
||||
export const ignoreBlockTypes: BlockFlavorKeys[] = [
|
||||
Protocol.Block.Type.workspace,
|
||||
Protocol.Block.Type.page,
|
||||
Protocol.Block.Type.group,
|
||||
Protocol.Block.Type.title,
|
||||
Protocol.Block.Type.grid,
|
||||
Protocol.Block.Type.gridItem,
|
||||
];
|
||||
Reference in New Issue
Block a user