Shell: single-instance tile entries, and a multiselect admin field
Two small pieces of contract for modules that offer several tiles from live
data:
- A `tiles()` entry may say `single: true`: at most one such tile per
dashboard. The + picker greys the entry out once it is placed ("Already on
this dashboard") and `addTile` refuses a second — for a control surface
that would only confuse in duplicate, a send box say.
- Admin config gains `multiselect`: several picks from one list, the same
`options` / `optionsRoute` as `select`, one switch per option, stored as an
array of values. A saved value the list no longer offers stays checked and
marked rather than being dropped in silence. The wrapper is a <label>, so
it is told to label nothing — otherwise a click anywhere would flip the
first switch.
Both documented in the module guide.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
babe8263eb
commit
7d34604f2f
+10
-2
@@ -108,9 +108,10 @@ function wireDropdown(btnId, menuId, rebuild) {
|
||||
return menu;
|
||||
}
|
||||
|
||||
function menuItem(label, onClick, { sub = '', danger = false } = {}) {
|
||||
function menuItem(label, onClick, { sub = '', danger = false, disabled = false } = {}) {
|
||||
const item = document.createElement('button');
|
||||
item.className = 'menu-item' + (danger ? ' danger' : '');
|
||||
item.disabled = disabled;
|
||||
const span = document.createElement('span');
|
||||
span.textContent = label;
|
||||
if (sub) {
|
||||
@@ -706,6 +707,10 @@ function buildDivider(L, R, top, bottom) {
|
||||
*/
|
||||
function addTile(moduleId, entry = null) {
|
||||
const man = registry.get(moduleId);
|
||||
if (entry?.single && tiles.some((t) => t.module === moduleId && t.variant === String(entry.id))) {
|
||||
toast(`${entry.name} is already on this dashboard`);
|
||||
return;
|
||||
}
|
||||
const defaultSize = entry?.defaultSize || man?.defaultSize;
|
||||
const size = {
|
||||
w: Math.max(1, Math.min(COLS, defaultSize?.w || 4)),
|
||||
@@ -1316,10 +1321,13 @@ function renderAddMenu(menu) {
|
||||
title.textContent = man.name;
|
||||
menu.appendChild(title);
|
||||
for (const entry of entries) {
|
||||
// An entry that allows one tile at most is offered greyed out once
|
||||
// that tile exists — a second Send box would only confuse.
|
||||
const placed = entry.single && tiles.some((t) => t.module === man.id && t.variant === String(entry.id));
|
||||
menu.appendChild(menuItem(entry.name, () => {
|
||||
menu.hidden = true;
|
||||
addTile(man.id, entry);
|
||||
}, { sub: entry.description || '' }));
|
||||
}, { sub: placed ? 'Already on this dashboard' : (entry.description || ''), disabled: placed }));
|
||||
}
|
||||
} else {
|
||||
menu.appendChild(menuItem(man.name, () => {
|
||||
|
||||
Reference in New Issue
Block a user