Next.jsでMarkdown Editorを作りました。
Next.js(というかReactで)でMarkdown Editorを作ってみたので、今回はその記事です。
完成系は以下の通り。
ざっくり概要
使用技術
- Next.js(というかReact)
- パッケージなど(react-markdown, remark-gfm)
- tailwind
※デザインはzennのエディタを少しだけ参考にさせていただきました。(zennのエディタ大好きなので!!)
全体像
まず、画像を見ていただくとわかると思いますが、Title
の下の部分にmarkdownを記入する部分
とプレビューを表示する部分
があります。
左側のmarkdownを記入する部分は、textareaタグ
にstyleを当てて作っています。一方、右側のプレビューはdivタグ
で作成しています。
textarea
に入力した内容をどのようにプレビューに表示しているかというと、textareaのvalueをstateに持たせ、それをプレビュー用のコンポーネントに渡しているだけです。 このようにすることでプレビューで入力した内容が表示されます。
あとは、markdownで入力した内容を何かしらの方法でhtml
に変換して、プレビューで表示すればできます。
ここで登場するのがreact-markdownです。react-markdownは、markdownで記述した内容をhtmlに変換してくれるもので、かなり便利です。使い方に関してはREADMEに書かれているので、ここでは割愛します。
また、react-markdownでremark-gfm
というプラグインを利用していますが、これはGitHubのmarkdownの書き方に従いますよ
ってやつです。
コードと解説
tailwindを使っているので、少しclassName
が汚いですが、以下がコードになります。
PostForm.tsx
export default function PostForm() {
const [markdown, setMarkdown] = useState();
const setData = (e: any) => {
e.preventDefault();
setMarkdown(e.target.value);
};
return (
<div className="post-form min-h-screen">
<div className="h-screen flex flex-col">
<div className="pl-9 pt-9">
<a
href="/"
className="transition duration-500 flex items-center justify-center rounded-full hover:bg-white hover:shadow-xl"
style={{ width: "50px", height: "50px" }}
>
<BsChevronLeft style={{ fontSize: "30px", fontWeight: "bold" }} />
</a>
</div>
<h1 className="text-center font-bold text-4xl py-10">投稿を作成</h1>
<div className="editor flex-grow flex-shrink">
<form className="h-full">
<input
type="text"
id="post-title"
placeholder="Title"
className="px-5 block mx-auto w-4/5 rounded-lg border h-14 text-2xl font-bold focus:outline-none mb-8 shadow-lg"
/>
<div
className="flex justify-between h-3/5"
style={{ maxHeight: "300px" }}
>
<div className="w-1/2 ml-10">
<textarea
name="md"
id="md"
placeholder="Markdownで記述"
className="markdown-form resize-none w-full h-full border shadow-xl mb-5 rounded-xl focus:outline-none py-4 px-2"
value={markdown}
onChange={setData}
></textarea>
</div>
<div className="w-1/2 mr-10">
<PostPreview markdown={markdown} />
</div>
</div>
<input
type="submit"
className="submit-post w-36 h-10 my-8 rounded-md font-bold block mx-auto hover:opacity-70"
/>
</form>
</div>
</div>
</div>
);
}
PostPreview.tsx
import React from "react";
import ReactMarkdown from "react-markdown";
import gfm from "remark-gfm";
const PostPreview = (props) => {
return (
<div className="h-full w-full mr-10">
<div className="markdown-preview h-full w-full border shadow-xl mb-5 rounded-xl py-4 px-2 overflow-y-scroll bg-white">
<ReactMarkdown plugins={[gfm]} unwrapDisallowed={false}>
{props.markdown}
</ReactMarkdown>
</div>
</div>
);
};
export default PostPreview;
今回の記事に関係ない部分は省略しました。型もanyです。
これらのコードのポイントで言うと、全体像の部分でも解説しましたが、PostPreviewコンポーネント(プレビューの部分)
をformの中に設置して、display flex
でtextareaと横並びになるようにしています。
また、PostPreview
に、markdown
と言うstateを渡しています。このmarkdown
と言うstateは、textareaに変更が加えられるたびに、onChangeで呼び出される関数setData
にsetMarkdown(e.target.value)
とすることで、stateが更新されるようになっています。
さらに、react-markdownが変換してくれたhtmlにstyleを当てるstylesheetも用意しておきます。
markdown.css
.markdown-preview h1,
.markdown-preview h2,
.markdown-preview h3,
.markdown-preview h4,
.markdown-preview h5,
.markdown-preview h6 {
font-weight: 600;
}
.markdown-preview h2 {
font-size: 1.5rem;
}
.markdown-preview h3 {
font-size: 1.3rem;
}
.markdown-preview h4 {
font-size: 1.1rem;
}
.markdown-preview h5 {
font-size: 0.9rem;
}
.markdown-preview h6 {
font-size: 0.7rem;
}
.markdown-preview p code {
background-color: #ebebeb;
}
.markdown-preview p a {
color: #0000ee;
}
.markdown-preview p a:visited {
color: #551a8b;
}
.markdown-preview ul li {
list-style: inside;
}
.markdown-preview ul li ul {
margin-left: 1rem;
}
.markdown-preview ol li {
list-style: inside;
list-style-type: decimal;
}
.markdown-preview table {
border: 1px solid #afadad;
}
.markdown-preview table thead {
background-color: #ebebeb;
}
.markdown-preview table thead tr {
border-bottom: 1px solid #afadad;
}
.markdown-preview table thead tr th {
border-right: 1px solid #afadad;
}
.markdown-preview table thead tr th:last-child {
border-right: none;
}
.markdown-preview tbody tr {
border-bottom: 1px solid #afadad;
}
.markdown-preview tbody tr:last-child {
border-bottom: none;
}
.markdown-preview tbody tr td {
border-right: 1px solid #afadad;
}
.markdown-preview tbody tr td:last-child {
border-right: none;
}
.markdown-preview blockquote {
font-size: 0.95rem;
margin: 1.4rem 0;
border-left: 3px solid #b3bfc7;
padding: 2px 0 2px 0.7em;
color: #626e77;
}
sassでやればよかった。。。(全部に.markdown-preview
書くの見にくいし面倒)
とりあえず、hタグ、テンプレートリテラル、blockquote、tableあたりはstykeを当てておきました。
まとめ
このような感じで、markdown editorを作成しました。markdown editorについて調べてみても、なんかしっくりくる記事に出会えなかったので自分で考えて作ったのですが、案外簡単でしたw
誰かの参考になれば幸いです。
参考
Electron + Next.js + Tailwind CSS で Markdown エディタを作った
Happy Hues
Discussion