microCMS × Reactで吹き出しで会話してるUIを作る
目次
上みたいな感じで、Wordpressでよく見る形の、ふきだしで会話をしている風なものを、microCMSとReactでカスタムフィールドを使って作ってみました。
下のWordpressのプラグインのような感じですね。
その手順と、Reactでのコンポーネントの作り方について解説します!
前提
- microCMSを使って記事用のapiが製作済み
管理画面の使い勝手
カスタムフィールドを使ってこのような形になるように作っていきます。
記事用APIのカスタムフィールドを設定
右上カスタムフィールドをクリック
カスタムフィールの基本情報を入力
カスタムフィールド名: comment
カスタムフィールドID: comment
としています。
APIスキーマ(インターフェース)を定義
フール度ID | 表示名 | 種類 |
---|---|---|
image | 画像 | 画像 |
name | 名前 | テキストフィールド |
text | テキスト | テキストフィールド |
isRight | コメント位置(右の場合ON) | 真偽値 |
項目名でなんとなくはわかるかと思います。
isRight
がちょっとわかりづらいかもですが、**画像を左に表示するか、右に表示するかを設定するものです。
コメント繰り返し用のカスタムフィールドを作る
先ほど作った「comment」のカスタムフィールドを「繰り返し」で設定します
記事API側で選択できるように
記事側のbodyを「繰り返しフィールド」にしてMarkdownで書けたりcommentsを設定できたりできるようにいくつか用意しています。
今回作ったコメント機能以外にも、拡張できるようにしています。
React側でそれに対応したコンポーネントを作る
使っているもの
- styled-component。
型定義
export interface Body {
fieldId: string
value: string
}
export interface Comments extends Body {
comments?: CommentBody[]
}
export interface CommentBody extends Body {
image?: ImageInfo
text?: string
isRight?: boolean
name?: string
}
Comment.tsx
import React from 'react'
import Image from 'next/image'
import { CommentBody } from '../entry/Entry'
import styled from 'styled-components';
const CommentContainer = styled.div<CommentBody>`
margin: 24px 5% !important;
display: flex;
flex-direction: ${(p) => p.isRight ? 'row-reverse' : 'row'};
align-items: flex-start;
vertical-align: top;
`
const Message = styled.p<CommentBody>`
margin: 0 !important;
width: 100%;
border-radius: 6px;
border: 2px solid #ccc !important;
margin-left: ${(p) => p.isRight ? '' : '16px'} !important;
margin-right: ${(p) => p.isRight ? '16px' : ''} !important;
padding: 16px !important;
position: relative;
&:before {
position: absolute;
top: 16px;
left: ${(p) => p.isRight ? '' : '-7px'};
right: ${(p) => p.isRight ? '-7px' : ''};
display: block;
content: '';
transform: rotate(45deg);
border: 2px solid #ccc;
border-top: ${(p) => p.isRight ? '' : 'none'};
border-right: ${(p) => p.isRight ? '' : 'none'};
border-bottom: ${(p) => p.isRight ? 'none' : ''};
border-left: ${(p) => p.isRight ? 'none' : ''};
width: 10px;
height: 10px;
background-color: #fff;
}
`
const Icon = styled.figure`
margin: 0;
vertical-align: top;
width: 100px;
font-size: 1px;
& img {
border-radius: 6px;
}
`
const Name = styled.p`
font-size: 11px;
padding: 0 !important;
margin: 0 !important;
border: none !important;
text-align: center;
`
export const Comment: React.FC<CommentBody> = props => {
return (
<CommentContainer {...props}>
{props.image && <Icon>
<Image src={props.image.url} width={props.image.width} height={props.image.height} alt="" />
{props.name && <Name>{props.name}</Name>}
</Icon>}
<Message {...props}>{props.children || props.text}</Message>
</CommentContainer>
)
};
export default Comment
基本的には仕組みは、先ほど作ったカスタムフィールドのAPIで帰ってくる値を元にコンポーネントを作っています。
isRightの場合は画像が右側に表示するようにstyled-componentにpropを渡してスタイルを変更するように書いています。
ちょっと!important
を使っちゃってるところもあります。。あまり良くないですね;
使ってる理由はこのコンポーネントが描画されるところでは自動的に良い感じのスタイルがつくようになっているので
むりやり上書きする形にしています。
なぜ良い感じのスタイルがつくようになっているかというと、
Markdownなどで変換したhtmlにスタイルを当てたいためそのような仕様にしています。
コメントコンポーネントを使う側のコード
<EntryBody>
<div ref={entryBody}>
{props?.body?.map((v, i) => {
const commentValue = v as Comments
if(v.fieldId === 'comments') {
return commentValue.comments!.map((v) => <Comment {...v} />)
}
return (
<div
key={`${v.fieldId}${i}`}
dangerouslySetInnerHTML={{
__html: v.fieldId === 'html' || v.fieldId === 'markdown' ? marked(v?.value) : v?.value,
}}
/>
)
})}
</div>
</EntryBody>
body
にapi
から取得してきた、繰り返しの設定を行った配列が返ってきます。fieldId
にカスタムフィールド作成時に設定したカスタムフィールド名が返ってきます。
返ってきた値によって。表示するコンポーネントを変えてあげることで、さまざまなコンポーネントを作ってUIを再現することができます。
まとめ
他にもいろいろなコンポーネントをカスタムフィールドを使って作ることができると思うので
いろいろな便利なUIを作ってブログを面白くしていきたいです!