generated from coulomb/repo-seed
feat(dashboard): shift+click trigger + Improvements section in Todo
improvement-modal.js: - Replace contextmenu handler with click+shiftKey check — browser context menu is no longer intercepted - Add keydown/keyup/blur listeners: holding Shift applies .impr-shift-mode to <body>, switching cursor to crosshair across the entire page as a visual affordance - Update hint text to "Ctrl + Enter to submit · Escape to cancel" todo.md: - New "Improvements" section shows open dashboard-improvement TD items with a "review →" link to the UI Feedback page - KPI sidebar row added for open improvement count (indigo when > 0) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,14 +11,15 @@ const THIS_REPO = "the-custodian";
|
||||
// Live poll: tasks + workstreams + topics + contributions
|
||||
const todoState = (async function*() {
|
||||
while (true) {
|
||||
let tasks = [], contribs = [], wsMap = {}, ok = false;
|
||||
let tasks = [], contribs = [], improvements = [], wsMap = {}, ok = false;
|
||||
try {
|
||||
const [rt, rw, rto, rr, rc] = await Promise.all([
|
||||
const [rt, rw, rto, rr, rc, ri] = await Promise.all([
|
||||
fetch(`${API}/tasks/?limit=500`),
|
||||
fetch(`${API}/workstreams/`),
|
||||
fetch(`${API}/topics/`),
|
||||
fetch(`${API}/repos/`),
|
||||
fetch(`${API}/contributions/`),
|
||||
fetch(`${API}/technical-debt/?debt_type=dashboard-improvement`),
|
||||
]);
|
||||
ok = rt.ok && rw.ok && rto.ok && rr.ok && rc.ok;
|
||||
if (ok) {
|
||||
@@ -37,19 +38,21 @@ const todoState = (async function*() {
|
||||
domain: wsMap[t.workstream_id]?.domain ?? "unknown",
|
||||
}));
|
||||
contribs = contribList;
|
||||
improvements = ri.ok ? (await ri.json()).filter(t => t.debt_type === "dashboard-improvement" && t.status === "open") : [];
|
||||
}
|
||||
} catch {}
|
||||
yield {tasks, contribs, ok, ts: new Date()};
|
||||
yield {tasks, contribs, improvements, ok, ts: new Date()};
|
||||
await new Promise(res => setTimeout(res, POLL));
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
```js
|
||||
const tasks = todoState.tasks ?? [];
|
||||
const contribs = todoState.contribs ?? [];
|
||||
const _ok = todoState.ok ?? false;
|
||||
const _ts = todoState.ts;
|
||||
const tasks = todoState.tasks ?? [];
|
||||
const contribs = todoState.contribs ?? [];
|
||||
const improvements = todoState.improvements ?? [];
|
||||
const _ok = todoState.ok ?? false;
|
||||
const _ts = todoState.ts;
|
||||
```
|
||||
|
||||
```js
|
||||
@@ -102,6 +105,12 @@ const _kpiBox = html`<div class="kpi-infobox">
|
||||
<div class="kpi-row-value">${thirdParty.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="kpi-row">
|
||||
<span class="kpi-row-label">improvements (open)</span>
|
||||
<div class="kpi-row-right">
|
||||
<div class="kpi-row-value" style="color:${improvements.length > 0 ? '#6366f1' : 'inherit'}">${improvements.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
// ── Live indicator ────────────────────────────────────────────────────────────
|
||||
@@ -198,6 +207,31 @@ if (thirdParty.length === 0) {
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Improvements
|
||||
|
||||
Dashboard suggestions submitted via Shift+click. Review and action on the
|
||||
[UI Feedback](/ui-feedback) page; open items shown here for visibility.
|
||||
|
||||
```js
|
||||
if (improvements.length === 0) {
|
||||
display(html`<p class="dim">No open improvement suggestions. Shift+click any widget to submit one.</p>`);
|
||||
} else {
|
||||
display(html`<div class="task-list">${improvements.map(t => html`
|
||||
<div class="task-item impr-item">
|
||||
<div class="task-item-header">
|
||||
<span class="task-badge" style="background:#ede9fe;color:#4c1d95">improvement</span>
|
||||
<span class="task-context">${t.location ?? ""}</span>
|
||||
<a class="impr-review-link" href="/ui-feedback">review →</a>
|
||||
</div>
|
||||
<div class="task-title">${t.title.replace(/^UI:\s*/, "")}</div>
|
||||
${t.description ? html`<div class="impr-desc">${t.description.slice(0, 200)}${t.description.length > 200 ? " …" : ""}</div>` : ""}
|
||||
</div>
|
||||
`)}</div>`);
|
||||
}
|
||||
```
|
||||
|
||||
<style>
|
||||
/* ── Live indicator ───────────────────────────────────────────────────────── */
|
||||
.live-indicator { font-size: 0.8rem; color: gray; position: relative; padding: 0.55rem 1.8rem 0.55rem 0.7rem; margin-bottom: 0.75rem; }
|
||||
@@ -231,4 +265,8 @@ if (thirdParty.length === 0) {
|
||||
.task-title { font-weight: 600; font-size: 0.95rem; margin-bottom: 0.15rem; }
|
||||
.task-blocking-reason { font-size: 0.8rem; color: #b45309; background: #fef3c7; border-radius: 4px; padding: 0.2rem 0.5rem; margin-top: 0.25rem; }
|
||||
.dim { color: gray; font-style: italic; }
|
||||
.task-item.impr-item { border-left-color: #6366f1; }
|
||||
.impr-desc { font-size: 0.8rem; color: var(--theme-foreground-muted); margin-top: 0.2rem; line-height: 1.45; }
|
||||
.impr-review-link { margin-left: auto; font-size: 0.75rem; color: #6366f1; text-decoration: none; }
|
||||
.impr-review-link:hover { text-decoration: underline; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user