Rules for a clean interface, and the modules brought to them
Seven rules join the four in the module guide, as rules 5 to 11: no
explanatory text in a tile's gear and no label over three words; server-side
settings in configSchema only; a tile setting changes that tile alone;
hide-toggles ungrouped when there are four or fewer and in a folded "Show"
group when there are five or more; title-bar controls are icons with
tooltips, never names; anything needing words belongs in the gear; and one
control per action, either place but not both.
Two passages said the opposite and now say the same thing — "keep labels
short and put the explanation there" is scoped to configSchema, and "icon
buttons, short labels" becomes icons with no labels at all. CLAUDE.md
carries the summary.
Then the modules. Nothing here changes a setting key or a default, so saved
layouts, named layouts and every tile already on a wall keep working; group
names, labels, help and fold state are presentation and are not stored.
- pco-plan: sixteen labels cut to three words or fewer ("Tint items by type
(song / media / other)" is now "Tint by type"), "Show / hide" renamed
"Show" and folded. Its one remaining help line stays by request: the top
bar's template needs its separator syntax spelled out, which the variable
chips beside it cannot convey, so rule 5 carves out template fields.
- propresenter-timers: the "Timers ▾" menu was the only named control left
in any title bar. It is a stopwatch icon now, with the count riding
alongside it while some timers are hidden — setLabel() writes over the
button's contents, so the count needed ProdCom's badge treatment rather
than a label. "Show" folds; the Colours help goes.
- propresenter-now-next: "Show" folds, in the manifest and in the Now
entry's own copy.
- prodcom-transcript: "Show channel icons" loses the redundant verb.
slack and clock were already compliant and are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
82e6386c73
commit
12f0b20e5f
@@ -15,7 +15,7 @@
|
||||
|
||||
Per-tile choices: the gear popover's static switches (whole sources,
|
||||
headings, status lines, the clock's format, the state colours) and the
|
||||
"Timers ▾" header menu, which hides any single timer — keyed `source:id`
|
||||
timers header menu, which hides any single timer — keyed `source:id`
|
||||
and saved with the layout via saveInstanceSettings. The header can be
|
||||
hidden by the user, so the static switches stay the primary controls.
|
||||
A solo tile's gear carries only the settings its one card can use (the
|
||||
@@ -196,6 +196,10 @@ function defaultStatus(timer, value, tone) {
|
||||
|
||||
/* ── the tile ─────────────────────────────────────────────────────────── */
|
||||
|
||||
/* The header menu's icon: a stopwatch, for the list of timers behind it.
|
||||
Title-bar controls carry no words (module guide, rule 9). */
|
||||
const TIMERS_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2h4"/><path d="M12 14V9"/><circle cx="12" cy="14" r="8"/></svg>';
|
||||
|
||||
export default function create({ root, moduleApi }) {
|
||||
let state = null;
|
||||
let feedOffline = false;
|
||||
@@ -227,7 +231,7 @@ export default function create({ root, moduleApi }) {
|
||||
}
|
||||
|
||||
/* Which picker entry this tile was added as (the module's tiles() list):
|
||||
'' or 'all' = every timer, selectable via the Timers ▾ menu;
|
||||
'' or 'all' = every timer, selectable via the timers menu;
|
||||
'solo:<source>:<id>' = exactly one card, no menu, no headings. The
|
||||
earlier entries 'timer:<uuid>' and 'ltc' map onto the new keys. */
|
||||
const variant = String(moduleApi.variant || '');
|
||||
@@ -283,8 +287,8 @@ export default function create({ root, moduleApi }) {
|
||||
|
||||
let menuEl = null; // the open menu's element (filled on each open)
|
||||
const itemsMenu = solo ? null : moduleApi.header.addMenu({
|
||||
label: 'Timers ▾',
|
||||
title: 'Choose timers',
|
||||
icon: TIMERS_SVG,
|
||||
title: 'Timers',
|
||||
build(menu) {
|
||||
// the shell hands over an emptied element on every open
|
||||
menu.classList.add('tm-menu');
|
||||
@@ -292,6 +296,12 @@ export default function create({ root, moduleApi }) {
|
||||
rebuildMenu(true);
|
||||
},
|
||||
});
|
||||
// The icon carries the name; a count rides alongside it while some timers
|
||||
// are hidden, so the bar says "filtered" without saying it in words.
|
||||
const itemsCountEl = document.createElement('span');
|
||||
itemsCountEl.className = 'tm-count';
|
||||
itemsCountEl.hidden = true;
|
||||
if (itemsMenu) itemsMenu.button.appendChild(itemsCountEl);
|
||||
|
||||
function menuRows() {
|
||||
const rows = [];
|
||||
@@ -319,7 +329,9 @@ export default function create({ root, moduleApi }) {
|
||||
if (!itemsMenu) return;
|
||||
const rows = menuRows();
|
||||
const visible = rows.filter((r) => !hidden.has(r.key)).length;
|
||||
itemsMenu.setLabel(visible === rows.length ? 'Timers ▾' : `Timers (${visible}/${rows.length}) ▾`);
|
||||
const filtering = visible !== rows.length;
|
||||
itemsCountEl.textContent = filtering ? `${visible}/${rows.length}` : '';
|
||||
itemsCountEl.hidden = !filtering;
|
||||
}
|
||||
|
||||
let menuSignature = '';
|
||||
@@ -779,7 +791,7 @@ export default function create({ root, moduleApi }) {
|
||||
let hint = '';
|
||||
const groups = visibleGroups();
|
||||
if (state && !state.sources.length) hint = 'Every source is switched off — turn one on in Admin.';
|
||||
else if (state && !groups.length) hint = 'Nothing selected — switch a source on in this tile’s settings, or pick timers in the Timers ▾ menu.';
|
||||
else if (state && !groups.length) hint = 'Nothing selected — switch a source on in this tile’s settings, or pick timers in the title bar’s timers menu.';
|
||||
hintEl.hidden = !hint;
|
||||
hintEl.textContent = hint;
|
||||
groupsEl.hidden = Boolean(hint);
|
||||
|
||||
Reference in New Issue
Block a user