M1: render evidence (current window, buckets, switches) in UI

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 12:55:43 -04:00
parent b5c3f883b7
commit f286609ec0
+25
View File
@@ -21,6 +21,13 @@
.meta { color: #9aa0b4; } .meta { color: #9aa0b4; }
.pill { display: inline-block; font-size: 12px; letter-spacing: .15em; text-transform: uppercase; .pill { display: inline-block; font-size: 12px; letter-spacing: .15em; text-transform: uppercase;
color: #7a8095; border: 1px solid #272b38; border-radius: 999px; padding: 3px 10px; } color: #7a8095; border: 1px solid #272b38; border-radius: 999px; padding: 3px 10px; }
.ev { margin-top: 18px; border-top: 1px solid #272b38; padding-top: 14px; }
.ev .now { font-size: 14px; color: #cdd2e0; }
.ev .health-ok { color: #5fd08a; }
.ev .health-bad { color: #e0b15f; }
.buckets { list-style: none; padding: 0; margin: 10px 0 0; font-size: 13px; color: #9aa0b4; }
.buckets li { display: flex; justify-content: space-between; padding: 2px 0; font-variant-numeric: tabular-nums; }
.switches { font-size: 13px; color: #7a8095; margin-top: 8px; }
</style> </style>
</head> </head>
<body> <body>
@@ -47,6 +54,22 @@ function fmt(secs) {
return `${m}:${s}`; return `${m}:${s}`;
} }
function evidenceBlock(ev) {
if (!ev) return '';
const health = ev.available
? `<span class="health-ok">tracking</span>`
: `<span class="health-bad">evidence unavailable: ${ev.reason || 'unknown'}</span>`;
const now = ev.current && (ev.current.class || ev.current.title)
? `${ev.current.class || '?'} · ${ev.current.title || ''}` : '—';
const rows = (ev.buckets || []).map(b =>
`<li><span>${(b.class || '?')} · ${b.title || ''}</span><span>${fmt(b.seconds)}</span></li>`).join('');
return `<div class="ev">
<div class="now">Now: ${now} &nbsp; ${health}</div>
<ul class="buckets">${rows}</ul>
<div class="switches">Context switches: ${ev.switch_count || 0}</div>
</div>`;
}
function render(state) { function render(state) {
if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null; } if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null; }
const rs = state.runtime_state; const rs = state.runtime_state;
@@ -76,6 +99,7 @@ function render(state) {
<div class="timer" id="t">--:--</div> <div class="timer" id="t">--:--</div>
<div class="action">${c.next_action || ''}</div> <div class="action">${c.next_action || ''}</div>
<p class="meta">Done when: ${c.success_condition || ''}</p> <p class="meta">Done when: ${c.success_condition || ''}</p>
${evidenceBlock(state.evidence)}
<button id="done">Complete</button>`; <button id="done">Complete</button>`;
document.getElementById('done').onclick = () => post('/complete'); document.getElementById('done').onclick = () => post('/complete');
const t = document.getElementById('t'); const t = document.getElementById('t');
@@ -87,6 +111,7 @@ function render(state) {
view.innerHTML = `<span class="pill">Review</span> view.innerHTML = `<span class="pill">Review</span>
<p class="action">Session ended</p> <p class="action">Session ended</p>
<p class="meta">${c.next_action || ''}</p> <p class="meta">${c.next_action || ''}</p>
${evidenceBlock(state.evidence)}
<button id="end">End</button>`; <button id="end">End</button>`;
document.getElementById('end').onclick = () => post('/end'); document.getElementById('end').onclick = () => post('/end');
} else { } else {