From 2bca823c5354a543b87da7816bd7a3e819308a06 Mon Sep 17 00:00:00 2001 From: parashardhapola Date: Mon, 26 Oct 2026 20:07:38 +0100 Subject: [PATCH] Smooth documentation navigation and move Nygen link to footer --- THIRD_PARTY_NOTICES.md | 10 +++++ docs/build_docs.py | 93 ++++++++++++++++++++++++++++++++++++++++-- docs/source/myst.yml | 2 +- 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 THIRD_PARTY_NOTICES.md diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..0688b68 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,10 @@ +# Third party notices + +## MyST Book Theme + +Source: + +Copyright (c) 2023 Executable Books. License: MIT. + +`docs/build_docs.py` adjusts the documentation theme so navigation sections are +expanded in the initial page and remain expanded when browser code starts. diff --git a/docs/build_docs.py b/docs/build_docs.py index 7b0abce..786f4ca 100644 --- a/docs/build_docs.py +++ b/docs/build_docs.py @@ -402,6 +402,26 @@ def write_discovery_files( ) if route.endswith("/"): script_url = "https://docs.nygen.io/assets/brand/docs.js" + links += ( + '' + ) + links += """""" links += f'' if not count: links = canonical_tag + links @@ -659,13 +679,15 @@ def staged_path(path: str) -> str: def link_shared_brand_assets(html: Path) -> None: - source_options = yaml.safe_load((SOURCE / "myst.yml").read_text())["site"]["options"] + source_options = yaml.safe_load((SOURCE / "myst.yml").read_text())["site"][ + "options" + ] config = json.loads((html / "config.json").read_text()) urls = { config["options"][key]: source_options[key] for key in ("logo", "logo_dark", "favicon", "style") } - nodes = [config["parts"]["navbar_end"]["mdast"]] + nodes = [config["parts"]["footer"]["mdast"]] symbols = [] while nodes: node = nodes.pop() @@ -697,7 +719,7 @@ def link_shared_brand_assets(html: Path) -> None: ("favicon.ico", source_options["favicon"]), ("myst-theme.css", source_options["style"]), ): - pattern = r'href:`\$\{[\w$]+\|\|""\}/' + re.escape(name) + r'`' + pattern = r'href:`\$\{[\w$]+\|\|""\}/' + re.escape(name) + r"`" contents, count = re.subn(pattern, f"href:{json.dumps(public)}", contents) if count != 1: raise ValueError(f"Expected one {name} link in {roots[0]}") @@ -729,6 +751,67 @@ def link_shared_brand_assets(html: Path) -> None: (html / "myst-theme.css").unlink() +def prepare_site_template(site: Path) -> None: + template_url = yaml.safe_load((site / "myst.yml").read_text())["site"]["template"] + template = ( + site + / "_build" + / "templates" + / "site" + / hashlib.sha256(template_url.encode()).hexdigest() + ) + if not (template / "template.yml").is_file(): + subprocess.run( + ["myst", "templates", "download", "--site", template_url], + cwd=site, + check=True, + ) + replacements = { + "build/index.js": ( + 'Pje.default.useState(i);(0,Pje.useEffect)(()=>{o.state==="idle"' + "&&s(tzt([t],e,r).includes(t.id))}", + 'Pje.default.useState(!0);(0,Pje.useEffect)(()=>{o.state==="idle"&&s(!0)}', + ), + "public/build/_shared/chunk-LS4ALTVG.js": ( + '_0.default.useState(o);(0,_0.useEffect)(()=>{i.state==="idle"' + "&&a(DS([t],e,r).includes(t.id))}", + '_0.default.useState(!0);(0,_0.useEffect)(()=>{i.state==="idle"&&a(!0)}', + ), + } + fingerprint = hashlib.sha256( + json.dumps(replacements, sort_keys=True).encode() + ).hexdigest()[:12] + for filename, (original, expanded) in replacements.items(): + path = template / filename + if not path.is_file() and filename.startswith("public/"): + path = path.with_stem(f"{path.stem}-{fingerprint}") + content = path.read_text() + if content.count(original) == 1 and expanded not in content: + path.write_text(content.replace(original, expanded)) + elif original in content or content.count(expanded) != 1: + raise ValueError(f"Unexpected navigation component in {path}") + modules = list((template / "public" / "build").rglob("*.js")) + filenames = { + path.name: f"{path.stem}-{fingerprint}.js" + for path in modules + if not path.stem.endswith(f"-{fingerprint}") + } + if not filenames: + return + if len({path.name for path in modules}) != len(modules): + raise ValueError(f"Duplicate browser module filenames in {template}") + references = re.compile(r"(? None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( @@ -737,9 +820,11 @@ def main() -> None: help="Allow missing executions and label those pages as source previews", ) args = parser.parse_args() + site = prepare_site(preview=args.preview) + prepare_site_template(site) subprocess.run( ["myst", "build", "--html", "--strict"], - cwd=prepare_site(preview=args.preview), + cwd=site, check=True, ) revision = subprocess.run( diff --git a/docs/source/myst.yml b/docs/source/myst.yml index a40520f..74c7732 100644 --- a/docs/source/myst.yml +++ b/docs/source/myst.yml @@ -92,7 +92,7 @@ site: template: https://github.com/myst-templates/book-theme/archive/23f2df5493e23dfb1d9433c8aa64c87beb4232a3.zip parts: primary_sidebar_footer: - navbar_end: 'Nygen documentation home' + footer: 'Nygen documentation home' options: folders: true style: https://docs.nygen.io/assets/brand/myst.css