Default the public catalog to colored PDFs
Some checks are pending
offline / test (push) Waiting to run
Some checks are pending
offline / test (push) Waiting to run
Render published markdown with pandoc + WeasyPrint (indigo tables, dark code). Home page links to PDFs with a top-right switch to Markdown indexes. Serve CONSOLE.pdf from the operator console.
This commit is contained in:
parent
cf4ef9e3af
commit
5ad3222def
9 changed files with 957 additions and 182 deletions
|
|
@ -1,22 +1,30 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Build static documentation site into ./site for zapier.georgelambert.org."""
|
||||
"""Build static documentation site into ./site for zapier.georgelambert.org.
|
||||
|
||||
Markdown is rendered to colored HTML *and* PDF. The home page (index.html)
|
||||
defaults to PDF links; index-md.html is the Markdown/HTML index.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SITE = ROOT / "site"
|
||||
CSS = ROOT / "scripts" / "docs-print.css"
|
||||
|
||||
SECTIONS = [
|
||||
(
|
||||
"Start here",
|
||||
[
|
||||
("packages/overview/README.md", "System overview (plain language)"),
|
||||
("packages/overview/INDEX.md", "Documentation index"),
|
||||
("packages/verae-fleet/docs/CONSOLE.md", "Operator console (Fleet · Trace · Docs)"),
|
||||
("README.md", "Workspace README"),
|
||||
("docs/04-activate/SETUP-ZAPIER-DEVELOPER.html", "Zapier developer setup (HTML)"),
|
||||
("docs/04-activate/SETUP-ZAPIER-DEVELOPER.pdf", "Zapier developer setup (PDF)"),
|
||||
("docs/OPEN.md", "Still open"),
|
||||
("TODO.md", "Implementation TODO / gates"),
|
||||
|
|
@ -33,8 +41,11 @@ SECTIONS = [
|
|||
("docs/02-architecture/modules-and-nats.md", "Module catalog and NATS addresses"),
|
||||
("docs/02-architecture/tree-nodes.md", "Tree nodes and bulk Merkle summaries"),
|
||||
("docs/02-architecture/fleet.md", "Fleet replica floors and monitor"),
|
||||
("packages/overview/README.md", "System overview (TOC)"),
|
||||
("packages/overview/INDEX.md", "Documentation index"),
|
||||
("packages/overview/03-nats-cluster.md", "NATS.IO 3-server cluster"),
|
||||
("packages/overview/04-uptime.md", "Uptime / replica floors"),
|
||||
("packages/overview/05-network-failures.md", "Local network failures"),
|
||||
("packages/overview/06-address-routing.md", "Address routing"),
|
||||
("packages/overview/08-diagrams.md", "Architectural diagrams"),
|
||||
],
|
||||
),
|
||||
(
|
||||
|
|
@ -82,44 +93,162 @@ def copy_tree(src: Path, dest: Path, ignore=None) -> None:
|
|||
shutil.copytree(src, dest, dirs_exist_ok=True, ignore=ignore)
|
||||
|
||||
|
||||
def pandoc_md(src: Path, dest: Path, title: str) -> None:
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
css = """
|
||||
body{font:16px/1.5 Georgia,serif;max-width:48rem;margin:2rem auto;padding:0 1rem;color:#122}
|
||||
a{color:#0b4f8a} code,pre{font-family:ui-monospace,Menlo,monospace;font-size:0.88rem}
|
||||
pre{background:#1b2833;color:#eef;padding:0.8rem;overflow:auto}
|
||||
table{border-collapse:collapse} td,th{border:1px solid #ccc;padding:0.35rem 0.5rem}
|
||||
nav{font:14px system-ui;margin-bottom:1.5rem}
|
||||
"""
|
||||
header = dest.with_suffix(".hdr.html")
|
||||
header.write_text(
|
||||
f"<nav><a href=\"/\">zapier.georgelambert.org</a></nav>\n<style>{css}</style>\n",
|
||||
def site_href_for(path: str, src: Path) -> tuple[str, str]:
|
||||
"""Return (pdf_or_native_href, md_or_html_href) relative to SITE."""
|
||||
suffix = src.suffix.lower()
|
||||
if suffix == ".md":
|
||||
pdf = Path(path).with_suffix(".pdf").as_posix()
|
||||
html = Path(path).with_suffix(".html").as_posix()
|
||||
return pdf, html
|
||||
return path, path
|
||||
|
||||
|
||||
def render_md(src: Path, html_dest: Path, pdf_dest: Path, title: str) -> str:
|
||||
"""Pandoc markdown → colored HTML + WeasyPrint PDF. Returns '' on success."""
|
||||
html_dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
pdf_dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
header = html_dest.with_suffix(".hdr.html")
|
||||
banner = html_dest.with_suffix(".ban.html")
|
||||
rel_src = src.relative_to(ROOT).as_posix() if src.is_relative_to(ROOT) else src.name
|
||||
css_text = CSS.read_text(encoding="utf-8")
|
||||
header.write_text(f"<style>{css_text}</style>\n", encoding="utf-8")
|
||||
banner.write_text(
|
||||
f'<div class="doc-banner">'
|
||||
f'<nav class="site"><a href="/">zapier.georgelambert.org</a>'
|
||||
f' · <a href="/index-md.html">Markdown indexes</a></nav>'
|
||||
f'<div class="kicker">Verae Time × Zapier</div>'
|
||||
f"<h1>{title}</h1>"
|
||||
f'<div class="source-path">{rel_src}</div>'
|
||||
f"</div>\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
subprocess.run(
|
||||
resource = str(src.parent)
|
||||
r = subprocess.run(
|
||||
[
|
||||
"pandoc",
|
||||
str(src),
|
||||
"-o",
|
||||
str(dest),
|
||||
str(html_dest),
|
||||
"--standalone",
|
||||
f"--resource-path={resource}",
|
||||
"--highlight-style=breezedark",
|
||||
f"--metadata=title={title}",
|
||||
f"--include-in-header={header}",
|
||||
f"--include-before-body={banner}",
|
||||
],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
header.unlink(missing_ok=True)
|
||||
banner.unlink(missing_ok=True)
|
||||
if r.returncode != 0:
|
||||
return f"pandoc {src}: {r.stderr[-400:]}"
|
||||
w = subprocess.run(
|
||||
["weasyprint", str(html_dest), str(pdf_dest)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if w.returncode != 0:
|
||||
return f"weasyprint {src}: {w.stderr[-400:]}"
|
||||
return ""
|
||||
|
||||
|
||||
def walk_md_pdf(prefix: Path) -> list[tuple[str, str]]:
|
||||
items = []
|
||||
if not prefix.exists():
|
||||
return items
|
||||
for p in sorted(prefix.rglob("*")):
|
||||
if p.suffix.lower() in {".md", ".pdf", ".html", ".yaml", ".yml", ".svg"} and p.is_file():
|
||||
items.append((rel(p), p.name))
|
||||
return items
|
||||
def convert_all_markdown(copied: list[tuple[Path, Path, str]]) -> list[str]:
|
||||
errors = []
|
||||
n = len(copied)
|
||||
print(f"rendering {n} markdown files to HTML + PDF…")
|
||||
with ThreadPoolExecutor(max_workers=6) as pool:
|
||||
futs = {
|
||||
pool.submit(render_md, src, html, pdf, title): src
|
||||
for src, html, pdf, title in (
|
||||
(
|
||||
src,
|
||||
dest.with_suffix(".html"),
|
||||
dest.with_suffix(".pdf"),
|
||||
title,
|
||||
)
|
||||
for src, dest, title in copied
|
||||
)
|
||||
}
|
||||
done = 0
|
||||
for fut in as_completed(futs):
|
||||
err = fut.result()
|
||||
done += 1
|
||||
if err:
|
||||
errors.append(err)
|
||||
print(f" [{done}/{n}] FAIL {futs[fut].name}")
|
||||
elif done % 25 == 0 or done == n:
|
||||
print(f" [{done}/{n}]")
|
||||
return errors
|
||||
|
||||
|
||||
def format_switch(to_md: bool) -> str:
|
||||
if to_md:
|
||||
href, label = "/index-md.html", "Markdown indexes"
|
||||
else:
|
||||
href, label = "/", "PDF catalog"
|
||||
return (
|
||||
f'<a class="format-switch" href="{href}">{label}</a>'
|
||||
)
|
||||
|
||||
|
||||
def page_shell(now: str, body: str, switch_to_md: bool, title: str) -> str:
|
||||
switch = format_switch(switch_to_md)
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>{title}</title>
|
||||
<style>
|
||||
:root {{ --ink:#171a26; --muted:#5b6178; --line:#d9dce8; --bg:#f4f5fb; --accent:#4f46e5; --accent-deep:#312e81; --soft:#eef0fe; }}
|
||||
body {{ margin:0; font:16px/1.5 Georgia, serif; color:var(--ink); background:var(--bg); }}
|
||||
header {{ background:linear-gradient(160deg,#312e81 0%,#4f46e5 60%,#7c74f0 100%); color:#eef0fe; padding:2rem 1.5rem 1.4rem; position:relative; }}
|
||||
header p {{ max-width:44rem; color:#e4e7ff; }}
|
||||
.kicker {{ letter-spacing:.12em; text-transform:uppercase; font:700 11px system-ui; opacity:.75; }}
|
||||
.format-switch {{
|
||||
position:absolute; top:1.25rem; right:1.5rem;
|
||||
font:650 13px system-ui, sans-serif; color:#fff; text-decoration:none;
|
||||
background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.35);
|
||||
padding:.4rem .75rem; border-radius:999px;
|
||||
}}
|
||||
.format-switch:hover {{ background:rgba(255,255,255,.28); }}
|
||||
main {{ max-width:52rem; margin:0 auto; padding:1.5rem 1.25rem 3rem; }}
|
||||
h1 {{ margin:.4rem 0 .6rem; font-size:1.85rem; }}
|
||||
h2 {{ border-top:1px solid var(--line); padding-top:.8rem; margin-top:1.8rem; color:var(--accent-deep); }}
|
||||
ul {{ padding-left:1.2rem; }}
|
||||
li {{ margin:.35rem 0; }}
|
||||
a {{ color:var(--accent); }}
|
||||
.path {{ color:var(--muted); font:12px ui-monospace, Menlo, monospace; margin-left:.4rem; }}
|
||||
.badge {{ font:700 10px system-ui; letter-spacing:.04em; text-transform:uppercase;
|
||||
background:var(--soft); color:var(--accent); padding:.1rem .35rem; border-radius:4px; margin-left:.25rem; }}
|
||||
input {{ width:100%; padding:.55rem .7rem; font:16px system-ui; border:1px solid var(--line); border-radius:6px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
{switch}
|
||||
<div class="kicker">zapier.georgelambert.org</div>
|
||||
<h1>Verae Time × Zapier documentation</h1>
|
||||
<p>Project reference: setup, architecture, NATS, module APIs, user guide, and operator console.
|
||||
Catalog defaults to <strong>colored PDFs</strong>. Generated {now}.</p>
|
||||
</header>
|
||||
<main>
|
||||
<p><input id="q" type="search" placeholder="Filter links…" /></p>
|
||||
{body}
|
||||
</main>
|
||||
<script>
|
||||
const q = document.getElementById('q');
|
||||
q.addEventListener('input', () => {{
|
||||
const v = q.value.toLowerCase();
|
||||
document.querySelectorAll('li').forEach(li => {{
|
||||
li.style.display = li.textContent.toLowerCase().includes(v) ? '' : 'none';
|
||||
}});
|
||||
}});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
|
@ -147,12 +276,37 @@ def main() -> None:
|
|||
"verae-nats-process",
|
||||
"docs-master",
|
||||
):
|
||||
readme = ROOT / "packages" / pkg / "README.md"
|
||||
if readme.exists():
|
||||
copy_tree(readme, SITE / "packages" / pkg / "README.md")
|
||||
pkg_root = ROOT / "packages" / pkg
|
||||
if pkg in {"zapier-user-docs", "overview", "docs-master"}:
|
||||
copy_tree(
|
||||
pkg_root,
|
||||
SITE / "packages" / pkg,
|
||||
ignore=shutil.ignore_patterns("node_modules", ".git", "src", "test", "data"),
|
||||
)
|
||||
elif pkg == "verae-fleet":
|
||||
for name in ("README.md", "SUMMARY.md", "NATS.md", "SERVICES.md"):
|
||||
p = pkg_root / name
|
||||
if p.exists():
|
||||
copy_tree(p, SITE / "packages" / pkg / name)
|
||||
copy_tree(
|
||||
pkg_root / "docs",
|
||||
SITE / "packages" / pkg / "docs",
|
||||
ignore=shutil.ignore_patterns("node_modules"),
|
||||
)
|
||||
elif pkg == "verae-nats-process":
|
||||
for p in pkg_root.glob("*.md"):
|
||||
copy_tree(p, SITE / "packages" / pkg / p.name)
|
||||
else:
|
||||
readme = pkg_root / "README.md"
|
||||
if readme.exists():
|
||||
copy_tree(readme, SITE / "packages" / pkg / "README.md")
|
||||
zdocs = ROOT / "packages" / "zappier" / "docs"
|
||||
if zdocs.exists():
|
||||
copy_tree(zdocs, SITE / "packages" / "zappier" / "docs", ignore=shutil.ignore_patterns("screenshots", "walkthrough", "superpowers"))
|
||||
copy_tree(
|
||||
zdocs,
|
||||
SITE / "packages" / "zappier" / "docs",
|
||||
ignore=shutil.ignore_patterns("screenshots", "walkthrough", "superpowers"),
|
||||
)
|
||||
for name in ("README.md", "TODO.md", "OPEN.md"):
|
||||
src = ROOT / name
|
||||
if not src.exists() and name == "OPEN.md":
|
||||
|
|
@ -163,11 +317,15 @@ def main() -> None:
|
|||
copy_tree(ROOT / "packages" / "docs-master", SITE / "docs-master")
|
||||
copy_tree(ROOT / "packages" / "overview", SITE / "overview")
|
||||
copy_tree(ROOT / "packages" / "zapier-user-docs", SITE / "user-docs", ignore=shutil.ignore_patterns("node_modules"))
|
||||
copy_tree(
|
||||
ROOT / "packages" / "verae-fleet" / "docs",
|
||||
SITE / "packages" / "verae-fleet" / "docs",
|
||||
ignore=shutil.ignore_patterns("node_modules"),
|
||||
)
|
||||
sim_pub = ROOT / "packages" / "verae-zapier-simulator" / "public" / "index.html"
|
||||
if sim_pub.exists():
|
||||
copy_tree(sim_pub, SITE / "simulator" / "index.html")
|
||||
|
||||
# research markdown + diagrams only
|
||||
r = ROOT / "research" / "zapier"
|
||||
if r.exists():
|
||||
for fname in (
|
||||
|
|
@ -186,45 +344,73 @@ def main() -> None:
|
|||
if diagrams.exists():
|
||||
copy_tree(diagrams, SITE / "research" / "docs" / "diagrams")
|
||||
|
||||
# HTML versions of markdown for the catalog entries
|
||||
html_pairs = []
|
||||
for _title, links in SECTIONS:
|
||||
# Render every published .md from the site copy so relative images resolve.
|
||||
to_render: list[tuple[Path, Path, str]] = []
|
||||
seen: set[Path] = set()
|
||||
for md in SITE.rglob("*.md"):
|
||||
if not md.is_file():
|
||||
continue
|
||||
key = md.resolve()
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
to_render.append((md, md, md.stem.replace("-", " ")))
|
||||
|
||||
# Prefer curated titles for catalog entries
|
||||
title_map = {}
|
||||
for _sec, links in SECTIONS:
|
||||
for path, label in links:
|
||||
src = ROOT / path
|
||||
if src.suffix == ".md" and src.exists():
|
||||
dest = SITE / Path(path).with_suffix(".html")
|
||||
pandoc_md(src, dest, label)
|
||||
html_pairs.append((path, dest.relative_to(SITE).as_posix(), label))
|
||||
title_map[path] = label
|
||||
labeled = []
|
||||
for src, dest, title in to_render:
|
||||
try:
|
||||
key = dest.relative_to(SITE).as_posix()
|
||||
except ValueError:
|
||||
key = dest.name
|
||||
# packages/overview/... also listed as packages/overview
|
||||
labeled.append((src, dest, title_map.get(key, title_map.get(src.relative_to(ROOT).as_posix() if src.is_relative_to(ROOT) else key, title))))
|
||||
|
||||
errors = convert_all_markdown(labeled)
|
||||
|
||||
# Also write CONSOLE.pdf next to the markdown in the fleet package (local console)
|
||||
console_md = ROOT / "packages" / "verae-fleet" / "docs" / "CONSOLE.md"
|
||||
if console_md.exists():
|
||||
err = render_md(
|
||||
console_md,
|
||||
ROOT / "packages" / "verae-fleet" / "docs" / "CONSOLE.html",
|
||||
ROOT / "packages" / "verae-fleet" / "docs" / "CONSOLE.pdf",
|
||||
"Operator console",
|
||||
)
|
||||
if err:
|
||||
errors.append(err)
|
||||
|
||||
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
|
||||
cards = []
|
||||
for title, links in SECTIONS:
|
||||
lis = []
|
||||
for path, label in links:
|
||||
src = ROOT / path
|
||||
if not src.exists() and path == "OPEN.md":
|
||||
src = ROOT / "docs" / "OPEN.md"
|
||||
path = "docs/OPEN.md"
|
||||
if not src.exists():
|
||||
continue
|
||||
href = path
|
||||
html = Path(path).with_suffix(".html").as_posix()
|
||||
if src.suffix == ".md" and (SITE / html).exists():
|
||||
href = html
|
||||
lis.append(f'<li><a href="{href}">{label}</a> <span class="path">{path}</span></li>')
|
||||
cards.append(f"<section><h2>{title}</h2><ul>{''.join(lis)}</ul></section>")
|
||||
|
||||
extra = [
|
||||
("docs/modules/README.md", "Module API sheets"),
|
||||
("docs/models/README.md", "Data models"),
|
||||
("sphinx/index.html", "Sphinx HTML"),
|
||||
("docs/04-activate/SETUP-ZAPIER-DEVELOPER.html", "Setup HTML"),
|
||||
("docs-master/README.md", "Master summaries (docs-master)"),
|
||||
("docs-master/MESSAGE-FLOWS.md", "Numbered message flows"),
|
||||
("docs-master/modules-and-nats.md", "NATS address table"),
|
||||
("user-docs/README.md", "User guide index"),
|
||||
("packages/verae-zapier-simulator/README.md", "Simulator README"),
|
||||
]
|
||||
def cards(mode: str) -> str:
|
||||
out = []
|
||||
for title, links in SECTIONS:
|
||||
lis = []
|
||||
for path, label in links:
|
||||
src = ROOT / path
|
||||
if not src.exists() and path == "OPEN.md":
|
||||
src = ROOT / "docs" / "OPEN.md"
|
||||
path = "docs/OPEN.md"
|
||||
if not src.exists():
|
||||
continue
|
||||
pdf_href, html_href = site_href_for(path, src)
|
||||
if mode == "pdf":
|
||||
href = pdf_href if (SITE / pdf_href).exists() or src.suffix.lower() in {".pdf", ".yaml", ".yml"} else html_href
|
||||
badge = "PDF" if href.endswith(".pdf") else src.suffix.lstrip(".").upper() or "FILE"
|
||||
else:
|
||||
href = html_href if (SITE / html_href).exists() else path
|
||||
badge = "MD" if src.suffix.lower() == ".md" else src.suffix.lstrip(".").upper() or "FILE"
|
||||
lis.append(
|
||||
f'<li><a href="{href}">{label}</a>'
|
||||
f'<span class="badge">{badge}</span>'
|
||||
f'<span class="path">{path}</span></li>'
|
||||
)
|
||||
out.append(f"<section><h2>{title}</h2><ul>{''.join(lis)}</ul></section>")
|
||||
return "".join(out)
|
||||
|
||||
git_repos = [
|
||||
("master-zapier-plan-draft", "Monorepo (this workspace)"),
|
||||
|
|
@ -248,41 +434,44 @@ def main() -> None:
|
|||
f'<span class="path">{desc}</span></li>'
|
||||
for name, desc in git_repos
|
||||
)
|
||||
extra_lis = "".join(
|
||||
f'<li><a href="{h}">{lab}</a></li>' for h, lab in extra if (SITE / h).exists() or h.startswith("sphinx")
|
||||
)
|
||||
|
||||
index = f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>Verae Time × Zapier documentation</title>
|
||||
<style>
|
||||
:root {{ --ink:#12202c; --muted:#52646f; --line:#d5dee4; --bg:#f6f3ee; --accent:#0f6e56; }}
|
||||
body {{ margin:0; font:16px/1.5 Georgia, serif; color:var(--ink); background:var(--bg); }}
|
||||
header {{ background:var(--ink); color:#f6f3ee; padding:2rem 1.5rem; }}
|
||||
header p {{ max-width:44rem; color:#d9e2e8; }}
|
||||
.kicker {{ letter-spacing:.12em; text-transform:uppercase; font:700 11px system-ui; opacity:.75; }}
|
||||
main {{ max-width:52rem; margin:0 auto; padding:1.5rem 1.25rem 3rem; }}
|
||||
h1 {{ margin:.4rem 0 .6rem; font-size:1.85rem; }}
|
||||
h2 {{ border-top:1px solid var(--line); padding-top:.8rem; margin-top:1.8rem; }}
|
||||
ul {{ padding-left:1.2rem; }}
|
||||
li {{ margin:.35rem 0; }}
|
||||
a {{ color:#0b4f8a; }}
|
||||
.path {{ color:var(--muted); font:12px ui-monospace, Menlo, monospace; margin-left:.4rem; }}
|
||||
input {{ width:100%; padding:.55rem .7rem; font:16px system-ui; border:1px solid var(--line); border-radius:6px; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="kicker">zapier.georgelambert.org</div>
|
||||
<h1>Verae Time × Zapier documentation</h1>
|
||||
<p>Project reference: setup checklist, architecture (including NATS job wait and WORM archive fan-out), module API sheets, models, OpenAPI, and research notes. Generated {now}.</p>
|
||||
</header>
|
||||
<main>
|
||||
<p><input id="q" type="search" placeholder="Filter links…" /></p>
|
||||
{''.join(cards)}
|
||||
extra_pdf = [
|
||||
("docs-master/README.pdf", "Master summaries (docs-master)"),
|
||||
("docs-master/MESSAGE-FLOWS.pdf", "Numbered message flows"),
|
||||
("docs-master/modules-and-nats.pdf", "NATS address table"),
|
||||
("user-docs/README.pdf", "User guide index"),
|
||||
("packages/verae-zapier-simulator/README.pdf", "Simulator README"),
|
||||
("packages/verae-fleet/docs/CONSOLE.pdf", "Operator console"),
|
||||
("overview/README.pdf", "System overview"),
|
||||
("overview/INDEX.pdf", "Documentation index"),
|
||||
("docs/modules-pdf/", "Module PDFs (book)"),
|
||||
("docs/models-pdf/", "Model PDFs (book)"),
|
||||
("sphinx/index.html", "Sphinx HTML"),
|
||||
]
|
||||
extra_md = [
|
||||
("docs-master/README.html", "Master summaries (docs-master)"),
|
||||
("docs-master/MESSAGE-FLOWS.html", "Numbered message flows"),
|
||||
("docs-master/modules-and-nats.html", "NATS address table"),
|
||||
("user-docs/README.html", "User guide index"),
|
||||
("packages/verae-zapier-simulator/README.html", "Simulator README"),
|
||||
("packages/verae-fleet/docs/CONSOLE.html", "Operator console"),
|
||||
("overview/README.html", "System overview"),
|
||||
("overview/INDEX.html", "Documentation index"),
|
||||
("docs/modules/", "All module markdown"),
|
||||
("docs/models/", "All model markdown"),
|
||||
("sphinx/index.html", "Sphinx HTML"),
|
||||
]
|
||||
|
||||
def extra_section(items: list[tuple[str, str]]) -> str:
|
||||
lis = "".join(
|
||||
f'<li><a href="{h}">{lab}</a></li>'
|
||||
for h, lab in items
|
||||
if (SITE / h).exists() or h.endswith("/") or h.startswith("sphinx")
|
||||
)
|
||||
return f"<section><h2>Catalogs</h2><ul>{lis}</ul></section>"
|
||||
|
||||
rest_pdf = f"""
|
||||
{cards("pdf")}
|
||||
<section>
|
||||
<h2>Git repositories (Forgejo)</h2>
|
||||
<p>Clone: <code>ssh://git@git.georgelambert.org:2223/marchon/<name>.git</code> (SSH port 2223). Branches <code>main</code> and <code>master</code>.</p>
|
||||
|
|
@ -291,43 +480,62 @@ def main() -> None:
|
|||
<section>
|
||||
<h2>Master module docs</h2>
|
||||
<ul>
|
||||
<li><a href="docs-master/README.md">docs-master README</a></li>
|
||||
<li><a href="docs-master/MESSAGE-FLOWS.md">MESSAGE-FLOWS.md</a></li>
|
||||
<li><a href="docs-master/modules-and-nats.md">modules-and-nats.md</a></li>
|
||||
<li><a href="docs-master/archive-nats.md">archive-nats.md</a></li>
|
||||
<li><a href="docs-master/composition.md">composition.md</a></li>
|
||||
<li><a href="docs-master/modules/">Per-module SUMMARY.md and NATS.md</a></li>
|
||||
<li><a href="user-docs/README.md">User guide (signup → tree-node lookup)</a></li>
|
||||
<li><a href="packages/verae-zapier-simulator/README.md">Simulator README</a></li>
|
||||
<li><a href="overview/README.md">System overview</a></li>
|
||||
<li><a href="overview/INDEX.md">Documentation index</a></li>
|
||||
<li><a href="docs-master/README.pdf">docs-master README</a><span class="badge">PDF</span></li>
|
||||
<li><a href="docs-master/MESSAGE-FLOWS.pdf">MESSAGE-FLOWS</a><span class="badge">PDF</span></li>
|
||||
<li><a href="docs-master/modules-and-nats.pdf">modules-and-nats</a><span class="badge">PDF</span></li>
|
||||
<li><a href="docs-master/archive-nats.pdf">archive-nats</a><span class="badge">PDF</span></li>
|
||||
<li><a href="docs-master/composition.pdf">composition</a><span class="badge">PDF</span></li>
|
||||
<li><a href="user-docs/README.pdf">User guide (signup → tree-node lookup)</a><span class="badge">PDF</span></li>
|
||||
<li><a href="packages/verae-zapier-simulator/README.pdf">Simulator README</a><span class="badge">PDF</span></li>
|
||||
<li><a href="overview/README.pdf">System overview</a><span class="badge">PDF</span></li>
|
||||
<li><a href="overview/INDEX.pdf">Documentation index</a><span class="badge">PDF</span></li>
|
||||
<li><a href="packages/verae-fleet/docs/CONSOLE.pdf">Operator console</a><span class="badge">PDF</span></li>
|
||||
<li><a href="overview/diagrams/system.svg">System diagram (SVG)</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
{extra_section(extra_pdf)}
|
||||
"""
|
||||
rest_md = f"""
|
||||
{cards("md")}
|
||||
<section>
|
||||
<h2>Catalogs</h2>
|
||||
<ul>{extra_lis}
|
||||
<li><a href="docs/modules/">All module markdown</a></li>
|
||||
<li><a href="docs/models/">All model markdown</a></li>
|
||||
<li><a href="docs/modules-pdf/">Module PDFs</a></li>
|
||||
<li><a href="docs/models-pdf/">Model PDFs</a></li>
|
||||
<h2>Git repositories (Forgejo)</h2>
|
||||
<p>Clone: <code>ssh://git@git.georgelambert.org:2223/marchon/<name>.git</code> (SSH port 2223).</p>
|
||||
<ul>{git_lis}</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Master module docs (HTML / Markdown)</h2>
|
||||
<ul>
|
||||
<li><a href="docs-master/README.html">docs-master README</a><span class="badge">MD</span></li>
|
||||
<li><a href="docs-master/MESSAGE-FLOWS.html">MESSAGE-FLOWS</a><span class="badge">MD</span></li>
|
||||
<li><a href="docs-master/modules-and-nats.html">modules-and-nats</a><span class="badge">MD</span></li>
|
||||
<li><a href="docs-master/archive-nats.md">archive-nats.md</a><span class="badge">MD</span></li>
|
||||
<li><a href="docs-master/composition.md">composition.md</a><span class="badge">MD</span></li>
|
||||
<li><a href="user-docs/README.html">User guide</a><span class="badge">MD</span></li>
|
||||
<li><a href="packages/verae-zapier-simulator/README.html">Simulator README</a><span class="badge">MD</span></li>
|
||||
<li><a href="overview/README.html">System overview</a><span class="badge">MD</span></li>
|
||||
<li><a href="overview/INDEX.html">Documentation index</a><span class="badge">MD</span></li>
|
||||
<li><a href="packages/verae-fleet/docs/CONSOLE.html">Operator console</a><span class="badge">MD</span></li>
|
||||
<li><a href="overview/diagrams/system.svg">System diagram (SVG)</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const q = document.getElementById('q');
|
||||
q.addEventListener('input', () => {{
|
||||
const v = q.value.toLowerCase();
|
||||
document.querySelectorAll('li').forEach(li => {{
|
||||
li.style.display = li.textContent.toLowerCase().includes(v) ? '' : 'none';
|
||||
}});
|
||||
}});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{extra_section(extra_md)}
|
||||
"""
|
||||
(SITE / "index.html").write_text(index, encoding="utf-8")
|
||||
print(f"site built at {SITE} ({sum(1 for _ in SITE.rglob('*') if _.is_file())} files)")
|
||||
|
||||
(SITE / "index.html").write_text(
|
||||
page_shell(now, rest_pdf, switch_to_md=True, title="Verae Time × Zapier documentation"),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(SITE / "index-md.html").write_text(
|
||||
page_shell(now, rest_md, switch_to_md=False, title="Verae Time × Zapier — Markdown indexes"),
|
||||
encoding="utf-8",
|
||||
)
|
||||
nfiles = sum(1 for _ in SITE.rglob("*") if _.is_file())
|
||||
npdf = sum(1 for _ in SITE.rglob("*.pdf") if _.is_file())
|
||||
print(f"site built at {SITE} ({nfiles} files, {npdf} PDFs)")
|
||||
if errors:
|
||||
print(f"{len(errors)} render errors:")
|
||||
for e in errors[:20]:
|
||||
print(" ", e[:300])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue