← Files taskplaneARCHIVED FILE
taskplane/dashboard.py
4.5 KB · Oct 2, 2026 · 00:29 UTC
"""Self-contained document shell for the shared delivery dashboard."""
from __future__ import annotations
def _esc(s: str) -> str:
return str(s).replace("&", "&").replace("<", "<").replace(">", ">")
_DOC_VARS = """
:root{
--font-sans:ui-sans-serif,-apple-system,"Segoe UI",Roboto,Helvetica,sans-serif;
--font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
--surface-0:#f0efea;--surface-1:#f7f6f3;--surface-2:#ffffff;
--border:#dcd9d2;--border-strong:#b6b2aa;--border-danger:#a8331f;
--line:#b6b2aa;--changed-bg:#eceae4;--accent:#1f1e1c;
--text-primary:#1f1e1c;--text-secondary:#55524c;
--text-muted:#8b877f;--text-danger:#a8331f;--bg-danger:#f6e3df;
--danger:#a8331f;--danger-bg:#f6e3df;
--text-warning:#8a5a10;--bg-warning:#f8ecd6;
}
@media (prefers-color-scheme:dark){
:root{
--surface-0:#232220;--surface-1:#2b2a27;--surface-2:#141412;
--border:#3b3934;--border-strong:#57544e;--border-danger:#e8836d;
--line:#57544e;--changed-bg:#302e2a;--accent:#f2f1ed;
--text-primary:#f2f1ed;--text-secondary:#b9b5ad;
--text-muted:#87837b;--text-danger:#e8836d;--bg-danger:#3a231e;
--danger:#e8836d;--danger-bg:#3a231e;
--text-warning:#e0b062;--bg-warning:#3a2f1a;
}
}
html,body{margin:0;background:var(--surface-2);color:var(--text-primary);
font-family:var(--font-sans);-webkit-font-smoothing:antialiased;}
.wrap{max-width:940px;margin:0 auto;padding:26px 22px 56px;}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;
clip:rect(0,0,0,0);}
.tp-sec{border-top:1px solid var(--border);margin-top:28px;padding-top:14px;}
.tp-kicker{font-family:var(--font-mono);font-size:10px;letter-spacing:1.6px;
text-transform:uppercase;color:var(--text-muted);margin:0 0 4px;}
.tp-lede{font-size:13px;color:var(--text-secondary);line-height:1.65;margin:2px 0 0;}
#tp-dashboard-freshness-status{position:sticky;top:0;z-index:10;
padding:9px 14px;border-bottom:1px solid var(--border-strong);
background:var(--surface-1);color:var(--text-secondary);
font:600 12px/1.4 var(--font-mono);overflow-wrap:anywhere;}
#tp-dashboard-freshness-status[data-status="stale"],
#tp-dashboard-freshness-status[data-status="unverified"]{
color:var(--text-warning);background:var(--bg-warning);}
#dashboard-snapshot{box-sizing:border-box;max-width:940px;margin:0 auto;
padding:26px 22px 56px;overflow:hidden;}
.tp-binding{display:grid;grid-template-columns:minmax(9rem,auto) minmax(0,1fr);
gap:6px 14px;margin:10px 0 0;}
.tp-binding dt{font:600 10.5px/1.4 var(--font-mono);color:var(--text-muted);
text-transform:uppercase;letter-spacing:.7px;}
.tp-binding dd{margin:0;font:12px/1.5 var(--font-mono);
overflow-wrap:anywhere;word-break:break-word;}
.tp-phase-graph{box-sizing:border-box;max-width:100%;overflow-x:auto;
overflow-y:hidden;overscroll-behavior-inline:contain;padding:10px 0;}
.tp-phase-graph svg{display:block;width:100%;height:auto;min-height:104px;
overflow:visible;}
.tp-phase-graph text{paint-order:stroke;stroke:var(--surface-1);
stroke-width:.35px;}
@media (max-width:767px){
#dashboard-snapshot{padding:18px 14px 40px;}
.tp-binding{grid-template-columns:1fr;gap:2px;}
.tp-binding dd{margin-bottom:7px;}
.tp-phase-graph svg{width:max(100%,680px);min-width:680px;min-height:112px;}
}
hr.pg{border:0;border-top:1px solid var(--border);margin:26px 0 0;}
"""
def standalone_document(fragments: list[str], title: str = "Taskplane delivery") -> str:
"""The paged fragments as ONE self-contained HTML document.
Every fragment this module emits is written for an inline widget host
that already defines the palette. Saved to a file it renders as unstyled
text — so a review whose host could not show widgets inline had no
legible artifact at all, and the reviewer had to hand-wrap the pages
before anything could be read. The fragments are embedded VERBATIM; only
the document shell around them is new.
"""
body = '<hr class="pg">'.join(fragments or [])
return (
'<!DOCTYPE html>\n<html lang="en">\n<head>\n'
'<meta charset="utf-8">\n'
'<meta name="viewport" content="width=device-width,'
'initial-scale=1">\n<title>' + _esc(title) + "</title>\n"
"<style>" + _DOC_VARS + "</style>\n</head>\n<body>\n"
'<div class="wrap">\n' + body + "\n</div>\n</body>\n</html>\n"
)
def report_widget(workspace: str) -> str:
from taskplane import flow_dashboard
return flow_dashboard.render(workspace)
SHA-256: b56ef5f04d33ef31b78f7541785c02848d731bd0a06e154a2b1eeaddcbd35ffb