Improve kiosk mode startup experience

- Pass query parameters to EJS template for kiosk mode detection
- Add kiosk class to body when enabled via query parameter
- Simplify kiosk mode CSS to hide all elements except main weather display
- Add null checks for progress object to prevent errors in kiosk mode
- Prevent navigation errors when no suitable displays are available
This commit is contained in:
Eddy G
2025-06-24 22:30:16 -04:00
parent 7a07c67e84
commit be41d66de9
5 changed files with 83 additions and 59 deletions

View File

@@ -138,6 +138,7 @@ const compressHtml = async () => {
production: version, production: version,
version, version,
OVERRIDES, OVERRIDES,
query: {},
})) }))
.pipe(rename({ extname: '.html' })) .pipe(rename({ extname: '.html' }))
.pipe(htmlmin({ collapseWhitespace: true })) .pipe(htmlmin({ collapseWhitespace: true }))

View File

@@ -54,6 +54,7 @@ const index = (req, res) => {
production: false, production: false,
version, version,
OVERRIDES, OVERRIDES,
query: req.query,
}); });
}; };

View File

@@ -36,57 +36,66 @@ const getWeather = async (latLon, haveDataCallback) => {
if (typeof haveDataCallback === 'function') haveDataCallback(point); if (typeof haveDataCallback === 'function') haveDataCallback(point);
try {
// get stations // get stations
const stations = await json(point.properties.observationStations); const stations = await json(point.properties.observationStations);
const StationId = stations.features[0].properties.stationIdentifier; const StationId = stations.features[0].properties.stationIdentifier;
let { city } = point.properties.relativeLocation.properties; let { city } = point.properties.relativeLocation.properties;
const { state } = point.properties.relativeLocation.properties; const { state } = point.properties.relativeLocation.properties;
if (StationId in StationInfo) { if (StationId in StationInfo) {
city = StationInfo[StationId].city; city = StationInfo[StationId].city;
[city] = city.split('/'); [city] = city.split('/');
city = city.replace(/\s+$/, ''); city = city.replace(/\s+$/, '');
}
// populate the weather parameters
weatherParameters.latitude = latLon.lat;
weatherParameters.longitude = latLon.lon;
weatherParameters.zoneId = point.properties.forecastZone.substr(-6);
weatherParameters.radarId = point.properties.radarStation.substr(-3);
weatherParameters.stationId = StationId;
weatherParameters.weatherOffice = point.properties.cwa;
weatherParameters.city = city;
weatherParameters.state = state;
weatherParameters.timeZone = point.properties.timeZone;
weatherParameters.forecast = point.properties.forecast;
weatherParameters.forecastGridData = point.properties.forecastGridData;
weatherParameters.stations = stations.features;
// update the main process for display purposes
populateWeatherParameters(weatherParameters);
// reset the scroll
postMessage({ type: 'current-weather-scroll', method: 'reload' });
// draw the progress canvas and hide others
hideAllCanvases();
if (!settings?.kiosk?.value) {
// In normal mode, hide loading screen and show progress
// (In kiosk mode, keep the loading screen visible until autoplay starts)
document.querySelector('#loading').style.display = 'none';
if (progress) {
await progress.drawCanvas();
progress.showCanvas();
}
}
// call for new data on each display
displays.forEach((display) => display.getData(weatherParameters));
} catch (error) {
console.error(`Failed to get weather data: ${error.message}`);
} }
// populate the weather parameters
weatherParameters.latitude = latLon.lat;
weatherParameters.longitude = latLon.lon;
weatherParameters.zoneId = point.properties.forecastZone.substr(-6);
weatherParameters.radarId = point.properties.radarStation.substr(-3);
weatherParameters.stationId = StationId;
weatherParameters.weatherOffice = point.properties.cwa;
weatherParameters.city = city;
weatherParameters.state = state;
weatherParameters.timeZone = point.properties.timeZone;
weatherParameters.forecast = point.properties.forecast;
weatherParameters.forecastGridData = point.properties.forecastGridData;
weatherParameters.stations = stations.features;
// update the main process for display purposes
populateWeatherParameters(weatherParameters);
// reset the scroll
postMessage({ type: 'current-weather-scroll', method: 'reload' });
// draw the progress canvas and hide others
hideAllCanvases();
document.querySelector('#loading').style.display = 'none';
if (progress) {
await progress.drawCanvas();
progress.showCanvas();
}
// call for new data on each display
displays.forEach((display) => display.getData(weatherParameters));
}; };
// receive a status update from a module {id, value} // receive a status update from a module {id, value}
const updateStatus = (value) => { const updateStatus = (value) => {
if (value.id < 0) return; if (value.id < 0) return;
if (!progress) return; if (!progress && !settings?.kiosk?.value) return;
progress.drawCanvas(displays, countLoadedDisplays());
if (progress) progress.drawCanvas(displays, countLoadedDisplays());
// first display is hazards and it must load before evaluating the first display // first display is hazards and it must load before evaluating the first display
if (displays[0].status === STATUS.loading) return; if (displays[0].status === STATUS.loading) return;
@@ -153,7 +162,7 @@ const displayNavMessage = (myMessage) => {
const navTo = (direction) => { const navTo = (direction) => {
// test for a current display // test for a current display
const current = currentDisplay(); const current = currentDisplay();
progress.hideCanvas(); if (progress) progress.hideCanvas();
if (!current) { if (!current) {
// special case for no active displays (typically on progress screen) // special case for no active displays (typically on progress screen)
// find the first ready display // find the first ready display
@@ -166,6 +175,11 @@ const navTo = (direction) => {
if (!firstDisplay) return; if (!firstDisplay) return;
// In kiosk mode, hide the loading screen when we start showing the first display
if (settings?.kiosk?.value) {
document.querySelector('#loading').style.display = 'none';
}
firstDisplay.navNext(msg.command.firstFrame); firstDisplay.navNext(msg.command.firstFrame);
firstDisplay.showCanvas(); firstDisplay.showCanvas();
return; return;
@@ -183,7 +197,7 @@ const loadDisplay = (direction) => {
// convert form simple 0-10 to start at current display index +/-1 and wrap // convert form simple 0-10 to start at current display index +/-1 and wrap
idx = wrap(curIdx + (i + 1) * direction, totalDisplays); idx = wrap(curIdx + (i + 1) * direction, totalDisplays);
if (displays[idx].status === STATUS.loaded && displays[idx].timing.totalScreens > 0) break; if (displays[idx].status === STATUS.loaded && displays[idx].timing.totalScreens > 0) break;
} }
const newDisplay = displays[idx]; const newDisplay = displays[idx];
// hide all displays // hide all displays
hideAllCanvases(); hideAllCanvases();
@@ -210,9 +224,12 @@ const setPlaying = (newValue) => {
playButton.title = 'Play'; playButton.title = 'Play';
playButton.src = 'images/nav/ic_play_arrow_white_24dp_2x.png'; playButton.src = 'images/nav/ic_play_arrow_white_24dp_2x.png';
} }
// if we're playing and on the progress screen jump to the next screen // if we're playing and on the progress screen (or in kiosk mode), jump to the next screen
if (!progress) return; if (playing && !currentDisplay()) {
if (playing && !currentDisplay()) navTo(msg.command.firstFrame); if (progress || settings?.kiosk?.value) {
navTo(msg.command.firstFrame);
}
}
}; };
// handle all navigation buttons // handle all navigation buttons
@@ -237,7 +254,12 @@ const handleNavButton = (button) => {
break; break;
case 'menu': case 'menu':
setPlaying(false); setPlaying(false);
progress.showCanvas(); if (progress) {
progress.showCanvas();
} else if (settings?.kiosk?.value) {
// In kiosk mode without progress, show the loading screen
document.querySelector('#loading').style.display = 'flex';
}
hideAllCanvases(); hideAllCanvases();
break; break;
default: default:

View File

@@ -1,5 +1,5 @@
@use 'shared/_utils'as u; @use 'shared/_utils' as u;
@use 'shared/_colors'as c; @use 'shared/_colors' as c;
@font-face { @font-face {
font-family: "Star4000"; font-family: "Star4000";
@@ -768,15 +768,15 @@ body {
display: none; display: none;
} }
// Hide instructions in kiosk mode (higher specificity than the show rule)
body.kiosk #loading .instructions {
display: none !important;
}
.kiosk { .kiosk {
#divQuery, // In kiosk mode, hide everything except the main weather display
>.info, >*:not(#divTwc) {
>.related-links, display: none !important;
>.heading,
#enabledDisplays,
#settings,
#divInfo {
display: none;
} }
} }

View File

@@ -63,7 +63,7 @@
</head> </head>
<body> <body<% if (query && query['settings-kiosk-checkbox'] === 'true') { %> class="kiosk"<% } %>>
<div id="divQuery"> <div id="divQuery">
@@ -192,4 +192,4 @@
</body> </body>
</html> </html>