mirror of
https://github.com/fluffos/fluffos
synced 2026-08-12 18:26:06 -04:00
* docs: fully-expandable generated sidebar, replacing index.md link pages
Rework docs navigation so the sidebar expands to every page of every
reference tree, instead of terminating at generated index.md link lists:
- New docs/gen_sidebar.py (replaces gen_index.py + update_index.sh):
walks efun/, apply/, stdlib/, concepts/, driver/, cli/ and zh-CN/ and
emits sidebars.generated.json — a full Docusaurus category tree per
directory. Category landing pages are now `generated-index` card pages
(title/description/slug), so all generated index.md files are deleted.
--check mode verifies freshness; new .github/workflows/docs-sidebar.yml
runs it in CI.
- New docs/sidebar_meta.json holds curated presentation: category labels,
one-line descriptions (shown on the landing cards), explicit ordering
(driver/cli/concepts read top-down from user-facing to internals) and
per-page label overrides.
- sidebars.ts becomes a hand-authored skeleton (Getting Started, lpc/,
Historical) that splices in the generated trees.
Content reorganization (from a docs-wide review):
- Move misplaced efun pages out of efun/general: terminal/protocol efuns
(act_mxp, send_zmp, request_term_*) to interactive/, debugging efuns
(check_memory, dump_*, clear_debug_level, destructed_objects) to
internals/, shallow_inherit_list to system/.
- Delete stub duplicates superseded by complete pages elsewhere:
general/parse_{add_synonym,dump,my_rules,remove}, contrib/{shuffle,
element_of}.
Modernize key pages with MDX:
- index.mdx: landing page with a card grid linking each doc section.
- build.mdx: per-platform <Tabs> (Ubuntu/macOS/Windows/Alpine+Docker),
admonitions, VitePress [[toc]] leftover removed, stale per-platform CI
workflow links updated to the unified ci.yml.
- ffi-plan.md: GitHub-style [!CAUTION] alert converted to an admonition.
`npm run build` passes clean (onBrokenLinks: throw, no warnings).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174GM2azvAHBmvyESwxm5om
* docs: serve the Chinese corpus through Docusaurus i18n
Move the zh-CN/ directory out of the default docs tree and into a proper
Docusaurus locale (i18n/zh-CN/docusaurus-plugin-content-docs/current/):
- The flat zh-CN/efun/ directory (333 pages) is re-homed to mirror the
categorized English layout (name-matched 1:1; `hash` maps to strings/
per its own frontmatter). apply/ pages map 1:1; the stray English-text
zh-CN/apply/master/view_errors.md documents a MudOS-era apply that no
longer exists in the driver and is dropped; stdlib/db/database_zh.md
becomes the i18n translation of stdlib/db/database.md; the Chinese
build guide becomes the translation of build.mdx.
- Untranslated pages automatically fall back to English content under
/zh-CN/, so the whole site is navigable in either locale from the new
navbar locale dropdown.
- Both locales share one sidebar. Generated sidebar items now carry
stable `key` fields (the directory/doc path) so translation keys are
unique (both efun/ and stdlib/ have an "Arrays" category, crypto and
strings both document `hash`). Category labels, generated-index
titles/descriptions, navbar and footer are translated in
i18n/zh-CN/...; theme UI strings come from Docusaurus' bundled
zh-Hans translations. Translated landing page at /zh-CN/.
- The "中文文档" sidebar section, the zh-CN tree in gen_sidebar.py /
sidebar_meta.json, and its slice of sidebars.generated.json are gone.
- Relative .md-file links on pages that render in both locales break
the localized build (the file->permalink map points at the localized
copy), so concepts/, the two socket_*_option pages and the config.md
generator now emit extension-less route links instead.
- zh interactive.md/objects.md get explicit slugs like their English
counterparts (a doc named after its parent directory is otherwise a
Docusaurus category-index doc, colliding with the generated-index
route).
`npm run build` builds both locales clean (onBrokenLinks: throw).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174GM2azvAHBmvyESwxm5om
---------
Co-authored-by: Claude <noreply@anthropic.com>
161 lines
5.7 KiB
Python
Executable file
161 lines
5.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Generate sidebars.generated.json for the reference doc trees (efun/, apply/, ...).
|
|
|
|
Usage: gen_sidebar.py [--check]
|
|
|
|
Replaces the old gen_index.py, which wrote per-directory index.md link pages.
|
|
Navigation is now the Docusaurus sidebar itself: this script walks each
|
|
reference tree and emits a fully-expandable category tree per directory.
|
|
Category landing pages are Docusaurus `generated-index` pages (auto-generated
|
|
card grids), so no index.md files are written or needed in these trees.
|
|
|
|
Curated presentation lives in sidebar_meta.json, keyed by directory (or page)
|
|
path relative to docs/:
|
|
|
|
"efun/arrays": { "label": "Arrays", "description": "..." }
|
|
"driver": { "label": "...", "description": "...",
|
|
"order": ["config", "wasm", ...],
|
|
"labels": { "config": "Runtime Configuration" } }
|
|
|
|
Per-directory meta keys:
|
|
label sidebar label for the category (default: directory name)
|
|
description shown on the generated-index landing page
|
|
order page/subdir names listed first, in this order; anything not
|
|
listed follows alphabetically (subdirectories, then pages)
|
|
labels per-page sidebar label overrides (default: file name)
|
|
|
|
sidebars.ts imports sidebars.generated.json and splices each tree into the
|
|
sidebar skeleton. Run this script after adding/removing/moving any page in
|
|
the trees below; CI verifies freshness with --check.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
DOCS_ROOT = os.path.dirname(os.path.realpath(__file__))
|
|
META_FILE = os.path.join(DOCS_ROOT, "sidebar_meta.json")
|
|
OUT_FILE = os.path.join(DOCS_ROOT, "sidebars.generated.json")
|
|
|
|
# The doc trees this script owns. lpc/ is NOT here: its index pages are
|
|
# hand-written and its sidebar is hand-authored in sidebars.ts. The Chinese
|
|
# corpus lives in i18n/zh-CN/ (Docusaurus i18n) and shares this sidebar;
|
|
# its category labels are translated in
|
|
# i18n/zh-CN/docusaurus-plugin-content-docs/current.json.
|
|
TREES = ["efun", "apply", "stdlib", "concepts", "driver", "cli"]
|
|
|
|
# Directory entries that are never documentation content.
|
|
SKIP_DIRS = {"node_modules"}
|
|
|
|
|
|
def load_meta():
|
|
with open(META_FILE, encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def list_entries(path):
|
|
"""Return (md_files, subdirs) for a directory, sorted and filtered.
|
|
|
|
md_files are page names without the .md/.mdx extension (index excluded);
|
|
subdirs are documentation subdirectories.
|
|
"""
|
|
files = []
|
|
subdirs = []
|
|
for entry in sorted(os.listdir(path)):
|
|
if entry.startswith(".") or entry in SKIP_DIRS:
|
|
continue
|
|
full = os.path.join(path, entry)
|
|
if os.path.isdir(full):
|
|
subdirs.append(entry)
|
|
else:
|
|
for ext in (".md", ".mdx"):
|
|
if entry.endswith(ext) and entry[: -len(ext)] != "index":
|
|
files.append(entry[: -len(ext)])
|
|
break
|
|
return files, subdirs
|
|
|
|
|
|
def apply_order(names, order):
|
|
"""Names from `order` first (in that order), the rest keep sorted order."""
|
|
if not order:
|
|
return names
|
|
ordered = [n for n in order if n in names]
|
|
return ordered + [n for n in names if n not in ordered]
|
|
|
|
|
|
def build_category(meta, rel):
|
|
"""Build the sidebar category item for directory `rel` (docs-relative)."""
|
|
path = os.path.join(DOCS_ROOT, rel)
|
|
files, subdirs = list_entries(path)
|
|
dir_meta = meta.get(rel, {})
|
|
label = dir_meta.get("label", os.path.basename(rel))
|
|
labels = dir_meta.get("labels", {})
|
|
order = dir_meta.get("order", [])
|
|
|
|
# Subdirectories first, then loose pages — with `order` pulling any
|
|
# explicitly-listed names (of either kind) to the front.
|
|
items = []
|
|
for name in apply_order(subdirs + files, order):
|
|
if name in subdirs:
|
|
items.append(build_category(meta, f"{rel}/{name}"))
|
|
else:
|
|
items.append(
|
|
{
|
|
"type": "doc",
|
|
"id": f"{rel}/{name}",
|
|
# Unique translation key (labels repeat: e.g. hash exists
|
|
# in both efun/crypto and efun/strings).
|
|
"key": f"{rel}/{name}",
|
|
"label": labels.get(name, name),
|
|
}
|
|
)
|
|
|
|
# A stable, unique translation key: labels repeat across trees (both
|
|
# efun/ and stdlib/ have "Arrays"), which would collide in i18n
|
|
# translation files (sidebar.docs.category.<key>).
|
|
category = {"type": "category", "key": rel, "label": label}
|
|
if os.path.exists(os.path.join(path, "index.md")):
|
|
# A hand-written landing page wins over the generated card grid.
|
|
category["link"] = {"type": "doc", "id": f"{rel}/index"}
|
|
else:
|
|
link = {
|
|
"type": "generated-index",
|
|
"title": label,
|
|
"slug": f"/{rel}/",
|
|
}
|
|
if "description" in dir_meta:
|
|
link["description"] = dir_meta["description"]
|
|
category["link"] = link
|
|
category["items"] = items
|
|
return category
|
|
|
|
|
|
def generate():
|
|
meta = load_meta()
|
|
return {tree: build_category(meta, tree) for tree in TREES}
|
|
|
|
|
|
def render(sidebars):
|
|
return json.dumps(sidebars, indent=2, ensure_ascii=False) + "\n"
|
|
|
|
|
|
def main(argv):
|
|
output = render(generate())
|
|
if "--check" in argv:
|
|
try:
|
|
with open(OUT_FILE, encoding="utf-8") as f:
|
|
current = f.read()
|
|
except FileNotFoundError:
|
|
current = ""
|
|
if current != output:
|
|
sys.exit(
|
|
"sidebars.generated.json is stale; run docs/gen_sidebar.py "
|
|
"and commit the result"
|
|
)
|
|
return
|
|
with open(OUT_FILE, "w", encoding="utf-8") as f:
|
|
f.write(output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|