From cb3898b96914b0f48621f9151a6f42a5e3b9353d Mon Sep 17 00:00:00 2001 From: liqingwei Date: Sun, 5 Sep 2021 16:02:26 +0800 Subject: [PATCH 1/7] feat: binding yjs --- components/container/edit-container.tsx | 9 ++- components/editor/editor.tsx | 6 +- components/editor/extensions/index.ts | 3 +- components/editor/extensions/y-sync.ts | 25 +++++++ components/note-nav.tsx | 10 +-- libs/server/note.ts | 4 +- libs/server/store/providers/base.ts | 2 +- libs/server/store/providers/s3.ts | 2 +- libs/shared/note.ts | 1 + libs/shared/str.ts | 7 +- libs/shared/y-doc.ts | 20 ++++++ libs/web/api/note.ts | 2 +- libs/web/editor/y-doc.ts | 96 +++++++++++++++++++++++++ libs/web/state/editor.ts | 45 +++++++++++- package.json | 6 +- pages/api/notes/[id]/index.ts | 36 ++++++---- yarn.lock | 33 +++++++++ 17 files changed, 269 insertions(+), 38 deletions(-) create mode 100644 components/editor/extensions/y-sync.ts create mode 100644 libs/shared/y-doc.ts create mode 100644 libs/web/editor/y-doc.ts diff --git a/components/container/edit-container.tsx b/components/container/edit-container.tsx index 8e59a4af8..0dbf6be33 100644 --- a/components/container/edit-container.tsx +++ b/components/container/edit-container.tsx @@ -55,9 +55,11 @@ export const EditContainer = () => { return } } catch (msg) { - if (msg.name !== 'AbortError') { - toast(msg.message, 'error') - router.push('/', undefined, { shallow: true }) + if (msg instanceof Error) { + if (msg.name !== 'AbortError') { + toast(msg.message, 'error') + router.push('/', undefined, { shallow: true }) + } } } } else { @@ -73,6 +75,7 @@ export const EditContainer = () => { } if (!isNew && id !== 'new') { + // todo: store in localStorage mutateSettings({ last_visit: `/${id}`, }) diff --git a/components/editor/editor.tsx b/components/editor/editor.tsx index 5fa5733ec..165bc5708 100644 --- a/components/editor/editor.tsx +++ b/components/editor/editor.tsx @@ -2,7 +2,6 @@ import { FC, useEffect, useState } from 'react' import { use100vh } from 'react-div-100vh' import MarkdownEditor, { Props } from 'rich-markdown-editor' import { useEditorTheme } from './theme' -import useMounted from 'libs/web/hooks/use-mounted' import Tooltip from './tooltip' import extensions from './extensions' import EditorState from 'libs/web/state/editor' @@ -21,13 +20,11 @@ const Editor: FC = ({ readOnly, isPreview }) => { onClickLink, onUploadImage, onHoverLink, - onEditorChange, backlinks, editorEl, note, } = EditorState.useContainer() const height = use100vh() - const mounted = useMounted() const editorTheme = useEditorTheme() const [hasMinHeight, setHasMinHeight] = useState(true) const toast = useToast() @@ -44,9 +41,8 @@ const Editor: FC = ({ readOnly, isPreview }) => { onUploadImage(file, note?.id)} diff --git a/components/editor/extensions/index.ts b/components/editor/extensions/index.ts index e2c8a934d..8b10957e9 100644 --- a/components/editor/extensions/index.ts +++ b/components/editor/extensions/index.ts @@ -1,6 +1,7 @@ import { Extension } from 'rich-markdown-editor' import Bracket from './bracket' +import YSync from './y-sync' -const extensions: Extension[] = [new Bracket()] +const extensions: Extension[] = [new Bracket(), new YSync()] export default extensions diff --git a/components/editor/extensions/y-sync.ts b/components/editor/extensions/y-sync.ts new file mode 100644 index 000000000..f6a5eb691 --- /dev/null +++ b/components/editor/extensions/y-sync.ts @@ -0,0 +1,25 @@ +import { Extension } from 'rich-markdown-editor' +import { ySyncPlugin } from 'y-prosemirror' +import * as Y from 'yjs' + +export default class YSync extends Extension { + get name() { + return 'y-sync' + } + + yDoc?: Y.Doc + + constructor(options?: Record) { + super(options) + } + + get plugins() { + if (this.yDoc) { + this.yDoc.destroy() + } + this.yDoc = new Y.Doc() + const type = this.yDoc.get('prosemirror', Y.XmlFragment) + + return [ySyncPlugin(type)] + } +} diff --git a/components/note-nav.tsx b/components/note-nav.tsx index 7ea41753a..e7b1b0aea 100644 --- a/components/note-nav.tsx +++ b/components/note-nav.tsx @@ -58,6 +58,8 @@ const NoteNav = () => { [note, menu] ) + const getTitle = (title?: string) => title ?? t('Untitled') + return (