Show today's tasks as seed chips on the planning screen

The planning view renders Marvin's today list as clickable chips;
clicking one fills the intent field, feeding the existing coach flow.
idle/error/empty render nothing, pending shows a quiet loading line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 22:09:38 -04:00
parent e832a2da85
commit 8b5121c69d
2 changed files with 33 additions and 0 deletions
+9
View File
@@ -107,3 +107,12 @@ input:focus { outline: 0; border-color: var(--accent); }
font-variant-numeric: tabular-nums; color: var(--ink-dim); font-variant-numeric: tabular-nums; color: var(--ink-dim);
} }
.summary-row span:last-child { color: var(--ink); font-family: ui-monospace, monospace; } .summary-row span:last-child { color: var(--ink); font-family: ui-monospace, monospace; }
/* Planning: today's tasks as clickable seed chips */
.tasklist { display: flex; flex-wrap: wrap; gap: 8px; }
.task-chip {
padding: 6px 10px; border: 1px solid var(--line); border-radius: 999px;
background: var(--bg); color: var(--ink); font: inherit; font-size: 13px;
cursor: pointer; text-align: left;
}
.task-chip:hover { border-color: var(--accent); color: var(--accent); }
+24
View File
@@ -136,11 +136,33 @@ function updatePlanningCoach(coach) {
} }
} }
// updatePlanningTasks renders today's Marvin tasks as clickable seed chips.
// Clicking a chip fills the intent field; the coach pipeline is unchanged.
// idle/error/empty render nothing; pending shows a quiet loading line.
function updatePlanningTasks(tasks) {
const el = document.getElementById('tasksBand');
if (!el) return;
if (!tasks || tasks.status === 'idle' || tasks.status === 'error') { el.innerHTML = ''; return; }
if (tasks.status === 'pending') { el.innerHTML = `<div class="meta">loading tasks…</div>`; return; }
const list = tasks.tasks || [];
if (!list.length) { el.innerHTML = ''; return; }
const chips = list.map((t, i) =>
`<button type="button" class="task-chip" data-i="${i}">${t.title}</button>`).join('');
el.innerHTML = `<label>Today</label><div class="tasklist">${chips}</div>`;
el.querySelectorAll('.task-chip').forEach(btn => {
btn.onclick = () => {
const intent = document.getElementById('intent');
if (intent) { intent.value = list[+btn.dataset.i].title; intent.focus(); }
};
});
}
function render(state) { function render(state) {
setStateAttr(state); setStateAttr(state);
const rs = state.runtime_state; const rs = state.runtime_state;
if (rs === 'planning' && renderedState === 'planning') { if (rs === 'planning' && renderedState === 'planning') {
updatePlanningCoach(state.coach); updatePlanningCoach(state.coach);
updatePlanningTasks(state.tasks);
return; return;
} }
if (rs === 'active' && renderedState === 'active') { if (rs === 'active' && renderedState === 'active') {
@@ -166,6 +188,7 @@ function render(state) {
<button id="sharpen" type="button" class="btn btn-ghost">Sharpen</button> <button id="sharpen" type="button" class="btn btn-ghost">Sharpen</button>
<div id="coachStatus" class="meta"></div> <div id="coachStatus" class="meta"></div>
</div> </div>
<div class="band" id="tasksBand"></div>
<div class="band"> <div class="band">
<label>Next action</label><input id="na" placeholder="What exactly will you do?"> <label>Next action</label><input id="na" placeholder="What exactly will you do?">
<label>Success condition</label><input id="sc" placeholder="How do you know it's done?"> <label>Success condition</label><input id="sc" placeholder="How do you know it's done?">
@@ -190,6 +213,7 @@ function render(state) {
if (intent) post('/coach', { intent }); if (intent) post('/coach', { intent });
}; };
updatePlanningCoach(state.coach); updatePlanningCoach(state.coach);
updatePlanningTasks(state.tasks);
} else if (rs === 'active') { } else if (rs === 'active') {
const c = state.commitment || {}; const c = state.commitment || {};