コンテンツにスキップ

UI コンポーネントとカスタム開発

EpoCanvas Docs の UI はゼロから作ったものではなく、Starlight のネイティブコンポーネントをベースにピンポイントでオーバーライドしたものです。Starlight のページ骨格とコンテンツ処理の能力を残しつつ、トップバー・サイドバー・目次・検索などの表示コンポーネントを差し替えることで、狙いどおりの 3 カラムレイアウトとインタラクションを実現しています。このページでは、このコンポーネント体系の構造と変更方法を説明します。


コンポーネントのオーバーライド機構

Starlight では、astro.config.mjs の components フィールドで任意のネイティブコンポーネントをカスタム実装に置き換えられます。このプロジェクトでは 7 つのコンポーネントをオーバーライドしています:

// astro.config.mjs(抜粋)
components: {
Header: './src/components/starlight/Header.astro',
Sidebar: './src/components/starlight/Sidebar.astro',
TableOfContents: './src/components/starlight/TableOfContents.astro',
PageTitle: './src/components/starlight/PageTitle.astro',
TwoColumnContent: './src/components/starlight/TwoColumnContent.astro',
Search: './src/components/starlight/Search.astro',
Pagination: './src/components/starlight/Pagination.astro',
},

ビルド時、Starlight がページをレンダリングする各位置では、ここで指定されたファイルが優先的に使われます。オーバーライドしていないコンポーネント(フッターの Footer やモバイルメニューなど)は引き続きネイティブ実装が使われます。


7 つのカスタムコンポーネントの役割

ソースコードはすべて src/components/starlight/ にあり、規模と役割は次のとおりです:

コンポーネントファイル規模役割
Header.astro約 646 行トップバーの全内容: ロゴ、検索ボックス、メインナビ、バージョン バッジ、言語切替、テーマ切替、GitHub と Telegram への入口
Search.astro約 837 行2 モード検索: トップバーのページ内検索(ハイライトとカウント)+ Ctrl+K のサイト全体検索ポップアップ(Pagefind UI)
Pagination.astro約 123 行下部の「前のページ / 次のページ」カード。フラットな細枠、テーマカラーのタイトル、↙/↘ の斜め矢印でページ送りの方向を表示
TwoColumnContent.astro約 77 行本文と右側目次の 2 カラム骨格。右カラムの固定幅とスクロールを制御
TableOfContents.astro約 65 行「目次」の見出し、アイコンと目次リスト。ページ自身のタイトルは除外
PageTitle.astro約 65 行ページの大きな見出し(Frontmatter の title を使用)と「最終更新」タイムスタンプ
Sidebar.astro約 22 行薄いラッパー。Starlight 公式の SidebarPersister を再利用し、ページ移動時にサイドバーのスクロール位置を維持

データフロー: 3 つの設定ファイルが UI 全体を駆動

カスタムコンポーネント自体は業務データを持たず、UI の内容は 3 つの設定ファイルによって駆動されます:

astro.config.mjs ──→ locales + sidebar 配列 ──→ Sidebar.astro が左側カタログをレンダリング(各言語は対応する訳語ラベルを使用)
src/config/navigation.ts ──→ navigationConfig ──→ Header.astro がトップナビとハイライトをレンダリング(リンクは自動的に言語プレフィックス付き)
src/utils/i18n.ts ──→ UI_TRANSLATIONS 辞書 ──→ 各コンポーネントはビルド時に現在の言語で語句を取得
  • 左側カタログは astro.config.mjs の sidebar 宣言のみを参照します。新規ドキュメントは必ずここに登録する必要があり、各エントリの translations フィールドで 10 言語分のメニュー文言を提供します。
  • トップナビの各項目の表示文言は labelKey で i18n.ts の辞書から翻訳を取得し、match 関数が現在ページでどのボタンをハイライトするかを決定します(判定の前に言語プレフィックスを除去します)。
  • UI 文言(検索ボックスのプレースホルダー、「目次」の見出し、テーマ切替の案内など)は、各コンポーネントが getTranslation(key, lang) を呼び出してビルド時に対応する言語を直接出力します。ページ内に実行時の置換スクリプトはありません。

つまり、UI の内容を変えたい場合はまず対応する設定ファイルを探し、見た目(余白・色・アイコン)だけを変える場合にのみコンポーネントのソースコードを触ります。


各コンポーネントの実装のポイント

PageTitle: ページタイトルと実際の更新日時

ページの大きな見出しは Frontmatter の title をそのまま読み込むため、本文中に # の見出し(レベル 1)を書かないでください。「最終更新」のタイムスタンプはビルド時の Git コミット履歴から取得されます(astro.config.mjs で lastUpdated: true が有効)。コミットのたびに自動更新されるため、手動での管理は不要です。

Sidebar.astro は 20 行余りしかなく、核心は Starlight 公式の SidebarPersister コンポーネントを再利用している点です。ページ切替時にサイドバーの DOM を再構築しないため、スクロール位置が保たれます。これが左側カタログが「ページを移動してもガタつかない」仕組みです。

TableOfContents: 目次の生成

目次データは、Starlight がビルド時に本文の見出し(## と ###)を解析して生成します。コンポーネントはページ自身のタイトルを除外してレンダリングするだけです。スクロール時のハイライトは starlight-toc カスタム要素がブラウザ側で処理し、フレームワークには依存しません。

TwoColumnContent: 右カラム幅の唯一の定義元

右側目次カラムの幅は @media (min-width: 72rem) で 20rem に固定され(超ワイド画面の 90rem 以上では 21rem)、本文エリアの最大幅はそこから右カラム幅が差し引かれます。右カラム幅を調整したい場合は、この 1 ファイルだけを変更すればよく、他のスタイルシートに点在する形で上書きしないでください。

Header: ナビ、テーマ、言語

  • ナビボタンは navigationConfig を走査してレンダリングされ、アクティブ状態のスタイルは match 関数の戻り値で決まります。リンクは localizedHref() により現在言語のプレフィックスが自動付加されます。
  • テーマ切替は LocalStorage の starlight-theme キーに書き込まれ、ページ読み込み時は「ローカルでの選択 → システム設定」の順に初期テーマを決定します。
  • 言語ドロップダウンの各項目は、現在ページの対応言語版への実リンクです。クリックするとそのまま遷移し、追加の状態保存はありません。
  • トップバー右側の GitHub と Telegram の両アイコンは src/components/starlight/Header.astro に直接書き込まれています。アドレスを変えるにはこのファイルを編集してください。Telegram は @epocanvas アカウントページを指し、ツールチップの文言は語条 social.telegram です。astro.config.mjs の social が制御するのはサイドバー下部のアイコン群で、両者は互いに影響しません。

Search: 2 モード検索

1 つのコンポーネント内に 2 つの検索を実装しています(詳しくは全文検索とショートカットキーの使い方を参照):

  1. ページ内検索: トップバーの入力ボックス。Enter キーで現在ページ内の一致文字列間を移動し、ハイライトはスクリプトがマークを打つことで実現します。
  2. サイト全体検索: <dialog> ポップアップ + Pagefind のデフォルト UI。index は pnpm run build の段階で生成されます。

Pagination: ページ送りカード

前 / 次のページのデータは、Starlight がビルド時に sidebar の順序に基づいて計算済みで(Astro.locals.starlightRoute.pagination)、コンポーネントはレンダリングだけを担当します。同幅の 2 枚のカード、細枠で影なし、タイトルはテーマカラー、↙ / ↘ の斜め矢印はホバー時にページ送りの方向へ移動します。矢印はインライン SVG パスで、サイトを RTL 言語で使う場合は自動的に方向が反転します。


カスタマイズ時の注意点

  • スタイル変更はまず CSS 変数で: 色・フォント・レイアウトサイズは src/styles/custom.css の :root 変数に集約されています。サイト全体の設定とスタイルのカスタマイズを参照してください。多くのカスタマイズはコンポーネントを触る必要がありません。
  • インタラクションを変えるときだけコンポーネントを触る: ボタンの追加や構造の調整の際は、UI 文言を getTranslation(key, lang) で取得し、i18n.ts に 10 言語分の語句を追加します。漏れた言語は fallback で中国語が表示されます。
  • 変更後は必ずローカルで検証: pnpm run dev でインタラクションを確認し、pnpm run build で型チェックとビルドの通過を確認します(ローカル用コマンドはよくある質問とトラブルシューティングを参照)。

具体的なカスタマイズ手順は、よくあるカスタマイズ早見表を参照してください。