Give every notification type its own row on the board

The shopfloor board grouped cards by display style alone, so every type set to
grid landed inside the Recertification row and every carousel type inside
Recognition's - under a heading naming somebody else's type. Setting Awareness
to grid put awareness messages under "Recertification Required".

Each type now gets a row of its own, titled by its own name, and rotation state
is per row: two carousel rows advance on their own indexes instead of sharing
one counter, and two grid rows page independently.

For the other direction there is notificationtypes.boardcategory. Types sharing
a category share one row under the category name, so Change, Awareness and
Incident can sit together while Recognition and Recertification keep their own.
Blank - the default - means a row of its own. The category is part of the
grouping key along with the display style, since a category cannot merge a
banner with a row of tiles.

A card that names no employee now renders its message as the tile or card,
rather than a placeholder face above a blank name, which is what a grid type
like Awareness looked like before.

The layout fingerprint that makes open kiosks reload now covers the category
and the grace window, so a re-grouped board reaches screens that are already up.
This commit is contained in:
cproudlock
2026-08-07 10:30:28 -04:00
parent a52e192501
commit 76c184fe91
7 changed files with 1081 additions and 826 deletions

View File

@@ -32,7 +32,10 @@
<span class="swatch" :style="{ backgroundColor: swatchColor(t.typecolor) }"></span>
<span class="mono">{{ t.typecolor }}</span>
</td>
<td><span class="badge">{{ t.displaystyle || 'standard' }}</span></td>
<td>
<span class="badge">{{ t.displaystyle || 'standard' }}</span>
<span v-if="t.boardcategory" class="badge badge-secondary">{{ t.boardcategory }}</span>
</td>
<td>
<span v-if="t.splitperemployee" class="badge badge-success">split</span>
<span v-if="t.showemployeephoto" class="badge badge-success">photo</span>
@@ -87,6 +90,17 @@
</select>
</label>
<label class="field">
<span>Board category (optional)</span>
<input v-model="form.boardcategory" type="text" maxlength="50"
placeholder="its own row" />
<small class="muted">
Types sharing a category share one row on the shopfloor board,
under the category name. Blank gives this type a row of its own.
Only types with the same display style can share a row.
</small>
</label>
<label class="field">
<span>Keep showing after end (minutes)</span>
<input v-model.number="form.gracewindowminutes" type="number"
@@ -215,6 +229,7 @@ function openNew() {
expirydays: null,
expiryhour: null,
gracewindowminutes: 0,
boardcategory: '',
isactive: true
}
editing.value = true
@@ -234,6 +249,7 @@ function openEdit(t) {
expirydays: t.expirydays ?? null,
expiryhour: t.expiryhour ?? null,
gracewindowminutes: t.gracewindowminutes ?? 0,
boardcategory: t.boardcategory || '',
isactive: t.isactive !== false
}
editing.value = true
@@ -300,7 +316,10 @@ onMounted(load)
z-index: 1000;
}
.modal-panel {
background: var(--bg-card);
/* Solid, not var(--bg-card): the card variable is translucent in dark mode
(rgba(0,0,61,0.4)) so cards glass over the page, which left this dialog
see-through with the table legible behind it. */
background: var(--bg-card-solid);
color: var(--text);
border: 1px solid var(--border);
border-radius: 10px;