aboutsummaryrefslogtreecommitdiffstats
path: root/src/web.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 11:33:31 +0100
committereunhhu <[email protected]>2026-09-26 11:33:31 +0100
commit0d5effd6afe8808296a01db102ca4c247cdcd1af (patch)
tree4f1113880606fb6dda861fd846f8ff40d5c17a63 /src/web.c
parent3b3e4a221fa47d0109c6ab99be65b5ba48bae254 (diff)
downloadvega-0d5effd6afe8808296a01db102ca4c247cdcd1af.tar.gz
vega-0d5effd6afe8808296a01db102ca4c247cdcd1af.zip
Show filtered lists and their shared focus
A list may now be filtered (each t in tasks where !t.done), and several filtered lists over one list share one focus: the focus view names an item, so Vega asks Pure which row shows it and highlights it only in the list that holds it; the other lists have no focus (null in the web surface's JSON, and the spoken surface names the item where it is). A click or point on a row points at the item that row shows, and the wheel on a list without the focus focuses the row under it. Pure's rows now take a mutable app. examples/today.aup shows what is open and what is done; its CLI output matches a model over random adds, moves, toggles and points into either list, and the web surface leaves the other list without a focus.
Diffstat (limited to 'src/web.c')
-rw-r--r--src/web.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/src/web.c b/src/web.c
index 78da0ab..149e888 100644
--- a/src/web.c
+++ b/src/web.c
@@ -123,8 +123,10 @@ static void screen_json(Buffer *b, PureApp *app, const VegaScreen *screen, size_
puts_(b, comma ? ",{\"part\":" : "{\"part\":");
putf(b, "%u,\"name\":", i);
json_name(b, m->view_names[part->view]);
- putf(b, ",\"kind\":\"%s\",\"rows\":%zu,\"focus\":%zu,\"first\":%zu,\"pointable\":%s,\"columns\":[",
- part->kind == VEGA_LIST ? "list" : "table", rows, rows ? focus : 0, first, part->pointer >= 0 ? "true" : "false");
+ putf(b, ",\"kind\":\"%s\",\"rows\":%zu,\"focus\":", part->kind == VEGA_LIST ? "list" : "table", rows);
+ if (focus < rows) putf(b, "%zu", focus);
+ else puts_(b, "null");
+ putf(b, ",\"first\":%zu,\"pointable\":%s,\"columns\":[", first, part->pointer >= 0 ? "true" : "false");
if (part->kind == VEGA_TABLE)
for (unsigned c = 0; c < part->column_count; ++c) {
if (c) puts_(b, ",");
@@ -224,12 +226,12 @@ static const char *const page_parts[] = {
"el('span',{className:'label',textContent:it.label?\?''}),it.detail?el('span',{className:'detail',textContent:it.detail}):null,"
"it.badge?el('span',{className:'badge',textContent:it.badge}):null);item.setAttribute('role','option');"
"item.setAttribute('aria-selected',it.row===p.focus);list.append(item)}"
-"list.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,p.focus+Math.sign(e.deltaY))))};"
+"list.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,(p.focus?\?-1)+Math.sign(e.deltaY))))};"
"return el('section',{},head,list)}"
"const table=el('table',{},el('thead',{},el('tr',{},...p.columns.map(c=>el('th',{textContent:c})))));"
"const body=el('tbody');for(const it of p.items){const tr=el('tr',{className:it.tone,onclick:()=>pick(it.row)},"
"...it.cells.map(c=>el('td',{textContent:c?\?'-'})));tr.setAttribute('aria-selected',it.row===p.focus);body.append(tr)}"
-"table.append(body);table.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,p.focus+Math.sign(e.deltaY))))};"
+"table.append(body);table.onwheel=e=>{e.preventDefault();pick(Math.max(0,Math.min(p.rows-1,(p.focus?\?-1)+Math.sign(e.deltaY))))};"
"return el('section',{},head,table)}));"
"$('prompt').hidden=!s.prompt;if(s.prompt)$('entry').placeholder=s.prompt;"
"const symbols={ArrowUp:'\u2191',ArrowDown:'\u2193',ArrowLeft:'\u2190',ArrowRight:'\u2192',Backspace:'Bksp',"