Created
April 29, 2025 23:02
-
-
Save azpoint/2f3dfcc7a18eb1e57aaf95e06d37b0ed to your computer and use it in GitHub Desktop.
MDXEditor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Headings */ | |
.mdxeditor h1 { | |
font-size: 2rem; | |
font-weight: bold; | |
margin: 1rem 0; | |
} | |
.mdxeditor h2 { | |
font-size: 1.5rem; | |
font-weight: bold; | |
margin: 0.75rem 0; | |
} | |
.mdxeditor h3 { | |
font-size: 1.25rem; | |
font-weight: bold; | |
margin: 0.5rem 0; | |
} | |
.mdxeditor h4 { | |
font-size: 1rem; | |
font-weight: bold; | |
margin: 0.25rem 0; | |
} | |
/* Paragraph */ | |
.mdxeditor p { | |
font-size: 1rem; | |
margin: 0.5rem 0; | |
line-height: 1.6; /* Added for better readability */ | |
} | |
/* Blockquote */ | |
.mdxeditor blockquote { | |
border-left: 4px solid #ccc; | |
padding-left: 1rem; | |
margin: 1rem 0; | |
color: #555; | |
font-style: italic; | |
background-color: #f9f9f9; | |
font-size: 1.1rem; /* Slightly larger text for quotes */ | |
} | |
/* Lists */ | |
.mdxeditor ul { | |
list-style-type: disc; | |
margin-left: 2rem; | |
} | |
.mdxeditor ol { | |
list-style-type: decimal; | |
margin-left: 2rem; | |
} | |
.mdxeditor li { | |
margin: 0.5rem 0; | |
line-height: 1.5; | |
} | |
/* Code Blocks */ | |
.mdxeditor pre { | |
background-color: #f5f5f5; | |
padding: 1rem; | |
border-radius: 5px; | |
font-size: 0.9rem; | |
overflow-x: auto; | |
margin: 1rem 0; | |
} | |
.mdxeditor code { | |
background-color: #f5f5f5; | |
padding: 0.2rem 0.4rem; | |
border-radius: 3px; | |
font-size: 1rem; | |
font-family: "Courier New", Courier, monospace; | |
} | |
/* Links */ | |
.mdxeditor a { | |
color: #0070f3; /* A nice blue for links */ | |
text-decoration: none; | |
} | |
.mdxeditor a:hover { | |
text-decoration: underline; /* Add underline on hover */ | |
} | |
/* Horizontal Line */ | |
.mdxeditor hr { | |
border: none; | |
border-top: 1px solid #ddd; | |
margin: 1rem 0; | |
} | |
/* Inline Elements */ | |
.mdxeditor strong { | |
font-weight: bold; | |
} | |
.mdxeditor em { | |
font-style: italic; | |
} | |
.mdxeditor u { | |
text-decoration: underline; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use client"; // Marks this file as a client component (Next.js App Router) | |
// ─── Imports ──────────────────────────────────────────────────────────────── | |
import dynamic from "next/dynamic"; | |
import { useState } from "react"; | |
// Editor UI styles (required for MDXEditor toolbar, text styles, etc.) | |
import "@mdxeditor/editor/style.css"; | |
// CSS styles to render in editor toolbar plugins | |
import "@/src/styles/components/MDX-inEditorStyles.css"; | |
// ─── Dynamic Import to Prevent SSR ────────────────────────────────────────── | |
// MDXEditor uses browser-only APIs (like selection), so we load it client-side only | |
const MDXEditor = dynamic( | |
() => import("@mdxeditor/editor").then((mod) => mod.MDXEditor), | |
{ ssr: false } // disables server-side rendering for this component | |
); | |
// ─── Plugins and Toolbar Buttons ──────────────────────────────────────────── | |
import { | |
headingsPlugin, // Enables heading elements (H1–H6) | |
BlockTypeSelect, // Toolbar dropdown to switch between paragraph/heading/etc | |
quotePlugin, // Enables blockquote support | |
listsPlugin, // Enables unordered and ordered lists | |
thematicBreakPlugin, // Enables horizontal rules (---) | |
UndoRedo, // Toolbar buttons for undo/redo | |
BoldItalicUnderlineToggles, // Toolbar toggles for bold, italic, underline | |
toolbarPlugin, // Enables the toolbar and its customization | |
CreateLink, // Button to create/edit links | |
linkDialogPlugin, // Dialog popup UI for inserting/editing links | |
imagePlugin, // Enables image support | |
InsertImage, // Toolbar button to insert an image | |
InsertThematicBreak, // Toolbar button for horizontal rule | |
markdownShortcutPlugin, // Enables markdown shortcuts (e.g. typing `#` makes heading) | |
Separator, // UI divider for toolbar groups | |
ListsToggle, // Button to toggle list types | |
linkPlugin, // Needed to render links in the output | |
} from "@mdxeditor/editor"; | |
// ─── Main Editor Component ────────────────────────────────────────────────── | |
export default function MDXEditorWrapper({ onChange }) { | |
const [markdown, setMarkdown] = useState("This is a [link](https://example.com)"); | |
return ( | |
<div | |
style={{ | |
padding: "1rem", | |
background: "oklch(97% 0.001 106.424)", // Soft background using OKLCH color | |
borderRadius: '0.5rem' // Rounded container | |
}} | |
> | |
<MDXEditor | |
markdown={markdown} // Initial content | |
plugins={[ | |
headingsPlugin(), | |
quotePlugin(), | |
listsPlugin(), | |
thematicBreakPlugin(), | |
linkDialogPlugin(), | |
imagePlugin(), | |
markdownShortcutPlugin(), | |
linkPlugin(), // 👈 Important: Required to render actual <a> links | |
toolbarPlugin({ | |
toolbarClassName: "mdx-toolbar", // Custom class for toolbar styling | |
toolbarContents: () => ( | |
<> | |
{/* Undo and Redo buttons (arrows) */} | |
<UndoRedo /> | |
{/* Visual separator for clarity */} | |
<Separator /> | |
{/* Dropdown to switch between Paragraph, Heading 1–6, etc. */} | |
<BlockTypeSelect /> | |
{/* Another separator to group formatting options */} | |
<Separator /> | |
{/* Buttons for bold, italic, and underline toggles */} | |
<BoldItalicUnderlineToggles /> | |
{/* Separator between formatting and structure tools */} | |
<Separator /> | |
{/* Button to toggle between ordered and unordered lists */} | |
<ListsToggle /> | |
{/* Separator before inserting content tools */} | |
<Separator /> | |
{/* Button to open a dialog for inserting/editing links */} | |
<CreateLink /> | |
{/* Button to open an image insertion dialog */} | |
<InsertImage /> | |
{/* Button to insert a horizontal rule (thematic break) */} | |
<InsertThematicBreak /> | |
</> | |
), | |
}), | |
]} | |
onChange={(newMarkdown) => { | |
setMarkdown(newMarkdown); // Updates local state | |
if (onChange) onChange(newMarkdown); // Fires external onChange if provided | |
}} | |
/> | |
</div> | |
); | |
} | |
// ─── Note ──────────────────────────────────────────────────────────────────── | |
// This config is compatible with "@mdxeditor/editor": "^3.31.0" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// React core imports | |
import React from "react"; | |
import { Suspense } from "react"; // Used to wrap lazy-loaded components | |
// Custom MDX text editor component | |
import MDXEditorWrapper from "@/src/components/panel/TextEditor"; | |
function ReactComponent() { | |
// State to store the live content of the editor | |
const [editorContent, setEditorContent] = useState(""); | |
// For debugging: logs the current content on every change | |
console.log(editorContent); | |
return ( | |
<div className="mt-8"> {/* Margin top spacing using Tailwind (or similar utility CSS) */} | |
{/* Suspense allows fallback UI while MDXEditor loads (due to dynamic import) */} | |
<Suspense fallback={<div>Loading editor...</div>}> | |
<MDXEditorWrapper | |
onChange={(markdown) => setEditorContent(markdown)} // Passes updated content back to parent state | |
/> | |
</Suspense> | |
</div> | |
); | |
} | |
export default ReactComponent; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment