MDX-Editor
This commit is contained in:
@@ -1,120 +1,59 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
MDXEditor,
|
||||
toolbarPlugin,
|
||||
headingsPlugin,
|
||||
listsPlugin,
|
||||
quotePlugin,
|
||||
thematicBreakPlugin,
|
||||
markdownShortcutPlugin,
|
||||
BoldItalicUnderlineToggles,
|
||||
ListsToggle,
|
||||
BoldItalicUnderlineTogglesProps,
|
||||
MDXEditorProps,
|
||||
UndoRedo,
|
||||
InsertImage,
|
||||
CreateLink
|
||||
} from "@mdxeditor/editor";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import useApiMutation from "@/hooks/use-api";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
export default function Editor() {
|
||||
const [blogContent, setBlogContent] = useState("");
|
||||
const [cursor, setCursor] = useState<{ line: number; column: number }>({
|
||||
line: 0,
|
||||
column: 0,
|
||||
});
|
||||
|
||||
const getCursorPosition = (newText: string) => {
|
||||
const cursorPos = newText.length;
|
||||
const lines = newText.substring(0, cursorPos).split("\n");
|
||||
const line = lines.length; // Current line number
|
||||
const column = lines[lines.length - 1].length + 1; // Current column number
|
||||
|
||||
setCursor({ line, column });
|
||||
};
|
||||
|
||||
const sanitized = DOMPurify.sanitize(blogContent);
|
||||
const propsa: BoldItalicUnderlineTogglesProps = { options: ["Bold", "Italic", "Underline"] }
|
||||
const mdxEditorProps: MDXEditorProps = {}
|
||||
const Editor = dynamic(
|
||||
() => import("@/components/editor").then((mod) => mod.Editor),
|
||||
{ ssr: false },
|
||||
);
|
||||
|
||||
export default function BlogEditor() {
|
||||
const {
|
||||
trigger,
|
||||
isMutating: loading,
|
||||
isSuccess,
|
||||
} = useApiMutation(
|
||||
"/blog/new",
|
||||
undefined,
|
||||
"POST",
|
||||
false,
|
||||
true,
|
||||
);
|
||||
} = useApiMutation("/blog/new", undefined, "POST", false, true);
|
||||
|
||||
return (
|
||||
<section className="m-10">
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
<MDXEditor
|
||||
plugins={[
|
||||
headingsPlugin(),
|
||||
listsPlugin(),
|
||||
quotePlugin(),
|
||||
thematicBreakPlugin(),
|
||||
markdownShortcutPlugin(),
|
||||
toolbarPlugin({
|
||||
toolbarContents: () => (
|
||||
<div className="flex flex-row">
|
||||
<UndoRedo />
|
||||
<BoldItalicUnderlineToggles {...propsa} />
|
||||
<InsertImage />
|
||||
<CreateLink />
|
||||
<ListsToggle />
|
||||
</div>
|
||||
),
|
||||
}),
|
||||
]}
|
||||
onChange={setBlogContent}
|
||||
onBlur={() => getCursorPosition(blogContent)}
|
||||
markdown="ok"
|
||||
<Editor
|
||||
markdown={localStorage.getItem("blog_draft") ?? ""}
|
||||
/>
|
||||
|
||||
<div>
|
||||
Line: {cursor.line}; Column: {cursor.column}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="mt-4 w-1/2 p-2 bg-gray-100 border rounded-md text-sm text-black"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: sanitized,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button className="text-black bg-white" onClick={async () => {
|
||||
try {
|
||||
const res = await trigger({
|
||||
label: "This is my label",
|
||||
summary: "A summary",
|
||||
image: "none",
|
||||
href: "none",
|
||||
blogID: "id",
|
||||
slug: "myslug",
|
||||
content: blogContent,
|
||||
published: "",
|
||||
});
|
||||
if (!res) throw new Error("The server hasn't responded.");
|
||||
if (res.status === "Error") throw new Error(res.message);
|
||||
if (res.data) console.log(res.data);
|
||||
return res;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}}>Sauvegarder</Button>
|
||||
</section >
|
||||
<Button
|
||||
className="text-black bg-white"
|
||||
onClick={async () => {
|
||||
try {
|
||||
const blogContent = localStorage.getItem("blog_draft");
|
||||
const res = await trigger({
|
||||
label: "This is my label",
|
||||
summary: "A summary",
|
||||
image: "none",
|
||||
href: "none",
|
||||
blogID: "id",
|
||||
slug: "myslug",
|
||||
content: blogContent,
|
||||
published: "",
|
||||
});
|
||||
if (!res)
|
||||
throw new Error("The server hasn't responded.");
|
||||
if (res.status === "Error")
|
||||
throw new Error(res.message);
|
||||
if (res.data) console.log(res.data);
|
||||
return res;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Sauvegarder
|
||||
</Button>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user