Counter widget: one to three linked counters are the digits of one number, published on one message in the finest counter's unit (hours and minutes send 07:30 as 450, 07:55 + 5 min carries to 08:00); wraps or stops at the coarsest's min/max. The arithmetic is one pure module, ui/core/counter.ts, with counter.check.ts. A tile steps each counter with a press up and down and publishes once 300 ms after the last; a round face turns the selected counter on the ring (wheel, keys, a drag counted in steps), its arc where that counter stands in its turn, and a press on a counter's digits selects it. Default config is the time picker. Editor rows, widgetIssue, server type and dtype, docs

This commit is contained in:
Melvin Strobl
2026-10-16 08:58:42 +02:00
parent 4ce50b5c3a
commit 21c7961d49
16 changed files with 745 additions and 33 deletions
+9 -3
View File
@@ -4642,7 +4642,7 @@ export const WidgetDefSchema = {
},
type: {
type: 'string',
enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'embed', 'button', 'buttons', 'switch', 'slider', 'input', 'dropdown', 'color'],
enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'embed', 'button', 'buttons', 'switch', 'slider', 'input', 'dropdown', 'color', 'counter'],
title: 'Type'
},
title: {
@@ -4694,7 +4694,13 @@ The first two are a \`\`list\`\` message, the third a \`\`str\`\`, which is what
A slider may also show what it is setting: \`\`reading\`\` binds
\`\`{message, dtype, label}\`\` — a room's temperature beside its setpoint —
held to the same numbers its target is.`
held to the same numbers its target is.
A counter publishes one number to its target, of which its \`\`counters\`\`
are the digits: up to three \`\`{label, step, size, min, max}\`\`, coarsest
first, so hours and minutes publish 07:30 as 450. \`\`wrap\`\` says whether it
wraps round at its ends; \`\`docs/interface/dashboards.md\`\` has the
arithmetic.`
} as const;
export const WidgetFootprintSchema = {
@@ -4721,7 +4727,7 @@ export const WidgetFootprintSchema = {
},
type: {
type: 'string',
enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'embed', 'button', 'buttons', 'switch', 'slider', 'input', 'dropdown', 'color'],
enum: ['stat', 'gauge', 'chart', 'markdown', 'agenda', 'notification', 'bar', 'icon', 'forecast', 'clock', 'media', 'player', 'embed', 'button', 'buttons', 'switch', 'slider', 'input', 'dropdown', 'color', 'counter'],
title: 'Type'
}
},
+9 -3
View File
@@ -1522,10 +1522,16 @@ export type WebPushKey = {
* A slider may also show what it is setting: ``reading`` binds
* ``{message, dtype, label}`` — a room's temperature beside its setpoint —
* held to the same numbers its target is.
*
* A counter publishes one number to its target, of which its ``counters``
* are the digits: up to three ``{label, step, size, min, max}``, coarsest
* first, so hours and minutes publish 07:30 as 450. ``wrap`` says whether it
* wraps round at its ends; ``docs/interface/dashboards.md`` has the
* arithmetic.
*/
export type WidgetDef = {
id: string;
type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color';
type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color' | 'counter';
title?: string;
layout?: {
[key: string]: Placement;
@@ -1535,7 +1541,7 @@ export type WidgetDef = {
};
};
export type type = 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color';
export type type = 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color' | 'counter';
/**
* A widget reduced to the shape it draws: what it is, and where it sits.
@@ -1550,7 +1556,7 @@ export type WidgetFootprint = {
y?: number;
w?: number;
h?: number;
type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color';
type: 'stat' | 'gauge' | 'chart' | 'markdown' | 'agenda' | 'notification' | 'bar' | 'icon' | 'forecast' | 'clock' | 'media' | 'player' | 'embed' | 'button' | 'buttons' | 'switch' | 'slider' | 'input' | 'dropdown' | 'color' | 'counter';
};
export type WorkerInfo = {