dashboard: move live indicator to TOC sidebar on all pages; add live-data docs

- All four pages (index, workstreams, decisions, progress) now inject the
  live indicator into #observablehq-toc via injectTocTop("live-indicator", el)
  Left-aligned (no text-align: right), position:relative + padding-right for
  the ? button affordance

- decisions.md: splits the former combined "decisions-sidebar" widget into two
  separate injectTocTop calls — KPI box first (ends lower), live indicator
  second (ends at top); both now have their own stable ids

- withDocHelp(_liveEl, "/docs/live-data") wires the ? button on every page

- src/docs/live-data.md: new documentation page explaining poll interval (15s),
  indicator colour semantics, offline recovery, and which endpoints each page hits

- Removes the .live-bar CSS class from all pages; replaces with .live-indicator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 16:18:09 +01:00
parent 902aafcfb1
commit 816f1e25f1
5 changed files with 101 additions and 16 deletions

View File

@@ -47,12 +47,17 @@ const _ts = wsState.ts;
# Workstreams
```js
display(html`<div class="live-bar">
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
const _liveEl = html`<div class="live-indicator">
<span style="color:${_ok ? 'var(--theme-foreground-focus)' : 'red'}">●</span>
${_ok
? `Live · updated ${_ts?.toLocaleTimeString()}`
: `<span style="color:red">Offline — run: <code>make api</code></span>`}
</div>`);
: html`<span style="color:red">Offline — run: <code>make api</code></span>`}
</div>`;
withDocHelp(_liveEl, "/docs/live-data");
injectTocTop("live-indicator", _liveEl);
```
```js
@@ -145,7 +150,7 @@ if (wsWithDeps.length === 0) {
```
<style>
.live-bar { font-size: 0.8rem; color: gray; text-align: right; margin-bottom: 0.5rem; }
.live-indicator { font-size: 0.8rem; color: gray; margin-bottom: 0.75rem; position: relative; padding-right: 1.6rem; }
.dim { color: gray; font-style: italic; }
.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; }
.filter-owner { display: flex; align-items: center; }