From 65d53d1d419cd0d15147992e296328ba0102429d Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 26 Aug 2026 10:57:31 +0000 Subject: [PATCH] Kiosk: dashboard-matching state-colour borders, AC top-right + TRV row layout - kiosk-block border-left now uses the same st-vacant/booked/heating_up/ occupied/cooling_down colour scheme as the Dashboard's ZoneCard - Layout tweak (user, 2026-08-26): a room only ever has one AC unit, so it's pinned top-right; lower half is a row of up to 3 TRVs with setpoint stacked below the icon rather than beside it (more legible at kiosk touch size than the dashboard's compact rad-row) Co-Authored-By: Claude Sonnet 5 --- frontend/src/components/KioskZoneBlock.tsx | 44 ++++++++++++---------- frontend/src/index.css | 28 ++++++++++---- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/KioskZoneBlock.tsx b/frontend/src/components/KioskZoneBlock.tsx index ff75738..4a3092c 100644 --- a/frontend/src/components/KioskZoneBlock.tsx +++ b/frontend/src/components/KioskZoneBlock.tsx @@ -32,38 +32,31 @@ interface Props { } // One tile per ROOM/ZONE — same idea as the Dashboard's ZoneCard, not one tile -// per device. A room with both a TRV and an AC unit shows both in one tile, via -// the exact same rad-row/ac-block markup+CSS ZoneCard.tsx uses, so the kiosk -// visually matches the staff dashboard (per user correction, 2026-08-26, to an -// earlier per-device-tile version of this file). +// per device (per user correction, 2026-08-26). Border colour is the room's +// live state, same st-* classes/vars ZoneCard uses, so a tile reads the same +// way on the kiosk as on the staff dashboard. Layout differs from ZoneCard +// deliberately (user, 2026-08-26): a room only ever has one AC unit, so it's +// pinned top-right, leaving the lower half for a row of up to 3 TRVs (setpoint +// stacked below the icon rather than beside it — more legible at a glance/touch +// size than the dashboard's compact side-by-side rad-row). export default function KioskZoneBlock({ zone, liveDevices, selectionMode, selected, onTap }: Props) { const trvs = liveDevices .filter(d => d.device_type === 'shelly_trv') .sort((a, b) => locationRank(a.location) - locationRank(b.location)) + .slice(0, 3) const ac = liveDevices.find(d => KIOSK_AC_DEVICE_TYPES.includes(d.device_type)) const acOn = ac?.power_state === 'on' const ModeIcon = MODE_ICONS[ac?.current_mode || ''] || Fan const fanLevel = ac ? (MHI_FAN_SPEEDS as readonly string[]).indexOf(ac.fan_speed || '') + 1 : 0 return ( -
+
{selectionMode && (
{selected && }
)} -
{zone.name}
- -
- {trvs.length > 0 && ( -
- {trvs.slice(0, 3).map(d => ( -
- - {fmtTemp(d.current_target_temp)} -
- ))} -
- )} +
+ {zone.name} {ac && (
{ac.remote_locked && } @@ -76,9 +69,20 @@ export default function KioskZoneBlock({ zone, liveDevices, selectionMode, selec
{fmtTemp(ac.current_target_temp)} / {fmtTemp(ac.current_room_temp)}
)} - - {trvs.length === 0 && !ac && No live devices}
+ + {trvs.length > 0 ? ( +
+ {trvs.map(d => ( +
+ + {fmtTemp(d.current_target_temp)} +
+ ))} +
+ ) : !ac ? ( + No live devices + ) : null}
) } diff --git a/frontend/src/index.css b/frontend/src/index.css index dbb4b40..a74ff5b 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -456,15 +456,23 @@ table.data tr:last-child td { border-bottom: none; } .kiosk-grid-wrap { flex: 1; overflow-y: auto; padding: 16px; } .kiosk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; } -/* One tile per zone, reusing ZoneCard's own rad-row/ac-block/fan-bar classes - (defined above under "Zone grid / cards") so a room's TRV + AC read - identically here and on the Dashboard — just the outer tile is kiosk-sized. */ +/* One tile per zone. Border colour = the room's live state, same st-* vars + ZoneCard uses (see "Zone grid / cards" above) — a tile reads the same way + here as on the Dashboard. Top area: zone name + the (at most one) AC block, + pinned top-right via space-between. Bottom half: a row of up to 3 TRVs, + pushed down by the outer flex's space-between — the "lower half" layout + the dashboard's cards don't need since staff view is denser/smaller text. */ .kiosk-block { position: relative; cursor: pointer; background: var(--card-bg); - border: 1px solid var(--card-border); border-radius: var(--radius); - box-shadow: var(--shadow-sm); padding: 12px; min-height: 96px; - display: flex; flex-direction: column; gap: 8px; user-select: none; + border: 1px solid var(--card-border); border-left: 4px solid var(--st-vacant); border-radius: var(--radius); + box-shadow: var(--shadow-sm); padding: 12px; min-height: 112px; + display: flex; flex-direction: column; justify-content: space-between; gap: 10px; user-select: none; } +.kiosk-block.st-vacant { border-left-color: var(--st-vacant); } +.kiosk-block.st-booked { border-left-color: var(--st-booked); } +.kiosk-block.st-heating_up { border-left-color: var(--st-heating-up); } +.kiosk-block.st-occupied { border-left-color: var(--st-occupied); } +.kiosk-block.st-cooling_down { border-left-color: var(--st-cooling-down); } .kiosk-block.selected { outline: 2px solid var(--gold); outline-offset: -2px; } .kiosk-block-check { position: absolute; top: 8px; right: 8px; width: 20px; height: 20px; border-radius: 5px; @@ -472,8 +480,12 @@ table.data tr:last-child td { border-bottom: none; } color: var(--navy); background: var(--card-bg); } .kiosk-block.selected .kiosk-block-check { background: var(--gold); border-color: var(--gold); color: var(--navy); } -.kiosk-block-zone { font-size: 13px; font-weight: 700; color: var(--text-dark); padding-right: 22px; } -.kiosk-block-body { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex: 1; } +.kiosk-block-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; padding-right: 24px; } +.kiosk-block-zone { font-size: 13px; font-weight: 700; color: var(--text-dark); } + +.kiosk-trv-row { display: flex; gap: 16px; } +.kiosk-trv { display: flex; flex-direction: column; align-items: center; gap: 3px; font-size: 11.5px; font-weight: 600; color: var(--text-mid); } +.kiosk-trv.heating { color: var(--danger); } .kiosk-bulk-bar { position: sticky; bottom: 0; display: flex; align-items: center; gap: 12px;