ディレクトリ階層の表示用に List を使いたい
やりたいこと/方針
- やりたいこと: ファイル/フォルダの階層リストを Markdown 上で表示したい
- 方針: リストの bullet を消す カスタムディレクティブだけ作って、ファイル/フォルダのアイコンは絵文字(📝/📁)で表現
Markdown 上で このように書いたら、
md
:::no-bullets
- 📁 src/
- 📁 components/
- 📄 Header.tsx
- 📄 Footer.tsx
- 📄 index.ts
:::
こう出るということ
- 📁 src/
- 📁 components/
- 📄 Header.tsx
- 📄 Footer.tsx
- 📄 index.ts
- 📁 components/
※ ::: ... :::
という記法、tips, info 等での使用例しか知らなかったから、どうして「カスタムディレクティブ」という呼び名かと思ったら、こうやってカスタマイズした記法を定義するための仕組みだから、ということね。
検討時の経緯:ある日の脳内会議
- 👴 : ファイル名/フォルダ名を list に書いたら、bullet のところ
- 🤖1 : できなくはないんだけど、、
- 🤖2 : カスタマイズ最小の方針にしているのでは?
- 🤖3 : ファイルかどうかは自動判別させないで、明示的に差し込んだ方が可読性が良いかと。特に前提知識ない人には...
- 🤖2 : だいたい作り込んだら、またバグるでしょう。で自動判別されなくてイライラするのが目に浮かぶよ。
- 🤖2 : ちょっと考えたら Makefile とか .git とか引っかかるし。ちゃんとパターン洗い出したの?
- 🤖1 : あと、<li> タグの bullet は同じ階層で別のものにできないから、bullet は消すだけかな
- 🤖1 : これで我慢なさい(bullet消すだけディレクティブ)
- 👴 : うぐぅ...
...
- 🤖??? : UI設計と一緒です。削ぎ落とした先に本当に必要なものがあるのです
...
- 👴 : 落ち着いて考えたら CSS で完結しない?
- 🤖2 : それしたら、通常のリストまで bullet 無しになってしまうでしょうよ。思いつきで発言しないでくれる?
- 👴 : うぐぅ...
実装
- plugin に Custom Directive の interface を作成し
- docusaurus.config.ts から読み込み
- css に「bulletなしリスト」クラスを追加 (Custom Directive で生成された HTMLで指定しているクラス)
plugin
src/plugins/remark-no-bullets.ts
import { Plugin } from 'unified'
import { visit } from 'unist-util-visit'
import { Node } from 'unist'
interface DirectiveNode extends Node {
name: string
type: 'containerDirective'
children: Node[]
}
interface ListNode extends Node {
type: 'list'
data?: {
hProperties?: Record<string, unknown>
}
}
const remarkNoBullets: Plugin = () => {
return (tree) => {
visit(tree, 'containerDirective', (node: DirectiveNode) => {
if (node.name !== 'no-bullets') return
// node の data を削除(<div>化しない)
delete node['data']
// 中の最初の list ノードに class を付与
const targetList = node.children.find((child): child is ListNode => child.type === 'list')
if (targetList) {
targetList.data ??= {}
targetList.data.hProperties ??= {}
targetList.data.hProperties.className = ['no-bullets']
}
})
}
}
export default remarkNoBullets
docusurus.config.ts
ts
import remarkNoBullets from './src/plugins/remark-no-bullets'
...
export default {
// ...
presets: [
[
'classic',
{
docs: {
remarkPlugins: [
remarkNoBullets, // ← ★ これを追加
],
},
},
],
],
}
css
custom.css
ul.no-bullets, ul.no-bullets li {
list-style: none;
padding-left: 0.2em;
}