Untitled
unknown
javascript
a year ago
6.5 kB
8
Indexable
// editor.js import { savePage } from "@/actions/save-page"; import { useToast } from "@/hooks/useToast"; import { useEdgeStore } from "@/lib/edgestore"; import { initSocket } from "@/lib/socket"; import { AdmonitionDirectiveDescriptor, codeBlockPlugin, codeMirrorPlugin, diffSourcePlugin, directivesPlugin, frontmatterPlugin, headingsPlugin, imagePlugin, linkDialogPlugin, linkPlugin, listsPlugin, markdownShortcutPlugin, MDXEditor, quotePlugin, tablePlugin, thematicBreakPlugin, toolbarPlugin, } from "@mdxeditor/editor"; import Toast from "awesome-toast-component"; import { useSession } from "next-auth/react"; import { useRouter, useSearchParams } from "next/navigation"; import { useCallback, useEffect, useMemo, useRef, useTransition } from "react"; import { Toolbar } from "./Toolbar"; let saveToDBTimeout = null; let intervalToSaveInDb = 1800; const Editor = ({ markdown, isViewOnly }) => { const session = useSession(); const params = useSearchParams(); const groupId = params.get("g"); const pageNumber = params.get("page"); const mdRef = useRef(null); const [ToastSuccess, ToastError] = useToast(); const [isPending, startTransition] = useTransition(); const router = useRouter(); const socketRef = useRef(null); const { edgestore } = useEdgeStore(); const allPlugins = useMemo( () => (diffMarkdown, isSaving) => [ toolbarPlugin({ toolbarContents: () => ( <> {isViewOnly ? ( <span> <i>View only mode</i> </span> ) : ( <Toolbar isSaving={isSaving} /> )} </> ), }), listsPlugin(), quotePlugin(), headingsPlugin(), linkPlugin(), linkDialogPlugin(), imagePlugin({ imageUploadHandler: async (e) => { const tst = ToastSuccess("Uploading " + 0 + "%", { timeout: 2000, }); if (e) { const res = await edgestore.publicFiles.upload({ file: e, onProgressChange: (progress) => { tst.setMessage("Uploading " + progress + "%"); }, }); tst.hide(); return res.url; } else { ToastError("Uploading error"); return "/error-upload.png"; } }, }), tablePlugin(), thematicBreakPlugin(), frontmatterPlugin(), codeBlockPlugin({ defaultCodeBlockLanguage: "txt" }), codeMirrorPlugin({ codeBlockLanguages: { js: "JavaScript", css: "CSS", txt: "text", tsx: "TypeScript", }, }), directivesPlugin({ directiveDescriptors: [AdmonitionDirectiveDescriptor], }), diffSourcePlugin({ viewMode: "rich-text", diffMarkdown }), markdownShortcutPlugin(), ], [] ); useEffect(() => { mdRef.current.setMarkdown(markdown); const init = async () => { // connect to websocket server socketRef.current = await initSocket(); // handle websockets error socketRef.current.on("connect_error", () => { ToastError("Error establishing connection"); router.push("/"); }); socketRef.current.on("connect_failed", () => { ToastError("Error establishing connection"); router.push("/"); }); // join room socketRef.current.emit("joinRoom", { group: groupId, page: pageNumber, user: session.data.user, }); socketRef.current.on("userJoined", (user) => { if (user.id !== session.data.user.id) { new Toast(user.name + " joined the page!", { theme: "light", timeout: 800, position: "bottom", }); } }); socketRef.current.on("userLeft", (user) => { if (user.id !== session.data.user.id) { new Toast(user.name + " left the page!", { theme: "light", timeout: 800, position: "bottom", }); } }); socketRef.current.on("pageChange", ({ user, markdown }) => { if (user.id !== session.data.user.id) { mdRef.current.setMarkdown(markdown); } }); }; init(); return () => { // disconnect the socket when user leaves the page if (socketRef.current) { socketRef.current.disconnect(); } }; }, [params, markdown]); const handleMarkdownChange = useCallback((e) => { if (isViewOnly || isPending) return; function normalizeString(str) { return str .trim() .replace(/\s+/g, "") .replace(/\r?\n|\r/g, ""); } // preventing saving to database, without change when page first loads if (normalizeString(e) === normalizeString(markdown)) { return; } if (saveToDBTimeout) { clearTimeout(saveToDBTimeout); } // Set a new timeout saveToDBTimeout = setTimeout(async () => { startTransition(async () => { const data = await savePage( mdRef.current.getMarkdown(), groupId, pageNumber ); if (!data.success) { ToastError(data.message); } mdRef.current.focus(); }); }, intervalToSaveInDb); if (mdRef.current) { socketRef.current.emit("pageChange", { user: session.data.user, markdown: mdRef.current.getMarkdown(), }); } }, []); console.count("rendered time"); return ( <MDXEditor markdown={markdown} onChange={handleMarkdownChange} ref={mdRef} className="h-full max-h-full border-r border-b border-l border-slate-100 rounded-lg overflow-y-auto" contentEditableClassName="prose max-w-full font-sans" plugins={allPlugins(markdown, isPending)} placeholder="Start Editing" readOnly={isViewOnly} autoFocus /> ); }; export default Editor; //editor-wrapper.js const Editor = dynamic(async () => await import("./Editor"), { ssr: false, loading: () => ( <div className="mt-4 ml-2 flex"> <Loader className="text-gray-500 animate-spin text-sm" />{" "} <span className="ml-2">Loading Editor</span> </div> ), }); export const EditorWrapper = ()=>{ return <> <h2>Editor will render here </h2> <Editor> </> }
Editor is loading...
Leave a Comment