""" The minisite: a document's index of books, and every book as pages you click through. minisite/ ├── index.html every book, with what came in and what came out ├── minisite.css viewer.html └── / ├── overview.html the book's top page ├── .html one subsystem each; its boxes open the next level ├── .svg the same drawing, for the full-screen viewer └── reference.html every module with its docstring — where a leaf opens ## Inline, so the boxes are links The single-page reference (`onepage.py`) put its diagram in an ``, and an image swallows every click. Here the SVG is inlined, so a box that stands for a subsystem opens that subsystem's page, a box for a module opens its section of the reference page, and a context box — something outside this subsystem — opens its own branch. Breadcrumbs lead back up. ## Adjustable A page is drawn to fit the content column, so it reads without zooming. The size is still the reader's: `fit` scales to the column, `1:1` shows the drawing at its natural size with scrollbars, and the choice is remembered. `full screen` opens the pan-and-zoom viewer for anything still too dense. This writes HTML and nothing else. What goes on each page, the links and the notes are prepared by `book/document.py` and handed in as data — an emitter has never heard of a book's extractor, and this one has not either. """ from html import escape from pathlib import Path from ..markdown import to_html from ..paged import inline from .onepage import CONTENT_W, CSS, SIDEBAR_W, VIEWER, _fill, _ledger, _slots from .onepage import emit as reference_page CONTENT_WIDTH = CONTENT_W SIZE_SCRIPT = """""" def _note(note, cls="note") -> str: if not note: return "" text, uris = note return f'
' + to_html( text, image=lambda alt, src: f'{escape(alt)}' ) + "
" def _missing(failed: dict | None) -> str: """Books that were meant to be here and are not. Above the ones that are, because a reader who does not see this has no way to know the minisite is short.""" if not failed: return "" items = "".join(f"
  • {escape(name)} — {escape(why)}
  • " for name, why in sorted(failed.items())) return ('
    This document is incomplete. ' f"{len(failed)} book(s) could not be built, so they are not below.
      {items}
    ") def _tree(pages: list[dict], current: str | None) -> str: by_parent: dict = {} for p in pages: by_parent.setdefault(p["parent"], []).append(p) root = pages[0]["id"] if pages else None def walk(page, depth): active = ' class="active"' if page["slug"] == current else "" link = f'{escape(page["title"])}' kids = by_parent.get(page["id"], []) if not kids: return f"
  • {link}
  • " return f"
  • {link}
      " + "".join(walk(k, depth + 1) for k in kids) + "
  • " return "
      " + "".join(walk(p, 0) for p in pages if p["id"] == root) + "
    " def _page(title: str, book: dict, page: dict, svg: str | None, pages: list[dict], note, doc_title: str) -> str: b = book["book"] by_id = {p["id"]: p for p in pages} trail, cur = [], page while cur is not None: trail.append(cur) cur = by_id.get(cur["parent"]) if cur.get("parent") else None crumbs = [f'{escape(doc_title)}'] for p in reversed(trail): if p is page: crumbs.append(escape(p["title"])) else: crumbs.append(f'{escape(p["title"])}') from ...book.document import caption # noqa: F401 - kept out of module import time cap = caption(page) warn = " warn" if page.get("too_wide") else "" if svg is not None: figure = ( '
    ' '' f'full screen' "
    " f'
    {inline(svg)}
    ' ) else: figure = '

    Not drawn — Graphviz is not installed here.

    ' children = "" if page.get("children"): items = "".join( f'
  • {escape(by_id[c]["title"])}
  • ' for c in page["children"] if c in by_id ) children = f"

    Opens into

      {items}
    " return f""" {escape(page["title"])} — {escape(b.slug)} — {escape(doc_title)}
    {" › ".join(crumbs)}

    {escape(page["title"])}

    {_note(note)} {figure}

    {escape(cap)}

    {children}
    {SIZE_SCRIPT} """ def write(out_dir, style, *, title: str, books: list[dict], intro=None, end=None, failed: dict | None = None) -> list[Path]: """Write the minisite. Returns every file written, for the output manifest. `books` is a list of:: {"book": Book, "pages": [(page, svg)], "notes": {slug: (markdown, {ref: data uri})}, "intro": (markdown, {}) or None} """ import shutil out_dir = Path(out_dir) out_dir.mkdir(parents=True, exist_ok=True) values = _slots(style) written: list[Path] = [] def put(path: Path, text: str): path.parent.mkdir(parents=True, exist_ok=True) path.write_text(text) written.append(path) put(out_dir / "minisite.css", _fill(CSS.replace("__SIDEBAR__", str(SIDEBAR_W)).replace("__CONTENT__", str(CONTENT_W)), values)) put(out_dir / "viewer.html", _fill(VIEWER.replace("__TITLE__", escape(title)), values)) cards, nav = [], [] for entry in books: b = entry["book"] pages = [p for p, _ in entry["pages"]] book_dir = out_dir / b.slug for page, svg in entry["pages"]: put(book_dir / f"{page['slug']}.html", _page(title, entry, page, svg, pages, entry["notes"].get(page["slug"]), title)) if svg is not None: put(book_dir / f"{page['slug']}.svg", svg) # The reference page: the single-page `onepage` as it was, one per book, where # a module box on any page opens its own section. ref = reference_page(b.view, style, title=f"{b.slug} — reference")["index.html"] ref = ref.replace('href="minisite.css"', 'href="../minisite.css"') put(book_dir / "reference.html", ref) explore = b.out / "explore" if explore.is_dir(): for f in sorted(explore.rglob("*")): if f.is_file(): target = book_dir / "explore" / f.relative_to(explore) target.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(f, target) written.append(target) first = pages[0]["slug"] if pages else "reference" too_wide = sum(1 for p in pages if p.get("too_wide")) cards.append( f'

    ' f"{escape(b.slug)}

    " + _note(entry.get("intro")) + _ledger(b.to_dict()) + '
    " ) nav.append(f'
  • {escape(b.slug)}
  • ') put(out_dir / "index.html", f""" {escape(title)}

    {escape(title)}

    Regenerated, not edited. Each book opens with what came in and what came out.

    {_note((intro, {}) if intro else None)} {_missing(failed)}
    {"".join(cards)}
    {_note((end, {}) if end else None)}
    """) return written