Hello there! Are you tired of manually editing markdown files in your IDE? Well, fret not! We're about to create a markdown editor that lets you edit directly on GitHub. Sounds cool, right?
The goal is simple: minimize the hassle and extend our current workflow. Instead of juggling multiple tools, we'll integrate everything into our existing application. No need for separate services or databases—just pure markdown magic.
Our editor will let you edit markdown files straight from your GitHub repo and push the changes. It's as straightforward as that!
Here's the core code snippet to get us started:
import {ForwardRefEditor as Editor} from './forwardRefEditor' import '@mdxeditor/editor/style.css' const getArticleBySlug = async (slug: string) => { 'use server' const owner = '<user>'; const repo = '<repo_name>'; const path = `path_to_your_articles/${slug}.mdx`; const ref = 'main'; // branch const rawArticleLocation = `https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${ref}`; const res = await fetch(rawArticleLocation, { headers: { 'Accept': 'application/vnd.github+json', 'Authorization': `token ${process.env.GITHUB_TOKEN}`, 'X-Github-Api-Version': "2022-11-28" }, }); const jsonResponse = await res.json(); const content = Buffer.from(jsonResponse.content, 'base64').toString(); return content; } interface PageProps { params: { slug: string }; searchParams: { [key: string]: string | string[] | undefined }; } const EditArticlePage = async (props: PageProps) => { const slug = props.params.slug; const article = await getArticleBySlug(slug) return <Editor markdown={article} />; }; export default EditArticlePage;
But wait, there's more! We need a couple of additional components to make this work. One of them is our InitializedMDXEditor
, heavily inspired by mdxeditor tutorials.
Here's the code for that:
'use client' import type { ForwardedRef } from 'react' import { headingsPlugin, listsPlugin, quotePlugin, thematicBreakPlugin, toolbarPlugin, MDXEditor, type MDXEditorMethods, type MDXEditorProps, UndoRedo, BoldItalicUnderlineToggles, markdownShortcutPlugin, CreateLink, BlockTypeSelect, CodeToggle, Separator, Button, frontmatterPlugin, InsertFrontmatter, diffSourcePlugin, DiffSourceToggleWrapper, codeBlockPlugin, codeMirrorPlugin } from '@mdxeditor/editor' // Only import this to the next file export default function InitializedMDXEditor({ editorRef, ...props }: { editorRef: ForwardedRef<MDXEditorMethods> | null } & MDXEditorProps) { return ( <MDXEditor plugins={[ headingsPlugin(), listsPlugin(), quotePlugin(), thematicBreakPlugin(), diffSourcePlugin({ diffMarkdown: props.markdown, viewMode: 'rich-text', // readOnlyDiff: true }), frontmatterPlugin(), toolbarPlugin({ toolbarContents: () => ( <> {' '} <DiffSourceToggleWrapper > <InsertFrontmatter /> <Separator /> <UndoRedo /> <BoldItalicUnderlineToggles /> <CreateLink /> <BlockTypeSelect /> <CodeToggle /> <Separator /> <Button>EditorAI</Button> <Button>Save</Button> </DiffSourceToggleWrapper> </> ), }), codeBlockPlugin({ defaultCodeBlockLanguage: 'js' }), codeMirrorPlugin({ codeBlockLanguages: { js: 'JavaScript', ts: 'Typescript', tsx: 'React TSX', json: 'JSON', diff: 'Diff', typescript: 'Typescript' }, }), markdownShortcutPlugin(), ]} {...props} ref={editorRef} /> ) }
And, of course, we need a dynamic import component. Here's how we do it:
'use client' import { forwardRef } from 'react'; import { type MDXEditorMethods, type MDXEditorProps } from '@mdxeditor/editor' import dynamic from 'next/dynamic'; const Editor = dynamic(() => import('./InitializedEditor'), { ssr: false }) export const ForwardRefEditor = forwardRef<MDXEditorMethods, MDXEditorProps>((props, ref) => <Editor {...props} editorRef={ref} />); ForwardRefEditor.displayName = 'ForwardRefEditor';
So there you have it! We've laid the groundwork for our AI-enhanced MDX editor. Stay tuned for part 2, where we'll dive into integrating AI to improve content quality. For those who can't wait, check out our article on Automate Content Quality with AI: Implement a Pre-Commit Hook in TypeScript with GPT-4.
Happy coding!
We use cookies to improve your experience and analyze our traffic. By using our site, you consent to our use of cookies. You can manage your preferences below: