Open4
フロントエンド学習日記
I have read the system guide for CodeMirror.
Why
I Wabted to write my own blog using Markdown, so Idecide to give it at try.
What
I'll try to summarize the CodeMirror SystemGuide in my own words.
The minimum requirements necessary to set up the editor
Changes
I swiched to react-markdown as it seemed more beginner-friendly.
Package Installation
pnpm i react-markdown remark-gfm
-
react-markdown
- Component for display Markdown editor
-
remark-gfm
- Enables markdown extensions as GFM
Implementation
'use client';
import { useState } from 'react';
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
const CreateBlog = () => {
const [text, setText] = useState('');
return (
<div className='grid grid-cols-2'>
<textarea
value={text}
onChange={(e) => {
setText(e.target.value);
}}
/>
<div className='markdown'>
<Markdown remarkPlugins={[remarkGfm]}>{text}</Markdown>
</div>
</div>
);
};
export default CreateBlog;
CSS Modifications
Since Tailwind's reset CSS conflicts with the default styles, i added styles to globals.css
Refer to this repository for the content:
Apply Syntax Highlighting
I referred to Newt's article in the following link.
'use client';
import type { ClassAttributes, HTMLAttributes } from 'react';
import { useState } from 'react';
import type { ExtraProps } from 'react-markdown';
import Markdown from 'react-markdown';
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/default-highlight';
import { darcula } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import remarkGfm from 'remark-gfm';
const CreateBlog = () => {
const [text, setText] = useState('');
return (
<div className='grid h-screen grid-cols-2 divide-x-2 overflow-scroll'>
<textarea
value={text}
spellCheck={false}
className='p-4 outline-none'
onChange={(e) => {
setText(e.target.value);
}}
/>
<div className='markdown overflow-scroll bg-white p-4'>
{/* Assign custom component to the pre element */}
<Markdown remarkPlugins={[remarkGfm]} components={{ pre: Pre }}>
{text}
</Markdown>
</div>
</div>
);
};
export default CreateBlog;
const Pre = ({ children, ...props }: ClassAttributes<HTMLPreElement> & HTMLAttributes<HTMLPreElement> & ExtraProps) => {
if (!children || typeof children !== 'object') {
return <code {...props}>{children}</code>;
}
// Only apply styling to code blocks, verify if the child is a code element.
const childType = 'type' in children ? children.type : '';
if (childType !== 'code') {
return <code {...props}>{children}</code>;
}
// Retrieve information inside the code element (refer to the supplementary)
const childProps = 'props' in children ? children.props : {};
const { className, children: code } = childProps;
// Retrieve the class name
// Use this class name to get language-specific syntax highlighting and file name.
const classList = className ? className.split(':') : [];
const language = classList[0]?.replace('language-', '');
const fileName = classList[1];
return (
<section>
{/* Display the file name obtained from splitting the class name */}
{fileName && (
<div className='bg-zinc-950 px-2 text-sm italic text-white'>
<span>{fileName}</span>
</div>
)}
<SyntaxHighlighter language={language} style={darcula}>
{code === null || code === undefined ? '' : String(code).replace(/\n$/, '')}
</SyntaxHighlighter>
</section>
);
};
Supplementary
The contents of the 'children' object:
Convexとは?
Convexをこれから使ってみたいと思う。
BaaS的なサービスっぽい。
Firebaseに近い感じだろうか