microCMSのコードブロックをShikiで彩る
はじめに
最近自分のブログサイトにコードハイライターの Shiki を導入したので、microCMS で入稿したコンテンツを Shiki で彩ったときにやったことを書いていこうと思います
Shiki Transformer Copy Buttonを使ってコピーボタンも追加します
前提
今回使ったフレームワーク、ライブラリは以下です
- Astro 5.1.1
- Cheerio 1.0.0
- Shiki 1.26.2
- Shiki Copy Button 0.0.3
彩っていく
それでは彩っていきます
Shiki は Astro にデフォルトで組み込まれていますが、今回は事前に Shiki でハイライトしたものを表示側に渡すため別でインストールしておきます
上記の対応をするので Astro 以外のフレームワークでもおそらくそのまま使えると思います(使えなかったらすみません)
事前準備
cheerio と Shiki と Shiki Copy Button を追加します
pnpm i cheerio
pnpm i -D shiki shiki-transformer-copy-button
Cheerio と Shiki で彩る
Cheerio で microCMS から渡されるコンテンツを HTML にし、その後 Shiki でハイライトしてもらい、元のコードブロックを置き換えたら表示側に渡します
microCMS のエディタで選択できる言語は code タグのクラス名として渡されるので、クラス名から抜き出して Shiki に渡します
microCMS から渡されるリッチエディタのコンテンツは post.content
に入っていますが、ご自身の環境に合わせて変えてください
const { post } = Astro.props;
const promise: any = [];
const $ = load(post.content);
$("pre").each(function (this: cheerio.Element) {
const element = $(this);
// 言語名を取得
const lang = element.find("code")?.attr("class")?.replace("language-", "");
// preタグをShikiに渡してハイライトしてもらう
const code = codeToHtml(element.text(), {
lang: lang ?? "plaintext", // 言語名
theme: "dark-plus", // Shikiのテーマ
transformers: [addCopyButton({ toggle: 3000 })], // コピーボタンを付与
}).then((highlight) => {
// 元のpreタグを置き換える
element.replaceWith(highlight);
});
promise.push(code);
});
await Promise.all(promise);
// 表示側に渡すための整形済みコンテンツ
const formattedContent = $.html();
これでコードがハイライトされた HTML が生成されました
あとは表示させたい場所に生成した HTML を埋め込みます
<div class="contents" set:html={formattedContent} />
コピーボタンのスタイリング
このままでは追加したコピーボタンが何も表示されないので、コピーボタンのスタイリングをしていきます
コピーボタンのアイコンは https://www.svgrepo.com/ から頂戴したものを public/icons
配下に置いています
pre {
position relative;
}
.copy {
position: absolute;
right: 16px;
top: 16px;
height: 28px;
width: 28px;
padding: 0;
display: flex;
& span {
width: 100%;
aspect-ratio: 1 / 1;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
& .ready {
background-image: url(/icons/copy.svg);
opacity: 0.4;
transition: 0.1s;
&:hover {
opacity: 1;
}
}
& .success {
display: none;
background-image: url(/icons/success.svg);
}
&.copied {
& .success {
display: block;
}
& .ready {
display: none;
}
}
}
完成
実際にブログを表示してみると、以下のように彩られたコードブロックが表示され、右上にコピーボタンも表示されているかと思います
おわりに
今回のコードの全体像は以下から確認できます
ブログの方ではファイル名も表示する処理を入れているため、ちょっとだけコードが違っていますので、もしファイル名を表示する処理も参考にしたい方がいたら全体のコードを見ていただけるとよいかと思います
microCMS 以外の記事ももっと書きたいけどネタがないですね~
Discussion