Add onboarding weather and template gradients
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m53s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 34s

This commit is contained in:
2026-08-28 20:05:23 +01:00
parent aa07a78912
commit 3960931ebe
80 changed files with 12750 additions and 519 deletions
+71 -2
View File
@@ -440,6 +440,34 @@ function isEditableTarget(target) {
return ['INPUT', 'TEXTAREA', 'SELECT', 'OPTION'].indexOf(tagName) !== -1;
}
var keyboardFeedbackTimer = null;
function showKeyboardFeedback(message) {
if (typeof document === 'undefined' || !document.body) {
return;
}
var feedback = document.querySelector('.player-keyboard-feedback');
if (!feedback) {
feedback = document.createElement('div');
feedback.className = 'player-keyboard-feedback';
feedback.setAttribute('aria-live', 'polite');
document.body.appendChild(feedback);
}
feedback.textContent = String(message || '');
feedback.classList.remove('is-visible');
void feedback.offsetWidth;
feedback.classList.add('is-visible');
if (keyboardFeedbackTimer) {
window.clearTimeout(keyboardFeedbackTimer);
}
keyboardFeedbackTimer = window.setTimeout(function () {
feedback.classList.remove('is-visible');
keyboardFeedbackTimer = null;
}, 900);
}
function handlePlayerKeydown(event) {
if (!event || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {
return;
@@ -452,12 +480,28 @@ function handlePlayerKeydown(event) {
if (event.key === 'ArrowLeft') {
event.preventDefault();
navigateSlides(-1);
showKeyboardFeedback('Previous slide');
return;
}
if (event.key === 'ArrowRight') {
event.preventDefault();
navigateSlides(1);
showKeyboardFeedback('Next slide');
return;
}
if (String(event.key || '').toLowerCase() === 'p') {
event.preventDefault();
setPaused(!isPaused);
showKeyboardFeedback(isPaused ? 'Paused' : 'Playing');
return;
}
if (String(event.key || '').toLowerCase() === 'b') {
event.preventDefault();
setBlackout(!isBlackout);
showKeyboardFeedback(isBlackout ? 'Blackout on' : 'Blackout off');
}
}
@@ -489,6 +533,10 @@ function handleCommandMessage(rawMessage) {
} catch (_error) {
return;
}
if (payload && payload.type === 'client-id-conflict') {
handleClientIdConflict();
return;
}
if (!payload || payload.type !== 'command') {
return;
@@ -505,7 +553,17 @@ function handleCommandMessage(rawMessage) {
return;
case 'redirect':
if (payload.url) {
window.location.replace(String(payload.url));
var redirectUrl = String(payload.url);
var authorizeMove = payload.moveToken
? fetch('/api/screen-move-authorize', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify({ moveToken: String(payload.moveToken) })
})
: Promise.resolve();
authorizeMove.finally(function () {
window.location.replace(redirectUrl);
});
}
return;
case 'pause':
@@ -541,6 +599,13 @@ function handleCommandMessage(rawMessage) {
}
}
function handleClientIdConflict() {
var replacementClientId = regenerateCommandClientId();
var onboardingUrl = new URL('/', window.location.origin);
onboardingUrl.searchParams.set('clientId', replacementClientId);
window.location.replace(onboardingUrl.toString());
}
// Retry the command websocket after a disconnect.
function scheduleCommandReconnect() {
if (commandReconnectTimer) {
@@ -577,8 +642,12 @@ function connectCommandSocket() {
handleCommandMessage(event.data);
};
socket.onclose = function () {
socket.onclose = function (event) {
commandSocket = null;
if (event && event.code === 4009) {
handleClientIdConflict();
return;
}
scheduleCommandReconnect();
};