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:
@@ -261,6 +261,59 @@ h('#comp', { component: MyPage, key: '/dashboard' }, [])
|
||||
|
||||
**Children flattening:** `null`, `undefined`, and `false` children are filtered out. String and number primitives are automatically converted to text VNodes.
|
||||
|
||||
### HTM (Tagged HTML Templates)
|
||||
|
||||
Hoover ships with **htm** for JSX-like template syntax using tagged template literals. Import and use:
|
||||
|
||||
```javascript
|
||||
import { html, Badge, ConfirmDelete } from '/static/hoover/index.js';
|
||||
|
||||
// Instead of:
|
||||
h('div', { class: 'card' },
|
||||
h('h3', { style: 'color:red' }, 'Title'),
|
||||
h('button', { 'on:click': handler }, 'Click')
|
||||
)
|
||||
|
||||
// Write:
|
||||
html`<div class="card">
|
||||
<h3 style="color:red">Title</h3>
|
||||
<button onClick=${handler}>Click</button>
|
||||
</div>`
|
||||
```
|
||||
|
||||
**Event naming:** Use camelCase `onClick=${fn}` — the adapter translates events to Hoover's `on:click` convention. Any attribute starting with `on` followed by a capital letter (e.g., `onSubmit`, `onChange`) is converted.
|
||||
|
||||
**Component syntax:** Use `<${Component}>` syntax for inline components:
|
||||
|
||||
```javascript
|
||||
html`<${Badge} text=${val} variant="info" />`
|
||||
html`<${ConfirmDelete} url=${url} message=${msg} success="Deleted" refresh="firewall" />`
|
||||
```
|
||||
|
||||
**Interpolation:** Values are interpolated with `${...}`. Use `esc()` for user-controlled text:
|
||||
|
||||
```javascript
|
||||
html`<tr key=${item.id}>
|
||||
<td>${esc(item.name)}</td>
|
||||
<td>${item.value}</td>
|
||||
</tr>`
|
||||
```
|
||||
|
||||
**Spread attributes:** Use `...${props}` to spread an object as props:
|
||||
|
||||
```javascript
|
||||
html`<${Badge} ...${badgeProps} />`
|
||||
```
|
||||
|
||||
**Boolean attributes:** Use `html`<${Badge} readonly />`` for boolean attributes.
|
||||
|
||||
**Coexistence with `h()`:** Both `h` and `html` are exported from the barrel. Use whichever is clearer for the given context. Simple elements are often shorter with `h()`, while complex nested structures benefit from `html`.
|
||||
|
||||
**Limitations:**
|
||||
- No `<Badge>...</Badge>` closing syntax — must use self-closing `<${Badge} ... />` or full `<${Badge} ... ></${Badge}>` syntax
|
||||
- No control flow (`if/for`) in templates — use JavaScript conditionals and `.map()` before interpolation
|
||||
- `esc()` is still required for user-controlled text to prevent XSS
|
||||
|
||||
### Props
|
||||
|
||||
| Prop | Behavior |
|
||||
|
||||
Reference in New Issue
Block a user