Timers: present each timer and LTC in the Add-tile picker

Adopt main's new multi-tile contract: the module's server exports
tiles() (answered from the poller's held state, never a fresh upstream
request) listing All timers, one entry per discovered timer, and LTC
timecode. The client branches on moduleApi.variant — solo tiles render
exactly one card with no selection menu, and a solo timer that vanishes
from ProPresenter shows a labeled "Not in ProPresenter" card instead of
erroring (visible even in the compact layout). pp-timers-mock gains
--drop=<uuid,...> to simulate a timer deleted in ProPresenter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-08-31 14:34:59 -04:00
co-authored by Claude Fable 5
parent a8a382c171
commit 12245cba93
5 changed files with 90 additions and 8 deletions
+29
View File
@@ -314,6 +314,35 @@ module.exports = {
};
},
/**
* The Add-tile picker's entries: one per discovered timer, plus "All
* timers" and the LTC card (moduleApi.variant carries the entry id —
* 'all', 'timer:<uuid>' or 'ltc'). Answered from the poller's latest
* state, never from a fresh upstream request — the picker must stay
* instant, and a dead ProPresenter must not stall it.
*/
tiles() {
const state = current ? current.getLatest() : null;
if (!state || !state.enabled) return []; // unconfigured → classic single entry
const TYPE_LABEL = {
countdown: 'Countdown timer',
countdown_to_time: 'Countdown to a time of day',
elapsed: 'Elapsed timer',
unknown: 'Timer',
};
const oneCard = { defaultSize: { w: 3, h: 2 }, minSize: { w: 2, h: 1 } };
return [
{ id: 'all', name: 'All timers', description: 'Every timer and the LTC timecode, selectable per tile' },
...state.timers.map((t) => ({
id: `timer:${t.uuid}`,
name: t.name,
description: TYPE_LABEL[t.type] || 'Timer',
...oneCard,
})),
{ id: 'ltc', name: 'LTC timecode', description: 'Incoming timecode (HH:MM:SS:FF)', ...oneCard },
];
},
routes() {
return {
'GET /state': (req, res) => {