Add prev/next textbook nav to wiki pages #77

Merged
claude merged 1 commits from feat/wiki-prev-next-nav into main 2026-06-22 19:22:01 -04:00
+46 -27
View File
@@ -8,7 +8,8 @@ the `--host` URL flavor and the CI wrapper differ.
The wiki is GENERATED BUILD OUTPUT. Never hand-edit it; edit modules/ and let CI
re-render. Labs are NOT copied into the wiki — lesson pages link to the runnable
files back in the main repo.
files back in the main repo. Each page gets prev/next navigation so the wiki reads
like a textbook.
Usage:
build_wiki.py --repo-root . --out <wiki-dir> \
@@ -105,6 +106,19 @@ def home_intro(repo_root: Path) -> str:
return "\n".join(out).strip()
def top_nav(prev) -> str:
"""prev is (page, label) or None."""
if not prev:
return ""
return f"⬅ **Previous: [{prev[1]}]({prev[0]})**\n"
def bottom_nav(nxt) -> str:
if not nxt:
return ""
return f"**Continue to: [{nxt[1]}]({nxt[0]})** ➡\n"
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--repo-root", default=".")
@@ -123,43 +137,47 @@ def main() -> int:
print("no modules found", flush=True)
return 1
# --- pass 1: read everything, build the ordered reading sequence ------
# each entry: {page, label, body, slug|None}
seq = []
titles: dict[int, str] = {}
slugs: dict[int, str] = {}
# --- per-module pages -------------------------------------------------
for num, slug, path in mods:
body = (path / "README.md").read_text(encoding="utf-8")
h1 = first_h1(body, f"Module {num}")
titles[num] = h1
slugs[num] = slug
source_path = f"modules/{slug}/README.md"
body = rewrite_lab_links(body, args.web_base, args.branch, args.host, slug)
body = rewrite_repo_file_links(body, args.web_base, args.branch, args.host)
page = (
banner(source_path, src_url(args.web_base, args.branch, args.host, source_path))
+ "\n"
+ body
+ "\n"
)
(out / f"{slug}.md").write_text(page, encoding="utf-8")
seq.append({"page": slug, "label": h1, "body": body, "slug": slug})
# --- capstone ---------------------------------------------------------
cap = repo_root / "capstone" / "README.md"
cap_title = None
if cap.exists():
body = cap.read_text(encoding="utf-8")
cap_title = first_h1(body, "Capstone — The Full Loop")
source_path = "capstone/README.md"
# capstone labs may reference modules/.. ; only lab/ links are rewritten elsewhere,
# capstone has none, so copy through with a banner.
body = rewrite_repo_file_links(body, args.web_base, args.branch, args.host)
page = (
banner(source_path, src_url(args.web_base, args.branch, args.host, source_path))
+ "\n"
+ body
+ "\n"
)
(out / "capstone.md").write_text(page, encoding="utf-8")
seq.append({"page": "capstone", "label": cap_title, "body": body, "slug": None})
# --- pass 2: write each page with banner + prev/next nav --------------
for i, entry in enumerate(seq):
prev = (seq[i - 1]["page"], seq[i - 1]["label"]) if i > 0 else None
nxt = (seq[i + 1]["page"], seq[i + 1]["label"]) if i < len(seq) - 1 else None
if entry["slug"] is not None:
source_path = f"modules/{entry['slug']}/README.md"
body = rewrite_lab_links(entry["body"], args.web_base, args.branch, args.host, entry["slug"])
body = rewrite_repo_file_links(body, args.web_base, args.branch, args.host)
else:
source_path = "capstone/README.md"
body = rewrite_repo_file_links(entry["body"], args.web_base, args.branch, args.host)
parts = [banner(source_path, src_url(args.web_base, args.branch, args.host, source_path))]
tn = top_nav(prev)
if tn:
parts.append("\n" + tn)
parts.append("\n" + body)
bn = bottom_nav(nxt)
if bn:
parts.append("\n---\n\n" + bn)
(out / f"{entry['page']}.md").write_text("\n".join(parts) + "\n", encoding="utf-8")
# --- _Sidebar.md (textbook nav) --------------------------------------
sb = ["### [📖 Home](Home)\n"]
@@ -205,9 +223,10 @@ def main() -> int:
encoding="utf-8",
)
pages = len(mods) + (1 if cap_title else 0) + 3
pages = len(seq) + 3
print(f"wrote {pages} wiki files to {out} ({len(mods)} modules"
f"{' + capstone' if cap_title else ''} + Home/_Sidebar/_Footer)", flush=True)
f"{' + capstone' if cap_title else ''} + Home/_Sidebar/_Footer, with prev/next nav)",
flush=True)
return 0