概要
こういう感じのMarkdownで書けるページをNext.jsとChakra UIとmicroCMSで実装する。
実装
プロジェクトの準備
上記を参考にプロジェクトの準備をする。
TypeScriptとChakra UIも入れておく。
$ npx create-next-app microcms-next-jamstack-blog
$ cd microcms-next-jamstack-blog
$ yarn add -D typescript @types/react @types/node
$ touch tsconfig.json
# ここで_app.jsとindex.jsの拡張子を.tsxに書き換える
$ yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
$ yarn dev
microCMSの準備
アカウント登録、ログイン、サービスの作成、APIの作成などこちらを参考に進める。
API テンプレートからブログを選択しておく。
「ブログ」と「カテゴリ」のAPIが作られるのでブログを選択する。
「ブログ」のAPI設定からAPIスキーマを選択し、content
が「リッチエディタ」になっていることを確認する。
microCMSではこのリッチエディタがMarkdownに対応しているエディタである。
「ブログ」の中に入っているサンプル記事をリッチエディタで編集する。
#
で見出し、*
で箇条書きなど基本的なMarkdown記法が使える。
リンクも[リンクテキスト](リンクURL)
の書き方で問題ない。
リッチエディタ上ではスタイルとして変換後の状態で表示される。
書き終わったら右上の「APIプレビュー」から「取得」を選択し、
見出しがh1
などhtmlに変換されているか確認する。
プロジェクトとAPIの接続
APIキーの設定を下記を参考に進める。
APIキーは先ほど開いた「APIプレビュー」の画面に書かれている。
同じく上記記事を参考に「microcms-js-sdk」を導入する。
$ yarn add microcms-js-sdk
libs
ディレクトリを作成しclient.js
ファイルを作成する。
serviceDomain
はXXXX.microcms.io
のXXXXの文字列を入力する。
import { createClient } from 'microcms-js-sdk';
export const client = createClient({
serviceDomain: 'service-domain',
apiKey: process.env.API_KEY,
});
表示のための整備
_app.tsx
をChakra UIの書き方に合わせて修正する。
import "../styles/globals.css";
import { ChakraProvider } from "@chakra-ui/react";
function MyApp({ Component, pageProps }) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
);
}
export default MyApp;
index.tsx
も修正する。
import { Box, Heading } from "@chakra-ui/react";
import React from "react";
import { MarkdownTemplate } from "../components/MarkdownTemplate";
import { client } from "../libs/client";
import type { Blog } from "../types/blog";
type Props = {
blog: Array<Blog>;
};
export default function Home({ blog }: Props) {
const title = blog[0].title;
const content = blog[0].content;
return (
<>
<Box p="10">
<Heading
as="h1"
fontWeight={"200"}
lineHeight={1.25}
mb={".67em"}
pb={".3em"}
size="4xl"
>
{title}
</Heading>
<MarkdownTemplate source={content} />
</Box>
</>
);
}
export const getStaticProps = async () => {
const data = await client.get({ endpoint: "blog" });
return {
props: {
blog: data.contents,
},
};
};
types
ディレクトリを作成し、blog.ts
ファイルを作成する。
export type Blog = {
id: string
createdAt: string
updatedAt: string
publishedAt: string
revisedAt: string
title: string
content: string
}
ここで「html-react-parser」を導入する。
remarkablemark/html-react-parser: HTML to React parser.
$ yarn add html-react-parser
components
ディレクトリを作成してMarkdownTemplate.tsx
を作成する。
Chakra UIではa
タグをLink
と表記するなど、タグの書き方もそのままでは使えないのでこのファイルで変換している。
また、見た目はGitHubのスタイルを参考にしている。
import {
BoxProps,
Box,
Text,
UnorderedList,
ListItem,
Link,
} from "@chakra-ui/react";
import parse, { domToReact, HTMLReactParserOptions } from "html-react-parser";
type MarkdownTemplateProps = {
source: string;
} & BoxProps;
const h1 = {
component: Text,
props: {
mt: "24px",
mb: "16px",
lineHeight: 1.25,
color: "#202020",
fontWeight: "600",
pb: ".3em",
fontSize: "2em",
borderBottom: "1px solid #E7ECF2",
},
};
const h2 = {
component: Text,
props: {
mt: "24px",
mb: "16px",
lineHeight: 1.25,
color: "#202020",
fontWeight: "600",
pb: ".3em",
fontSize: "1.5em",
borderBottom: "1px solid #E7ECF2",
},
};
const h3 = {
component: Text,
props: {
mt: "24px",
mb: "16px",
lineHeight: 1.25,
color: "#202020",
fontWeight: "600",
fontSize: "1.25em",
},
};
const p = {
component: Text,
props: {
lineHeight: "1.5",
mb: "10px",
fontSize: "16px",
color: "##000",
},
};
const ul = {
component: UnorderedList,
props: {
color: "#000",
mt: 0,
mb: 0,
pl: "2em",
lineHeight: "1.6",
},
};
const li = {
component: ListItem,
};
const a = {
component: Link,
props: {
isExternal: true,
textDecoration: "none",
color: "#0058B3",
_hover: {
textDecoration: "none",
color: "#4593e6",
},
},
};
const options: HTMLReactParserOptions = {
replace: (domNode: any) => {
if (domNode.type === "tag") {
if (domNode.name === "h1") {
return (
<Text as="h1" {...h1.props}>
{domToReact(domNode.children, options)}
</Text>
);
}
if (domNode.name === "h2") {
return (
<Text as="h2" {...h2.props}>
{domToReact(domNode.children, options)}
</Text>
);
}
if (domNode.name === "h3") {
return (
<Text as="h3" {...h3.props}>
{domToReact(domNode.children, options)}
</Text>
);
}
if (domNode.name === "ul") {
return (
<UnorderedList {...ul.props}>
{domToReact(domNode.children, options)}
</UnorderedList>
);
}
if (domNode.name === "li") {
return <ListItem>{domToReact(domNode.children, options)}</ListItem>;
}
if (domNode.name === "a") {
return (
<Link {...a.props} href={domNode.attribs.href}>
{domToReact(domNode.children, options)}
</Link>
);
}
if (domNode.name === "p") {
return (
<Text {...p.props}>{domToReact(domNode.children, options)}</Text>
);
}
}
},
};
export const MarkdownTemplate = (props: MarkdownTemplateProps) => {
return <Box {...props}>{parse(props.source, options)}</Box>;
};
反映の確認
$ yarn dev
すると下記のような見た目になるはず。
Markdownで編集・更新できるページの完成🎉