mirror of https://github.com/fantasticit/think.git
feat: improve editor
This commit is contained in:
parent
3f981d44b0
commit
612754fe4b
|
@ -53,7 +53,6 @@
|
|||
"@tiptap/extension-underline": "^2.0.0-beta.23",
|
||||
"@tiptap/react": "^2.0.0-beta.107",
|
||||
"@tiptap/suggestion": "^2.0.0-beta.90",
|
||||
"@traptitech/markdown-it-katex": "^3.5.0",
|
||||
"axios": "^0.25.0",
|
||||
"classnames": "^2.3.1",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
|
@ -66,11 +65,8 @@
|
|||
"markdown-it-anchor": "^8.4.1",
|
||||
"markdown-it-container": "^3.0.0",
|
||||
"markdown-it-emoji": "^2.0.0",
|
||||
"markdown-it-footnote": "^3.0.3",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"marked": "^4.0.12",
|
||||
"next": "12.0.10",
|
||||
"prosemirror-markdown": "^1.7.0",
|
||||
"prosemirror-tables": "^1.1.1",
|
||||
|
|
|
@ -78,8 +78,8 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
|
|||
CollaborationEventEmitter.on(KEY, ({ states: users }) => {
|
||||
const newCollaborationUsers = users
|
||||
.filter(Boolean)
|
||||
.map((state) => ({ ...state.user, clientId: state.clientId }))
|
||||
.filter(Boolean);
|
||||
.filter((state) => state.user)
|
||||
.map((state) => ({ ...state.user, clientId: state.clientId }));
|
||||
|
||||
if (
|
||||
collaborationUsers.length === newCollaborationUsers.length &&
|
||||
|
|
|
@ -6,7 +6,6 @@ import { ILoginUser, IAuthority } from '@think/domains';
|
|||
import { useToggle } from 'hooks/useToggle';
|
||||
import {
|
||||
DEFAULT_EXTENSION,
|
||||
Document,
|
||||
DocumentWithTitle,
|
||||
getCollaborationExtension,
|
||||
getCollaborationCursorExtension,
|
||||
|
@ -16,6 +15,8 @@ import {
|
|||
} from 'components/tiptap';
|
||||
import { DataRender } from 'components/data-render';
|
||||
import { joinUser } from 'components/document/collaboration';
|
||||
import { debounce } from 'helpers/debounce';
|
||||
import { changeTitle } from './index';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
interface IProps {
|
||||
|
@ -44,10 +45,6 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
|||
});
|
||||
}, [documentId, user.token]);
|
||||
|
||||
const noTitleEditor = useEditor({
|
||||
extensions: [...DEFAULT_EXTENSION, Document],
|
||||
});
|
||||
|
||||
const editor = useEditor({
|
||||
editable: authority && authority.editable,
|
||||
extensions: [
|
||||
|
@ -56,10 +53,12 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
|||
getCollaborationExtension(provider),
|
||||
getCollaborationCursorExtension(provider, user),
|
||||
],
|
||||
editorProps: {
|
||||
// @ts-ignore
|
||||
noTitleEditor,
|
||||
},
|
||||
onTransaction: debounce(({ transaction }) => {
|
||||
try {
|
||||
const title = transaction.doc.content.firstChild.content.firstChild.textContent;
|
||||
changeTitle(title);
|
||||
} catch (e) {}
|
||||
}, 200),
|
||||
});
|
||||
const [loading, toggleLoading] = useToggle(true);
|
||||
|
||||
|
@ -68,8 +67,6 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
|||
toggleLoading(false);
|
||||
});
|
||||
|
||||
// provid
|
||||
|
||||
provider.on('status', async ({ status }) => {
|
||||
console.log('status', status);
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
z-index: 110;
|
||||
background-color: var(--semi-color-nav-bg);
|
||||
height: 60px;
|
||||
user-select: none;
|
||||
|
||||
> div {
|
||||
overflow: auto;
|
||||
|
@ -39,6 +40,7 @@
|
|||
overflow: hidden;
|
||||
background-color: var(--semi-color-nav-bg);
|
||||
border-bottom: 1px solid var(--semi-color-border);
|
||||
user-select: none;
|
||||
|
||||
&.isStandardWidth {
|
||||
justify-content: center;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Router from 'next/router';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Layout, Nav, Skeleton, Typography, Space, Button, Tooltip, Spin, Popover } from '@douyinfe/semi-ui';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Nav, Skeleton, Typography, Space, Button, Tooltip, Spin, Popover } from '@douyinfe/semi-ui';
|
||||
import { IconChevronLeft, IconArticle } from '@douyinfe/semi-icons';
|
||||
import { useUser } from 'data/user';
|
||||
import { useDocumentDetail } from 'data/document';
|
||||
|
@ -13,12 +13,19 @@ import { DocumentStar } from 'components/document/star';
|
|||
import { DocumentCollaboration } from 'components/document/collaboration';
|
||||
import { DocumentStyle } from 'components/document/style';
|
||||
import { useDocumentStyle } from 'hooks/useDocumentStyle';
|
||||
import { EventEmitter } from 'helpers/event-emitter';
|
||||
import { Editor } from './editor';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
const { Text } = Typography;
|
||||
|
||||
const em = new EventEmitter();
|
||||
const TITLE_CHANGE_EVENT = 'TITLE_CHANGE_EVENT';
|
||||
|
||||
export const changeTitle = (title) => {
|
||||
em.emit(TITLE_CHANGE_EVENT, title);
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
documentId: string;
|
||||
}
|
||||
|
@ -30,7 +37,7 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
|||
const editorWrapClassNames = useMemo(() => {
|
||||
return width === 'standardWidth' ? styles.isStandardWidth : styles.isFullWidth;
|
||||
}, [width]);
|
||||
|
||||
const [title, setTitle] = useState('');
|
||||
const { user } = useUser();
|
||||
const { data: documentAndAuth, loading: docAuthLoading, error: docAuthError } = useDocumentDetail(documentId);
|
||||
const { document, authority } = documentAndAuth || {};
|
||||
|
@ -54,13 +61,21 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
|||
}
|
||||
normalContent={() => (
|
||||
<Text ellipsis={{ showTooltip: true }} style={{ width: ~~(windowWith / 4) }}>
|
||||
{document.title}
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
em.on(TITLE_CHANGE_EVENT, setTitle);
|
||||
|
||||
return () => {
|
||||
em.destroy();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={styles.wrap}>
|
||||
<header>
|
||||
|
@ -91,10 +106,9 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
|||
<Spin></Spin>
|
||||
</div>
|
||||
}
|
||||
error={null}
|
||||
error={docAuthError}
|
||||
normalContent={() => {
|
||||
return (
|
||||
// <div style={{ fontSize }}>
|
||||
<>
|
||||
<Seo title={document.title} />
|
||||
<Editor
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
z-index: 110;
|
||||
background-color: var(--semi-color-nav-bg);
|
||||
height: 60px;
|
||||
user-select: none;
|
||||
|
||||
> div {
|
||||
overflow: auto;
|
||||
|
@ -39,6 +40,7 @@
|
|||
overflow: hidden;
|
||||
background-color: var(--semi-color-nav-bg);
|
||||
border-bottom: 1px solid var(--semi-color-border);
|
||||
user-select: none;
|
||||
|
||||
&.isStandardWidth {
|
||||
> div {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.items {
|
||||
width: 160px;
|
||||
max-height: 50vh;
|
||||
max-height: 40vh;
|
||||
overflow: auto;
|
||||
padding: 0.2rem;
|
||||
position: relative;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.wrap {
|
||||
margin: 8px 0;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { Popover, TextArea, Typography, Space } from '@douyinfe/semi-ui';
|
||||
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
||||
import katex from 'katex';
|
||||
import { Checkbox } from '@douyinfe/semi-ui';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
export const TaskItemWrapper = ({ editor, node, updateAttributes }) => {
|
||||
const isEditable = editor.isEditable;
|
||||
const { checked } = node.attrs;
|
||||
|
||||
console.log(node.attrs);
|
||||
|
||||
return (
|
||||
<NodeViewWrapper as="span" className={styles.wrap} contentEditable={false}>
|
||||
<Checkbox checked={checked} onChange={(e) => updateAttributes({ checked: e.target.checked })} />
|
||||
<NodeViewContent></NodeViewContent>
|
||||
</NodeViewWrapper>
|
||||
);
|
||||
};
|
|
@ -11,7 +11,7 @@ const attrs = {
|
|||
bdo: ['dir'],
|
||||
};
|
||||
|
||||
export const HTMLMarks = marks.map(({ name, tag }) =>
|
||||
export const HTMLMarks = marks.slice(1).map(({ name, tag }) =>
|
||||
Mark.create({
|
||||
name,
|
||||
tag,
|
||||
|
|
|
@ -116,7 +116,8 @@ export const Paste = Extension.create({
|
|||
return false;
|
||||
},
|
||||
clipboardTextSerializer: (slice) => {
|
||||
const doc = this.editor.schema.topNodeType.createAndFill(undefined, slice.content);
|
||||
const doc = slice.content;
|
||||
|
||||
if (!doc) {
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export const Table = BuiltInTable.extend({
|
|||
if (fixedWidth && totalWidth > 0) {
|
||||
HTMLAttributes.style = `width: ${totalWidth}px;`;
|
||||
} else if (totalWidth && totalWidth > 0) {
|
||||
HTMLAttributes.style = `min-width: ${totalWidth}px`;
|
||||
HTMLAttributes.style = `min-width: 100%`;
|
||||
} else {
|
||||
HTMLAttributes.style = null;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { wrappingInputRule, mergeAttributes } from '@tiptap/core';
|
||||
import { wrappingInputRule } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||
import { TaskItem as BuiltInTaskItem } from '@tiptap/extension-task-item';
|
||||
import { Plugin } from 'prosemirror-state';
|
||||
import { findParentNodeClosestToPos } from 'prosemirror-utils';
|
||||
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
|
||||
import { TaskItemWrapper } from '../components/taskItem';
|
||||
|
||||
const CustomTaskItem = BuiltInTaskItem.extend({
|
||||
parseHTML() {
|
||||
|
@ -27,35 +29,79 @@ const CustomTaskItem = BuiltInTaskItem.extend({
|
|||
];
|
||||
},
|
||||
|
||||
// addProseMirrorPlugins() {
|
||||
// return [
|
||||
// new Plugin({
|
||||
// props: {
|
||||
// // @ts-ignore
|
||||
// handleClick: (view, pos, event) => {
|
||||
// const state = view.state;
|
||||
// const schema = state.schema;
|
||||
// addNodeView() {
|
||||
// return ReactNodeViewRenderer(TaskItemWrapper);
|
||||
// },
|
||||
|
||||
// const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY });
|
||||
// const position = state.doc.resolve(coordinates.pos);
|
||||
// const parentList = findParentNodeClosestToPos(position, function (node) {
|
||||
// return node.type === schema.nodes.taskItem || node.type === schema.nodes.listItem;
|
||||
// });
|
||||
// // @ts-ignore
|
||||
// const isListClicked = event.target.tagName.toLowerCase() === 'li';
|
||||
// if (!isListClicked || !parentList || parentList.node.type !== schema.nodes.taskItem) {
|
||||
// return;
|
||||
// }
|
||||
// const tr = state.tr;
|
||||
// tr.setNodeMarkup(parentList.pos, schema.nodes.taskItem, {
|
||||
// checked: !parentList.node.attrs.checked,
|
||||
// });
|
||||
// view.dispatch(tr);
|
||||
// },
|
||||
// },
|
||||
// }),
|
||||
// ];
|
||||
// },
|
||||
addNodeView() {
|
||||
return ({ node, HTMLAttributes, getPos, editor }) => {
|
||||
const listItem = document.createElement('li');
|
||||
const checkboxWrapper = document.createElement('span');
|
||||
const content = document.createElement('div');
|
||||
|
||||
checkboxWrapper.contentEditable = 'false';
|
||||
|
||||
Object.entries(this.options.HTMLAttributes).forEach(([key, value]) => {
|
||||
listItem.setAttribute(key, value);
|
||||
});
|
||||
|
||||
listItem.dataset.checked = node.attrs.checked;
|
||||
listItem.append(checkboxWrapper, content);
|
||||
|
||||
Object.entries(HTMLAttributes).forEach(([key, value]) => {
|
||||
listItem.setAttribute(key, value);
|
||||
});
|
||||
|
||||
return {
|
||||
dom: listItem,
|
||||
contentDOM: content,
|
||||
update: (updatedNode) => {
|
||||
if (updatedNode.type !== this.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
listItem.dataset.checked = updatedNode.attrs.checked;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
// @ts-ignore
|
||||
handleClick: (view, pos, event) => {
|
||||
const state = view.state;
|
||||
const schema = state.schema;
|
||||
|
||||
const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY });
|
||||
const position = state.doc.resolve(coordinates.pos);
|
||||
const parentList = findParentNodeClosestToPos(position, function (node) {
|
||||
return node.type === schema.nodes.taskItem || node.type === schema.nodes.listItem;
|
||||
});
|
||||
if (!parentList) {
|
||||
return;
|
||||
}
|
||||
const element = view.nodeDOM(parentList.pos) as HTMLLIElement;
|
||||
if (element.tagName.toLowerCase() !== 'li') return;
|
||||
|
||||
const parentElement = element.parentElement;
|
||||
const type = parentElement && parentElement.getAttribute('data-type');
|
||||
if (!type || type.toLowerCase() !== 'tasklist') return;
|
||||
|
||||
const tr = state.tr;
|
||||
const nextValue = !(element.getAttribute('data-checked') === 'true');
|
||||
tr.setNodeMarkup(parentList.pos, schema.nodes.taskItem, {
|
||||
checked: nextValue,
|
||||
});
|
||||
view.dispatch(tr);
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
export const TaskItem = CustomTaskItem.configure({ nested: true });
|
||||
|
|
|
@ -11,6 +11,8 @@ import { HorizontalRule } from '../extensions/horizontalRule';
|
|||
import { Iframe } from '../extensions/iframe';
|
||||
import { Mind } from '../extensions/mind';
|
||||
import { Table } from '../extensions/table';
|
||||
import { TaskList } from '../extensions/taskList';
|
||||
import { TaskItem } from '../extensions/taskItem';
|
||||
import { Katex } from '../extensions/katex';
|
||||
import { DocumentReference } from '../extensions/documentReference';
|
||||
import { DocumentChildren } from '../extensions/documentChildren';
|
||||
|
@ -26,6 +28,8 @@ const OTHER_BUBBLE_MENU_TYPES = [
|
|||
Iframe.name,
|
||||
Mind.name,
|
||||
Table.name,
|
||||
TaskList.name,
|
||||
TaskItem.name,
|
||||
DocumentReference.name,
|
||||
DocumentChildren.name,
|
||||
Katex.name,
|
||||
|
|
|
@ -10,8 +10,6 @@ export const markdownToProsemirror = ({ schema, content, hasTitle }) => {
|
|||
|
||||
if (!html) return null;
|
||||
|
||||
console.log(html);
|
||||
|
||||
const parser = new DOMParser();
|
||||
const { body } = parser.parseFromString(html, 'text/html');
|
||||
body.append(document.createComment(content));
|
||||
|
|
|
@ -10,7 +10,7 @@ import { DocumentReference } from '../../../extensions/documentReference';
|
|||
import { HardBreak } from '../../../extensions/hardBreak';
|
||||
import { Heading } from '../../../extensions/heading';
|
||||
import { HorizontalRule } from '../../../extensions/horizontalRule';
|
||||
import { marks, HTMLMarks } from '../../../extensions/htmlMarks';
|
||||
import { marks } from '../../../extensions/htmlMarks';
|
||||
import { Iframe } from '../../../extensions/iframe';
|
||||
import { Image } from '../../../extensions/image';
|
||||
import { Italic } from '../../../extensions/italic';
|
||||
|
@ -29,6 +29,7 @@ import { TableRow } from '../../../extensions/tableRow';
|
|||
import { Text } from '../../../extensions/text';
|
||||
import { TaskItem } from '../../../extensions/taskItem';
|
||||
import { TaskList } from '../../../extensions/taskList';
|
||||
import { TextStyle } from '../../../extensions/textStyle';
|
||||
import { Title } from '../../../extensions/title';
|
||||
import {
|
||||
isPlainURL,
|
||||
|
@ -66,6 +67,8 @@ const SerializerConfig = {
|
|||
mixable: true,
|
||||
expelEnclosingWhitespace: true,
|
||||
},
|
||||
// FIXME: 如何导出 style?
|
||||
[TextStyle.name]: { open: '', close: '', mixable: true, expelEnclosingWhitespace: true },
|
||||
...marks.reduce(
|
||||
(acc, { name, tag }) => ({
|
||||
...acc,
|
||||
|
@ -151,10 +154,9 @@ const SerializerConfig = {
|
|||
*/
|
||||
export const prosemirrorToMarkdown = ({ content }) => {
|
||||
const serializer = new ProseMirrorMarkdownSerializer(SerializerConfig.nodes, SerializerConfig.marks);
|
||||
|
||||
console.log(content);
|
||||
|
||||
return serializer.serialize(content, {
|
||||
const markdown = serializer.serialize(content, {
|
||||
tightLists: true,
|
||||
});
|
||||
|
||||
return markdown;
|
||||
};
|
||||
|
|
|
@ -178,11 +178,31 @@
|
|||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
user-select: none;
|
||||
transform: translateY(2px);
|
||||
> span {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid var(--semi-color-border);
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
|
||||
&::after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
left: 4.071429px;
|
||||
top: -0.357143px;
|
||||
width: 6.714286px;
|
||||
height: 12.142857px;
|
||||
border: 2px solid #fff;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
transition: all 0.1s cubic-bezier(0.71, -0.46, 0.88, 0.6), opacity 0.1s;
|
||||
transform: rotate(45deg) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
|
@ -193,6 +213,15 @@
|
|||
&[data-checked='true'] {
|
||||
color: var(--semi-color-text-2);
|
||||
|
||||
> span {
|
||||
background-color: var(--semi-color-primary);
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ export class CreateDocumentDto {
|
|||
@IsString({ message: '文档名称类型错误(正确类型为:String)' })
|
||||
@IsNotEmpty({ message: '文档名称不能为空' })
|
||||
@MinLength(1, { message: '文档名称至少1个字符' })
|
||||
@MaxLength(50, { message: '文档名称最多50个字符' })
|
||||
@IsOptional()
|
||||
readonly title?: string;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ export class DocumentEntity {
|
|||
@Column({ type: 'varchar', comment: '父文档 Id', default: null })
|
||||
public parentDocumentId: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 50, comment: '文档标题', default: '' })
|
||||
@Column({ type: 'varchar', default: '未命名文档', comment: '文档标题' })
|
||||
public title: string;
|
||||
|
||||
@Column({ type: 'text', comment: '文档内容' })
|
||||
|
|
|
@ -87,7 +87,6 @@ importers:
|
|||
'@tiptap/extension-underline': ^2.0.0-beta.23
|
||||
'@tiptap/react': ^2.0.0-beta.107
|
||||
'@tiptap/suggestion': ^2.0.0-beta.90
|
||||
'@traptitech/markdown-it-katex': ^3.5.0
|
||||
'@types/node': 17.0.13
|
||||
'@types/react': 17.0.38
|
||||
axios: ^0.25.0
|
||||
|
@ -102,11 +101,8 @@ importers:
|
|||
markdown-it-anchor: ^8.4.1
|
||||
markdown-it-container: ^3.0.0
|
||||
markdown-it-emoji: ^2.0.0
|
||||
markdown-it-footnote: ^3.0.3
|
||||
markdown-it-sub: ^1.0.0
|
||||
markdown-it-sup: ^1.0.0
|
||||
markdown-it-task-lists: ^2.1.1
|
||||
marked: ^4.0.12
|
||||
next: 12.0.10
|
||||
prosemirror-markdown: ^1.7.0
|
||||
prosemirror-tables: ^1.1.1
|
||||
|
@ -166,7 +162,6 @@ importers:
|
|||
'@tiptap/extension-underline': 2.0.0-beta.23_@tiptap+core@2.0.0-beta.171
|
||||
'@tiptap/react': 2.0.0-beta.107_a3fcdb91535fe17b69dfabaa94f3bb3d
|
||||
'@tiptap/suggestion': 2.0.0-beta.90_@tiptap+core@2.0.0-beta.171
|
||||
'@traptitech/markdown-it-katex': 3.5.0
|
||||
axios: 0.25.0
|
||||
classnames: 2.3.1
|
||||
copy-to-clipboard: 3.3.1
|
||||
|
@ -179,11 +174,8 @@ importers:
|
|||
markdown-it-anchor: 8.4.1_markdown-it@12.3.2
|
||||
markdown-it-container: 3.0.0
|
||||
markdown-it-emoji: 2.0.0
|
||||
markdown-it-footnote: 3.0.3
|
||||
markdown-it-sub: 1.0.0
|
||||
markdown-it-sup: 1.0.0
|
||||
markdown-it-task-lists: 2.1.1
|
||||
marked: 4.0.12
|
||||
next: 12.0.10_react-dom@17.0.2+react@17.0.2
|
||||
prosemirror-markdown: 1.7.0
|
||||
prosemirror-tables: 1.1.1
|
||||
|
@ -1953,12 +1945,6 @@ packages:
|
|||
resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
/@traptitech/markdown-it-katex/3.5.0:
|
||||
resolution: {integrity: sha512-7/GI3ETKJjrZD9+azn7WraDWo0ZQ6grtzR4I36qu7U0vOJMBtC+znX7UghdOScrgGnxqGvgWm07SYnlcCtdCvw==}
|
||||
dependencies:
|
||||
katex: 0.15.2
|
||||
dev: false
|
||||
|
||||
/@tsconfig/node10/1.0.8:
|
||||
resolution: {integrity: sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==}
|
||||
dev: true
|
||||
|
@ -6008,10 +5994,6 @@ packages:
|
|||
resolution: {integrity: sha512-39j7/9vP/CPCKbEI44oV8yoPJTpvfeReTn/COgRhSpNrjWF3PfP/JUxxB0hxV6ynOY8KH8Y8aX9NMDdo6z+6YQ==}
|
||||
dev: false
|
||||
|
||||
/markdown-it-footnote/3.0.3:
|
||||
resolution: {integrity: sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==}
|
||||
dev: false
|
||||
|
||||
/markdown-it-sub/1.0.0:
|
||||
resolution: {integrity: sha1-N1/WAm6ufdywEkl/ZBEZXqHjr+g=}
|
||||
dev: false
|
||||
|
@ -6020,10 +6002,6 @@ packages:
|
|||
resolution: {integrity: sha1-y5yf+RpSVawI8/09YyhuFd8KH8M=}
|
||||
dev: false
|
||||
|
||||
/markdown-it-task-lists/2.1.1:
|
||||
resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==}
|
||||
dev: false
|
||||
|
||||
/markdown-it/12.3.2:
|
||||
resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==}
|
||||
hasBin: true
|
||||
|
@ -6035,12 +6013,6 @@ packages:
|
|||
uc.micro: 1.0.6
|
||||
dev: false
|
||||
|
||||
/marked/4.0.12:
|
||||
resolution: {integrity: sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==}
|
||||
engines: {node: '>= 12'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/mdurl/1.0.1:
|
||||
resolution: {integrity: sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=}
|
||||
dev: false
|
||||
|
|
Loading…
Reference in New Issue