diff --git a/CHANGELOG.md b/CHANGELOG.md index 185df77..9f06a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. +## 2.16.7 - 2026-10-22 + +### Changed + +- Slide advanced animation options open over the animation editor in a separate popup matching templates. Both use an "Advanced animations: [region]" title and support outside-click dismissal without applying changes. +- Slide animation playback controls remain visible above the right-hand settings while those settings scroll, with clearer spacing below field labels. + +### Fixed + +- Slide animation reset controls become available immediately after unsaved basic or advanced changes and restore template settings without requiring a slide save. +- Closing Advanced animations preserves the underlying editor's focus and scroll state, and closing all animation popups restores page scrolling. + ## 2.16.6 - 2026-10-22 ### Fixed diff --git a/build/package.player.json b/build/package.player.json index 86e89ba..6284fa9 100644 --- a/build/package.player.json +++ b/build/package.player.json @@ -1,6 +1,6 @@ { "name": "pulse-signage-player", - "version": "2.16.6", + "version": "2.16.7", "private": false, "description": "Pulse Signage player application bundle", "engines": { diff --git a/build/package.web.json b/build/package.web.json index feb2673..04942b3 100644 --- a/build/package.web.json +++ b/build/package.web.json @@ -1,6 +1,6 @@ { "name": "pulse-signage-web", - "version": "2.16.6", + "version": "2.16.7", "private": false, "description": "Pulse Signage web and bridge application bundle", "engines": { diff --git a/package-lock.json b/package-lock.json index 3150977..ff17dcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pulse-signage", - "version": "2.16.6", + "version": "2.16.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pulse-signage", - "version": "2.16.6", + "version": "2.16.7", "dependencies": { "animate.css": "^4.1.1", "bootstrap-icons": "1.13.1", diff --git a/package.json b/package.json index 9ef35ed..057ba47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pulse-signage", - "version": "2.16.6", + "version": "2.16.7", "private": false, "description": "Pulse Signage application with MySQL and media storage", "engines": { diff --git a/src/web/public/css/theme-custom.css b/src/web/public/css/theme-custom.css index bacb683..054b949 100644 --- a/src/web/public/css/theme-custom.css +++ b/src/web/public/css/theme-custom.css @@ -2439,8 +2439,25 @@ html[data-bs-theme='dark'] .template-field-card .tox .tox-collection { min-height: 0; } +.slide-animation-properties { + display: grid; + grid-template-rows: auto minmax(0, 1fr); + gap: 1rem; + min-width: 0; + min-height: 0; +} + +.slide-animation-advanced-overlay { + z-index: 1075; +} + +.slide-animation-advanced-backdrop { + z-index: 1070; +} + .slide-animation-controls { min-width: 0; + min-height: 0; overflow-y: auto; padding: 0 4px; } @@ -2449,55 +2466,18 @@ html[data-bs-theme='dark'] .template-field-card .tox .tox-collection { grid-template-columns: repeat(2, minmax(0, 1fr)); } -.slide-animation-advanced-fields { - min-width: 0; - overflow-x: clip; -} - -#slide-animation-advanced { - gap: 0.5rem !important; -} - -.slide-animation-advanced-fields .row { +.slide-animation-controls .region-field-grid--animation label { display: grid; - grid-template-columns: minmax(0, 1fr); gap: 0.5rem; - margin: 0; -} - -.slide-animation-advanced-fields .row > * { - width: 100%; - max-width: 100%; - min-width: 0; - padding: 0; -} - -.slide-animation-advanced-fields .card, -.slide-animation-advanced-fields .card-body, -.slide-animation-advanced-fields label { - min-width: 0; -} - -.slide-animation-advanced-fields input, -.slide-animation-advanced-fields select { - width: 100%; - min-width: 0; -} - -#slide-animation-advanced[hidden] { - display: none !important; } .slide-animation-preview-panel { - container-type: size; min-width: 0; min-height: 0; - display: flex; - align-items: center; - justify-content: center; } #slide-animation-preview { + container-type: size; width: 100%; height: 100%; display: flex; @@ -2506,11 +2486,11 @@ html[data-bs-theme='dark'] .template-field-card .tox .tox-collection { } #slide-animation-preview .slide-preview-stage { - width: min(100%, calc(100cqh * var(--slide-layout-ratio, 1.777778))); + width: min(100cqw, calc(100cqh * var(--slide-layout-ratio, 1.777778))); flex-shrink: 0; } -.slide-animation-preview-panel [data-slide-animation-preview][aria-pressed="true"] { +.slide-animation-properties [data-slide-animation-preview][aria-pressed="true"] { color: var(--bs-btn-active-color, #fff); background-color: var(--bs-info); border-color: var(--bs-info); diff --git a/src/web/public/js/slides/slide-animation-editor.js b/src/web/public/js/slides/slide-animation-editor.js index e17e916..ae940f8 100644 --- a/src/web/public/js/slides/slide-animation-editor.js +++ b/src/web/public/js/slides/slide-animation-editor.js @@ -4,8 +4,10 @@ export function createSlideAnimationEditor(options) { var openButton = document.getElementById('adjust-slide-animations'); var regionSelect = document.getElementById('slide-animation-region'); var card = document.getElementById('slide-animation-fields'); - var advanced = document.getElementById('slide-animation-advanced'); - var advancedFields = advanced.querySelector('[data-animation-advanced-fields]'); + var advanced = document.getElementById('animation-advanced-modal'); + var advancedButton = card.querySelector('[data-animation-advanced-button]'); + var advancedOpen = false; + var advancedScrollBar = null; var stage = options.stage; var previewHost = document.getElementById('slide-animation-preview'); var previewButtons = Array.prototype.slice.call(modal.querySelectorAll('[data-slide-animation-preview]')); @@ -31,28 +33,26 @@ export function createSlideAnimationEditor(options) { ? draft[regionKey] : region && region.animation_json || '{}'; } - function getCurrentConfig() { - var config = controls.read(card); - return advanced.hidden ? config : controls.readAdvanced(advancedFields, config); - } function syncDraft() { if (!active || !selectedKey()) return; stopPreview(); - var config = getCurrentConfig(); + var config = controls.read(card); controls.write(card, config); draft[selectedKey()] = JSON.stringify(config); updatePreviewButtons(); + updateResetButtons(); + } + function updateResetButtons() { + document.getElementById('slide-animation-reset-region').disabled = !Object.prototype.hasOwnProperty.call(draft, selectedKey()); + document.getElementById('slide-animation-reset-all').disabled = !Object.keys(draft).length; } function renderRegion() { var key = selectedKey(); var region = regions().find(function (item) { return item.region_key === key; }); if (!region) return; controls.write(card, getConfig(key)); - controls.populateAdvanced(advancedFields, getConfig(key)); - advanced.hidden = true; updatePreviewButtons(); - document.getElementById('slide-animation-reset-region').disabled = !Object.prototype.hasOwnProperty.call(draft, key); - document.getElementById('slide-animation-reset-all').disabled = !Object.keys(draft).length; + updateResetButtons(); } function readResponse(response) { @@ -115,7 +115,7 @@ export function createSlideAnimationEditor(options) { } }); modal.addEventListener('hide.bs.modal', function (event) { - if (sharedSaving) event.preventDefault(); + if (sharedSaving || advancedOpen) event.preventDefault(); }); function getPreviewElements() { @@ -231,11 +231,52 @@ export function createSlideAnimationEditor(options) { controls.bind(card, { onChange: syncDraft, onAdvanced: function () { - advanced.hidden = !advanced.hidden; - if (!advanced.hidden) controls.populateAdvanced(advancedFields, controls.read(card)); + stopPreview(); + controls.populateAdvanced(advanced, controls.read(card)); + var region = regions().find(function (item) { return item.region_key === selectedKey(); }); + advanced.querySelector('[data-animation-modal-title]').textContent = 'Advanced animations: ' + (region.label || region.region_key); + advancedOpen = true; + advancedButton.setAttribute('aria-expanded', 'true'); + advanced.classList.add('slide-animation-advanced-overlay'); + window.pulseModal.getOrCreate(modal)._focustrap.deactivate(); + modal.inert = true; + modal.setAttribute('aria-hidden', 'true'); + modal.removeAttribute('aria-modal'); + var advancedModal = window.pulseModal.getOrCreate(advanced); + advancedScrollBar = advancedModal._scrollBar; + advancedModal._scrollBar = Object.create(advancedScrollBar); + advancedModal._scrollBar.hide = function () {}; + advancedModal._scrollBar.reset = function () {}; + window.pulseModal.show(advanced); + var backdrops = document.querySelectorAll('.modal-backdrop'); + if (backdrops.length) backdrops[backdrops.length - 1].classList.add('slide-animation-advanced-backdrop'); } }); - advancedFields.addEventListener('change', syncDraft); + advanced.addEventListener('shown.bs.modal', function () { + advanced.querySelector('[data-animation-modal-field]').focus(); + }); + advanced.addEventListener('hidden.bs.modal', function () { + window.pulseModal.getOrCreate(advanced)._scrollBar = advancedScrollBar; + advancedScrollBar = null; + advancedOpen = false; + advancedButton.setAttribute('aria-expanded', 'false'); + advanced.classList.remove('slide-animation-advanced-overlay'); + modal.inert = false; + modal.removeAttribute('aria-hidden'); + modal.setAttribute('aria-modal', 'true'); + document.body.classList.add('modal-open'); + var parentModal = window.pulseModal.getOrCreate(modal); + parentModal._focustrap.activate(); + advancedButton.focus(); + }); + advanced.querySelector('[data-animation-modal-apply]').addEventListener('click', function () { + controls.write(card, controls.readAdvanced(advanced, controls.read(card))); + syncDraft(); + window.pulseModal.hide(advanced); + }); + advanced.querySelector('[data-animation-modal-reset]').addEventListener('click', function () { + controls.populateAdvanced(advanced, '{}'); + }); document.getElementById('slide-animation-reset-region').addEventListener('click', function () { stopPreview(); delete draft[selectedKey()]; diff --git a/src/web/public/js/templates/template-designer.js b/src/web/public/js/templates/template-designer.js index 2130f70..4335de7 100644 --- a/src/web/public/js/templates/template-designer.js +++ b/src/web/public/js/templates/template-designer.js @@ -584,7 +584,7 @@ var config = getAnimationConfig(card); if (title) { - title.textContent = (label ? label.textContent : 'Region') + ' animation settings'; + title.textContent = 'Advanced animations: ' + (label ? label.textContent : 'Region'); } window.pulseRegionAnimationControls.populateAdvanced(animationAdvancedModal, config); diff --git a/src/web/views/signage/slides/form.hbs b/src/web/views/signage/slides/form.hbs index a303df7..c3ab74e 100644 --- a/src/web/views/signage/slides/form.hbs +++ b/src/web/views/signage/slides/form.hbs @@ -123,23 +123,21 @@ -