コース

このページの内容

コース

コース は、一連のページを案内付きの番号順シーケンス - レッスン1、レッスン2、 レッスン3…… - に変えます。自動生成される独自の番号付きインデックス、その コース自身に閉じた「Lesson N of M」の前後リンク(サイト全体のページ間の順序 とは独立しています)、そして読者が一度レッスンを開くと、そこから先は自分の ブラウザの中で進捗が記録されます: どのレッスンを完了したか、そして最後に 訪れたレッスンへ戻る「Continue where you left off」リンクです。

マニフェスト

docs/data/courses.yaml.yml/.json も使えます - データファイル を参照)ファイルを追加します。各トップレベルキーが1つのコースで、その lessons 配列がそのコース自身のページを順番に並べます - 配列内の位置が そのままレッスン番号 になります:

getting-started:
  title: "Getting Started with BoxLang"
  description: "A guided walkthrough from install to your first deployed site."
  lessons:
    - guides/course/introduction.md
    - guides/course/windows-installation.md
    - guides/course/mac-installation.md
    - guides/course/creating-a-new-site.md

lessons の各エントリは docs/ 相対のパス文字列で、nav.json 自身が使って いるのと同じ相対パスの規約です。レッスン自身のタイトル/サマリは そのページ 自身のフロントマター から取得され - マニフェストに複製されることはありません

  • そのため、ページのタイトルをリネームしたり、サマリを編集したりすると、 コースインデックスに自動的に反映されます。複数のコースは、単に同じファイル 内に複数のトップレベルキーがあるだけのことです。

インデックス

Markdown のどこかに1行を置くだけで、そのコース自身の番号付きインデックスが レンダリングされます:

::: course id="getting-started" :::

これは本物のセマンティックな <ol> を1つレンダリングします - レッスンごとに 1つの番号付きリンクがあり、それぞれがそのレッスン自身のタイトルとサマリを 持ちます - さらに(最初は非表示で、読者が実際にコースを開始してから クライアントサイドで埋められる)進捗バーと「Continue where you left off」 リンクが付きます。id のタイプミスや、レッスンがすべて揃っていないコースは、 ビルドを失敗させる代わりに、小さな目に見える注記に成り下がります。

レッスンページ

コースの lessons に列挙されたページはすべて、自動的に course コンテキスト (page.course - コンテキスト変数 を参照)を、自分自身の位置・タイトル、そして そのコースに閉じた 前後リンク とともに受け取ります - page.course.prevLesson/.nextLesson は、常にその1つの コース内だけを移動します。これは、コースの有無にかかわらずナビツリー全体を 歩く、サイト自身のグローバルな page.prevPage/.nextPage とは 異なります。レッスンは、自分がどのコースに属しているか、どこに属しているかを 申告する必要はありません - それを決めるのはマニフェストただ1か所であり、 あるページが誤って2つのコースに入ってしまうこともありません(それは執筆上の ミスであり、ビルドが明確なエラーで検出します - エラー を参照)。

現時点では、bootstrap テーマだけが、この閉じたナビゲーション - 「Lesson N of M」バッジ、コースに閉じた前後ページャー、「Mark complete」トグル - を レッスンページ上に直接レンダリングします。他の組み込みテーマもすべて page.course 自体は正しく計算します(そのため、それらのテーマを使っている プロジェクトでも、独自のテーマオーバーライド 経由ですでにこれを表示できます)。残りの組み込みテーマにおけるネイティブな 表示はロードマップ上にあります。

進捗トラッキング

読者が一度レッスンを開くと、そのページ自身の隠しマーカーが course-progress.js(すべての組み込みテーマで共有され、常に含まれています) に訪問を記録するよう伝えます - 設定もオプトインも不要です。進捗は、その ブラウザ自身の localStorage の中、bxsites-course-progress-<courseId> というキーの下に完全に保存されます:

{
  "firstStarted": "2026-08-30T14:02:11.000Z",
  "lastVisited": { "url": "/guides/course/mac-installation/", "at": "2026-08-30T14:22:03.000Z" },
  "completed": {
    "/guides/course/introduction/": "2026-08-30T14:05:00.000Z",
    "/guides/course/windows-installation/": "2026-08-30T14:12:44.000Z"
  }
}

レッスンは、そのページが訪問された瞬間に自動的に完了としてマークされます。 「Mark complete」/「Mark incomplete」トグルを使えば、読者は誤って自動マーク されたものを取り消したり、後から戻ってレッスンを再マークしたりできます。 コースインデックスは、このデータをそのまま読み取って、チェックマーク、 進捗バー(「N of M complete」)、そして続きから再開するリンクを埋めます。

これは純粋なクライアントサイドの拡張であり、それなしでもすでに完全に機能 しているコースの上に重ねられているだけです - 番号付きインデックスも、 コースに閉じた前後ページャーも、どちらもサーバーサイドでレンダリングされる ため、JavaScript を無効にした読者や検索クローラーにも、基本機能一式 - 正しく番号が振られ、正しくリンクされたすべてのレッスン - がそのまま見えます。 進捗トラッキングは、コースが機能するために必須のものは何もありません。 ストレージがそもそも利用できない場合(プライベートブラウジング、サイト データのブロックなど)は、静かに「進捗は記憶されない」という状態に縮退する だけで、エラーにはなりません。

進捗はブラウザ単位のもので、背後にアカウントやバックエンドは一切ありません

  • デバイス間で同期されることはなく、誰が何を読んだかというサーバーサイドの 記録もありません。それがプロジェクトにとって本当に必要な要件であれば、それは 今日のこの機能が対応する範囲の外です。

今後の拡張

この機能が意図的にまだ作り込んでいないものが2つありますが、既存の courses.yaml を壊すことなく、将来そこへ育っていけるように形作られています:

  • レッスン間のクイズ。 解決済みのレッスンは、内部的にはすでに type (現時点では常に "lesson")を持っています - 将来のバージョンでは、 lessons のエントリとして、裸のパス文字列に加えて、小さなオブジェクト (例: { path: ..., type: "quiz" })を受け付けられるようになる可能性が あります。裸のパスだけを列挙しているコースには何の変更も必要ありません。
  • コース末尾の最終テスト/評価。 マニフェストのスキーマは、コースごとの 任意のトップレベルキー finalTest を予約しています(現時点では無視され ます)- これは、後からスキーマの破壊的変更なしにこの機能を追加できる ようにするためだけのものです。自分のマニフェストの中で、このキーを他の 用途に使わないでください。

なぜフロントマターではなくマニフェストなのか?

コースのレッスンは、courses.yaml の中でただ一度だけ宣言されます - 各 レッスン自身のフロントマターに散らばる course: getting-started のような フィールドとしてではありません。ページ単位のフィールドは、マニフェストと 並ぶ、強制力のない第二の信頼できる情報源になってしまいます。そして両者が 食い違うこと(あるレッスンのフロントマターは1つのコースを指しているのに、 マニフェストでは別のコースに列挙されている - あるいはどこにも列挙されて いない)は、まさにこの設計が避けようとしている、静かなズレそのものです。 マニフェストこそが、コースの形 - どのレッスンを、どの順序で - を決める 唯一の場所です。レッスンページ自身が、自分がどのコースに属しているか、 どこに属しているかを知る必要は決してありません。

スコープ

  • lessons が現在ビルド中のツリーの中で実在するページとしてすべて揃って いないコースは、そのツリーについては静かにスキップされます。ビルド失敗 にはなりません - これが重要なのは、docs/data/courses.yaml がプロジェクト 全体で一度だけ読み込まれ(データファイル がすでに 持っているのと同じスコープです)、すべてのバージョン/ロケールツリーで 変更なく再利用されるためです。裸の docs/versions/<name>/ スナップショット には、コースのレッスンファイルがまったく含まれていないこともあります。
  • レッスンは1つのコースにしか属せません - 同じパスを2つの異なるコースの下に 列挙するのは実際の執筆上のミスであり、例外が送出されます(エラー を参照)。
  • この最初のバージョンでは、ネスト/マルチトラックのコースはなく、バージョン ごとに異なるレッスン順を持つバージョン別のコースマニフェストもありません。

エラー

  • BxSites.InvalidConfig - docs/data/courses.yaml の形に問題があります: コースの値がオブジェクトでない、title が欠けている、lessons がパス 文字列の空でない配列になっていない、または同じレッスンパスが複数の コースの下に列挙されている、のいずれかです。
このページを編集 Markdownをダウンロード 最終更新 Sep 11, 2026, 7:11:15 PM