diff --git a/ui/src/components/nodes/Code.tsx b/ui/src/components/nodes/Code.tsx index 8aaa59ce..b321200d 100644 --- a/ui/src/components/nodes/Code.tsx +++ b/ui/src/components/nodes/Code.tsx @@ -23,7 +23,6 @@ import ReactFlow, { NodeProps, useStore as useReactFlowStore, } from "reactflow"; -import "reactflow/dist/style.css"; import Box from "@mui/material/Box"; import InputBase from "@mui/material/InputBase"; diff --git a/ui/src/components/nodes/Rich.tsx b/ui/src/components/nodes/Rich.tsx index a9e64299..ea5c91c2 100644 --- a/ui/src/components/nodes/Rich.tsx +++ b/ui/src/components/nodes/Rich.tsx @@ -5,6 +5,7 @@ import { useContext, useEffect, memo, + useMemo, } from "react"; import * as React from "react"; @@ -30,7 +31,6 @@ import ReactFlow, { Node, useStore as useReactFlowStore, } from "reactflow"; -import "reactflow/dist/style.css"; import Ansi from "ansi-to-react"; import Box from "@mui/material/Box"; @@ -114,7 +114,6 @@ import { markInputRule } from "@remirror/core-utils"; import { TableExtension } from "@remirror/extension-react-tables"; import { GenIcon, IconBase } from "@remirror/react-components"; import "remirror/styles/all.css"; -import "./remirror-size.css"; import { styled } from "@mui/material"; import { MyYjsExtension } from "./extensions/YjsRemirror"; @@ -128,11 +127,15 @@ import { TaskListExtension, } from "./extensions/list"; +import { CodePodSyncExtension } from "./extensions/codepodSync"; + import { LinkExtension, LinkToolbar } from "./extensions/link"; import { NewPodButtons, level2fontsize } from "./utils"; import { RepoContext } from "../../lib/store"; +import "./remirror-size.css"; + /** * This is the toolbar when user select some text. It allows user to change the * markups of the text, e.g. bold, italic, underline, highlight, etc. @@ -303,6 +306,11 @@ const MyEditor = ({ autoLinkAllowedTLDs: ["dev", ...TOP_50_TLDS], }), new UnderlineExtension(), + new CodePodSyncExtension({ + id: id, + setPodContent: setPodContent, + setPodRichContent: setPodRichContent, + }), ], onError: ({ json, invalidContent, transformers }) => { // Automatically remove all invalid nodes and marks. @@ -329,8 +337,6 @@ const MyEditor = ({ stringHandler: "markdown", }); - let index_onChange = 0; - return ( { - let nextState = parameter.state; - setState(nextState); - // TODO sync with DB and yjs - if (parameter.tr?.docChanged) { - setPodRichContent({ - id, - richContent: parameter.helpers.getMarkdown(), - }); - index_onChange += 1; - if (index_onChange == 1) { - if ( - JSON.stringify(pod.content) === - JSON.stringify(nextState.doc.toJSON()) - ) { - // This is the first onChange trigger, and the content is the same. Skip it. - return; - } - } - setPodContent({ id, content: nextState.doc.toJSON() }); - } - }} > {/* */} diff --git a/ui/src/components/nodes/Scope.tsx b/ui/src/components/nodes/Scope.tsx index fa8ca5b1..71a2538c 100644 --- a/ui/src/components/nodes/Scope.tsx +++ b/ui/src/components/nodes/Scope.tsx @@ -23,7 +23,6 @@ import ReactFlow, { NodeProps, useStore as useReactFlowStore, } from "reactflow"; -import "reactflow/dist/style.css"; import Box from "@mui/material/Box"; import InputBase from "@mui/material/InputBase"; diff --git a/ui/src/components/nodes/extensions/codepodSync.ts b/ui/src/components/nodes/extensions/codepodSync.ts new file mode 100644 index 00000000..7df6678d --- /dev/null +++ b/ui/src/components/nodes/extensions/codepodSync.ts @@ -0,0 +1,53 @@ +import TurndownService from "turndown"; + +import { PlainExtension, StateUpdateLifecycleProps, extension } from "remirror"; + +interface CodePodSyncOptions { + // Options are `Dynamic` by default. + id: string; + setPodContent: any; + setPodRichContent: any; +} + +@extension({ + defaultOptions: { + id: "defaultId", + setPodContent: () => {}, + setPodRichContent: () => {}, + }, + staticKeys: [], + handlerKeys: [], + customHandlerKeys: [], +}) +/** + * This extension is used to sync the content of the editor with the pod. + */ +export class CodePodSyncExtension extends PlainExtension { + firstUpdate = true; + turndownService = new TurndownService(); + get name(): string { + return "codepod-sync"; + } + onStateUpdate({ state, tr }: StateUpdateLifecycleProps) { + if (tr?.docChanged) { + this.options.setPodContent( + { + id: this.options.id, + content: state.doc.toJSON(), + }, + // The first onChange event is triggered wehn the content is the same. + // Skip it. + this.firstUpdate + ); + this.firstUpdate = false; + } + + var markdown = this.turndownService.turndown( + this.store.helpers.getHTML(state) + ); + this.options.setPodRichContent({ + id: this.options.id, + richContent: markdown, + }); + } +} diff --git a/ui/src/lib/store/podSlice.tsx b/ui/src/lib/store/podSlice.tsx index c9173629..3610eb34 100644 --- a/ui/src/lib/store/podSlice.tsx +++ b/ui/src/lib/store/podSlice.tsx @@ -33,7 +33,12 @@ export interface PodSlice { dirty?: boolean ) => void; setPodName: ({ id, name }: { id: string; name: string }) => void; - setPodContent: ({ id, content }: { id: string; content: string }) => void; + setPodContent: ( + { id, content }: { id: string; content: string }, + // Whether to perform additional verification of whether content == + // pod.content before setting the dirty flag.. + verify?: boolean + ) => void; setPodRichContent: ({ id, richContent, @@ -87,10 +92,15 @@ export const createPodSlice: StateCreator = ( // @ts-ignore "setPodName" ), - setPodContent: ({ id, content }) => + setPodContent: ({ id, content }, verify = false) => set( produce((state) => { let pod = state.pods[id]; + if (verify) { + if (JSON.stringify(pod.content) === JSON.stringify(content)) { + return; + } + } pod.content = content; pod.dirty = true; }),