Add state management, WebSocket polling, html.js templating, and refactor pages
- lib/state.py: per-subsystem collectors with versioned state store - daemon/server.py: state refresh on request, batch routing updates - webui/static/hoover/html.js: new html tag template helper via htm.js - webui/static/hoover/websocket.js: real-time state change notifications - webui/static/hoover/vdom.js: VDOM improvements for keyed diff - All frontend pages refactored to use html templates - Add tests for state management and polling - Update docs and AGENTS.md
This commit is contained in:
@@ -21,6 +21,29 @@ export const _unmountFn = { fn: null };
|
||||
export function setMountFn(fn) { _mountFn.fn = fn; }
|
||||
export function setUnmountFn(fn) { _unmountFn.fn = fn; }
|
||||
|
||||
/**
|
||||
* htm event adapter: translates camelCase events (onClick) to Hoover's on:click.
|
||||
*/
|
||||
export function htmAdapter(tag, props, ...children) {
|
||||
if (tag === '#text' || tag === '#comp' || typeof tag === 'function') {
|
||||
return h(tag, props, ...children);
|
||||
}
|
||||
|
||||
if (props) {
|
||||
const normalized = {};
|
||||
for (const [key, val] of Object.entries(props)) {
|
||||
if (key.startsWith('on') && key.length > 2 && key[2] >= 'A' && key[2] <= 'Z') {
|
||||
normalized['on:' + key.slice(2).toLowerCase()] = val;
|
||||
} else {
|
||||
normalized[key] = val;
|
||||
}
|
||||
}
|
||||
props = normalized;
|
||||
}
|
||||
|
||||
return h(tag, props, ...children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a VNode. Three forms:
|
||||
* h('div', { class: 'x' }, h('span', null, 'hi')) — element
|
||||
|
||||
Reference in New Issue
Block a user