"""Writing HTML pages that use the beadnet components.""" from __future__ import annotations import html import os import shutil from typing import Optional, Sequence, Union from .store import Store STATIC = os.path.join(os.path.dirname(__file__), "static") PAGE_CSS = """ body { margin: 0; background: var(--bn-bg, #fff); color: var(--bn-fg, #1d1d1b); font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; } main { max-width: 1100px; margin: 0 auto; padding: 16px; } h1 { font-size: 22px; margin: 8px 0 4px; } h2 { font-size: 17px; margin: 28px 0 4px; } p.lead { color: var(--bn-muted, #666); margin: 0 0 12px; } """ def run_block_html(src: str, kind: str = "run", heading: Optional[str] = None) -> str: """The default set of components for one run (or saved model) at src.""" parts = [] if heading: parts.append(f"

{html.escape(heading)}

") parts.append(f'') if kind == "run": parts += [" ", " ", " ", " ", " "] else: parts += [" ", " ", " "] parts.append("") return "\n".join(parts) def page_html(body: str, title: str = "beadnet", script: str = "beadnet/beadnet.js", lead: str = "") -> str: lead_html = f'

{html.escape(lead)}

' if lead else "" return f""" {html.escape(title)}

{html.escape(title)}

{lead_html} {body}
""" def write_page(path: str, runs: Union[str, Sequence[str]], title: str = "beadnet", lead: str = "", copy_js: bool = False) -> str: """Write an HTML page showing one or more runs (or saved models) with the default components. Paths in the page are relative to the page's directory. The script is referenced as beadnet/beadnet.js next to the page: `beadnet serve` provides it, or pass copy_js=True to copy it there for any static server. """ if isinstance(runs, str): runs = [runs] d = os.path.dirname(os.path.abspath(path)) os.makedirs(d, exist_ok=True) blocks = [] for r in runs: st = Store(r) a = st.attrs().get("beadnet", {}) kind = "run" if a.get("kind") == "run" else "model" name = a.get("model", {}).get("name") or os.path.basename(os.path.normpath(r)) rel = os.path.relpath(os.path.abspath(r), d).replace(os.sep, "/") blocks.append(run_block_html(rel, kind, heading=name if len(runs) > 1 else None)) with open(path, "w") as f: f.write(page_html("\n\n".join(blocks), title=title, lead=lead)) if copy_js: copy_static(d) return path def copy_static(directory: str) -> str: """Copy the components (beadnet/beadnet.js and the viewer) into directory/beadnet/.""" dst = os.path.join(directory, "beadnet") os.makedirs(dst, exist_ok=True) for name in os.listdir(STATIC): shutil.copy2(os.path.join(STATIC, name), os.path.join(dst, name)) return dst