トップナビゲーションとページルーティング
トップナビゲーションバーは、ユーザーが各機能セクションの間を行き来するための主な通路です。EpoCanvas Docs ではすべてのナビゲーション項目を 1 つの設定ファイルに集めており、1 か所の変更だけでサイト全体に反映されます。さらに、現在のページを正確にハイライトする仕組みと、過去のリンクのリダイレクト機構も組み込まれています。
ナビゲーション設定の一元管理 (src/config/navigation.ts)
トップバーのナビゲーションボタンはすべて、src/config/navigation.ts 内で宣言的な配列として管理されています。各エントリーのフィールド定義は次のとおりです。
// ナビゲーションエントリーのプロパティ定義export interface NavItem { id: string; // 一意の識別子 labelKey: string; // 多言語翻訳辞書内のキー名 defaultLabel: string; // デフォルトで表示するテキスト(例:「ホーム」「製品概要」) href: string; // ジャンプ先のリンクまたは相対パス match?: (pathname: string) => boolean; // 現在のページでこのボタンをハイライトすべきかを判定するルール badge?: string; // 追加で表示する小さなカプセル型バッジ(例:バージョン番号 "v1.2.0") isExternal?: boolean; // 外部 Web ページへの遷移かどうか(true の場合は新しいウィンドウで開く)}現在の公式設定(抜粋)
export const navigationConfig: NavItem[] = [ { id: 'home', labelKey: 'nav.home', defaultLabel: '首页', href: '/', match: (pathname: string) => pathname === '/' || pathname === '', }, { id: 'docs', labelKey: 'nav.docs', defaultLabel: '产品说明', href: '/canvas/', match: (pathname: string) => pathname === '/canvas' || pathname === '/canvas/' || pathname.includes('about') || pathname.includes('layout') || pathname.includes('search-engine') || pathname.includes('i18n') || pathname.includes('navigation'), }, { id: 'quickstart', labelKey: 'nav.quickstart', defaultLabel: '快速上手', href: '/canvas/deployment/', match: (pathname: string) => pathname.includes('deployment'), }, // この先には guide(執筆ガイドライン)、deploy(デプロイ)、faq(よくある質問)などもある // また、GitHub Releases を指す release の外部エントリーもある];ナビゲーション項目の追加・削除は、この配列にエントリーを追加・削除するだけで行えます。保存するとローカル開発サーバーが自動的にホットリロードします。
動的なアクティブ化とハイライトのルール
単純に pathname.startsWith('/canvas') だけを判定していると、「クイックスタート」ページの /canvas/deployment/ にアクセスしたときに「製品概要」と「クイックスタート」の 2 つのボタンが同時に点灯してしまい、混乱を招きます。
そこで各ナビゲーション項目は、match 関数で自分のハイライト範囲を宣言しています。
- ホーム
/にアクセスしたときは「ホーム」ボタンだけがアクティブになります。 /canvas/layout/、/canvas/about/などの通常のドキュメントにアクセスしたときは「製品概要」ボタンがアクティブになります。deploymentパスのページに入ったときは「クイックスタート」ボタンだけが排他的にアクティブになります。- アクティブなボタンにはテーマカラーのカプセル状の背景が付き、非アクティブなボタンと明確に区別できます。
新しいドキュメントページを追加するときは、パスのキーワードを対応するナビゲーション項目の match ルールに加えるのを忘れないでください。忘れるとトップバーが正しくハイライトされません。
外部リンクとバージョンバッジの挙動
あるナビゲーション項目が外部サイト(たとえば GitHub リポジトリの Releases ページ)を指している場合は、次のようになります。
isExternal: trueを設定します。- システムがそのリンクに
target="_blank" rel="noopener noreferrer"のセキュリティ属性を自動的に付け、新しいタブで開きます。 - テキストの横に斜め向きの小さな矢印アイコン(
↗)が表示され、クリックすると現在のサイトを離れることが読者に伝わります。
バージョンバッジはボタン内のカプセル表示で、文言は src/config/navigation.ts の CURRENT_DOCS_VERSION から取ります。これは package.json の version を直接読むため、リリース時に書き換えるのは package.json の 1 箇所だけでよく、ヘッダーは自動追従します。バッジをクリックすると GitHub のリリース一覧へ開きます。手順は バージョン管理と自動化ワークフロー を参照してください。
ページのリダイレクト規則 (astro.config.mjs)
プロジェクトの反復の中では、ドキュメントのパスを調整することは避けられません。読者のブックマークにある古いリンクが 404 にならないように、astro.config.mjs の redirects テーブルに新旧パスの対応を登録できます。
export default defineConfig({ redirects: { // サイト内の章パスを意味の分かる名前に変更した後も、旧リンクはすべてリダイレクトを維持する '/canvas/rule-engine': '/canvas/cloudflare/', '/canvas/dns-setup': '/canvas/layout/', },});Astro はビルド時にこれらのパスの自動転送ページを生成します。読者が古いアドレスにアクセスすると新しいアドレスへスムーズに案内され、検索エンジンの評価も引き継がれます。
本番で 301 が返る理由
Astro が生成する転送ページは 200 の meta-refresh 文書で、検索エンジンには別ページとして認識されます。Cloudflare Pages はサイトの _redirects を静的ファイルより先に適用するため、astro.config.mjs の cloudflareRedirectsFile() がビルド完了後に同じ legacyRedirects から dist/_redirects を書き出します:
/mail /canvas/ 301/mail/ /canvas/ 3012 行の違いは末尾スラッシュだけで、Cloudflare はパスを完全一致で照合するため、スラッシュ付きのリクエストはスラッシュ無しのルールに当たらず、あの 200 ページに落ちます。手元の pnpm run preview は _redirects を読まないため Astro の転送ページが使われ、両者は共存します。
旧パスを追加するのはスラッシュ無しの 1 行だけにしてください。Astro はそれを <旧パス>/index.html として描画するため、スラッシュ付きも redirects に書くと同一ルートに衝突し、ビルド時に route collision の警告が出ます(Astro の次のメジャーではエラーで停止します)。