Render a choice's whole list item inside its pick box

This commit is contained in:
Ian Gulliver
2026-10-15 11:46:24 -07:00
parent 0000db1f86
commit d3d9c804e9
5 changed files with 25 additions and 6 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ New inbox items are sent as web push notifications to every browser a user has t
The **Settings** modal (the navbar's **Settings** button) turns notifications on or off for the current browser (asking for permission on the way) and edits the preferences. Opening it re-registers the browser's existing subscription, which restores one byre deleted as expired.
In the UI each card is answered on its own; there is no batch submission. A pick-one question's choices are clickable blocks, and clicking one sends that answer at once. A pick-any question's choices are checkboxes, sent with the Submit button at the bottom of the card. Below the choices, an "Other…" block in the same style opens the only text field. A card has at most one Submit button: on a pick-any question it sends the checked choices with the Other text alongside (one `option` response), or the Other text alone as `other` when nothing is checked. A report has only an OK button, which dismisses it at once; an error has a "Reply…" block (`other`) and a Dismiss button. The Other and Reply text boxes send with the Submit button under them or on Enter (Shift+Enter for a newline), like the message box, and fold back into their block when left empty. The list updates in place: a card stays attached while its item is unchanged, so task and inbox updates from other agents don't pull focus out of a text box being typed in.
In the UI each card is answered on its own; there is no batch submission. A pick-one question's choices are clickable blocks, and clicking one sends that answer at once. A choice's block (or a pick-any choice's checkbox label) holds the whole list item: its first line, which is the choice's text, and everything under it, such as an example's paragraph or code block. A pick-any question's choices are checkboxes, sent with the Submit button at the bottom of the card. Below the choices, an "Other…" block in the same style opens the only text field. A card has at most one Submit button: on a pick-any question it sends the checked choices with the Other text alongside (one `option` response), or the Other text alone as `other` when nothing is checked. A report has only an OK button, which dismisses it at once; an error has a "Reply…" block (`other`) and a Dismiss button. The Other and Reply text boxes send with the Submit button under them or on Enter (Shift+Enter for a newline), like the message box, and fold back into their block when left empty. The list updates in place: a card stays attached while its item is unchanged, so task and inbox updates from other agents don't pull focus out of a text box being typed in.
There is no snoozing. The `snoozed_until` and `snooze_until` columns are still in the schema, always empty, so builds from older branches keep working against the same database; nothing reads them.
+9 -2
View File
@@ -191,10 +191,14 @@ function item(body, opts) {
li.className = "choice";
li.append(picker);
}
const target = picker ?? li;
const first = picker ? [] : [body[0]];
const rest = body.slice(1);
if (rest.every((l) => !startsBlockLine(l)) && !rest.includes("")) {
li.append(...joinLines([...first, ...rest].map((l) => l.trim()), opts));
if (picker && rest.length > 0) {
target.append(h("br"));
}
target.append(...joinLines([...first, ...rest].map((l) => l.trim()), opts));
return li;
}
const head = first;
@@ -203,7 +207,10 @@ function item(body, opts) {
head.push(body[k].trim());
k++;
}
li.append(...joinLines(head, opts), ...blocks(body.slice(k), opts));
if (picker && head.length > 0) {
target.append(h("br"));
}
target.append(...joinLines(head, opts), ...blocks(body.slice(k), opts));
return li;
}
function startsBlockLine(line) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+9 -2
View File
@@ -220,10 +220,14 @@ function item(body: string[], opts: Options): HTMLElement {
li.className = "choice";
li.append(picker);
}
const target = picker ?? li;
const first = picker ? [] : [body[0]!];
const rest = body.slice(1);
if (rest.every((l) => !startsBlockLine(l)) && !rest.includes("")) {
li.append(...joinLines([...first, ...rest].map((l) => l.trim()), opts));
if (picker && rest.length > 0) {
target.append(h("br"));
}
target.append(...joinLines([...first, ...rest].map((l) => l.trim()), opts));
return li;
}
const head: string[] = first;
@@ -232,7 +236,10 @@ function item(body: string[], opts: Options): HTMLElement {
head.push(body[k]!.trim());
k++;
}
li.append(...joinLines(head, opts), ...blocks(body.slice(k), opts));
if (picker && head.length > 0) {
target.append(h("br"));
}
target.append(...joinLines(head, opts), ...blocks(body.slice(k), opts));
return li;
}
+5
View File
@@ -1369,6 +1369,11 @@ pre.file-text .line::before {
cursor: pointer;
}
.pick > :last-child,
.option > :last-child {
margin-bottom: 0;
}
.pick:hover,
.pick:focus-visible {
border-color: var(--accent);