"""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