From eca81e11cf91f95e5aaafdb4c949400669554b03 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Fri, 6 Feb 2026 18:18:33 +0300 Subject: [PATCH] Improve Web UI with footer, icon buttons, and better modals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add footer with author info (name, email, git repository link) - Replace device action buttons with icons to save space: - Start/Stop: ▶️/⏹️, Settings: ⚙️, Calibrate: 📐, Remove: 🗑️ - Added hover tooltips with translated text - Added btn-icon CSS class for compact styling - Replace native browser confirm() with custom modal dialog: - Matches app theme and supports translations - Used for logout and device removal confirmations - Added confirm.title, confirm.yes, confirm.no translations - Disable background scrolling when modals are open: - Added modal-open class to body when any modal opens - Prevents page scroll behind modals for better UX - Applied to all modals: login, settings, calibration, confirmation Co-Authored-By: Claude Sonnet 4.5 --- server/src/wled_controller/static/app.js | 61 +++++++++++++++---- server/src/wled_controller/static/index.html | 51 +++++++++++++--- .../wled_controller/static/locales/en.json | 5 +- .../wled_controller/static/locales/ru.json | 5 +- server/src/wled_controller/static/style.css | 48 +++++++++++++++ 5 files changed, 147 insertions(+), 23 deletions(-) diff --git a/server/src/wled_controller/static/app.js b/server/src/wled_controller/static/app.js index 235977e..bacb218 100644 --- a/server/src/wled_controller/static/app.js +++ b/server/src/wled_controller/static/app.js @@ -464,22 +464,22 @@ function createDeviceCard(device) {
${isProcessing ? ` - ` : ` - `} - - -
@@ -542,7 +542,8 @@ async function stopProcessing(deviceId) { } async function removeDevice(deviceId) { - if (!confirm('Are you sure you want to remove this device?')) { + const confirmed = await showConfirm(t('device.remove.confirm')); + if (!confirmed) { return; } @@ -603,6 +604,7 @@ async function showSettings(deviceId) { // Show modal const modal = document.getElementById('device-settings-modal'); modal.style.display = 'flex'; + document.body.classList.add('modal-open'); // Focus first input setTimeout(() => { @@ -620,6 +622,7 @@ function closeDeviceSettingsModal() { const error = document.getElementById('settings-error'); modal.style.display = 'none'; error.style.display = 'none'; + document.body.classList.remove('modal-open'); } async function saveDeviceSettings() { @@ -742,6 +745,40 @@ function showToast(message, type = 'info') { }, 3000); } +// Confirmation modal +let confirmResolve = null; + +function showConfirm(message, title = null) { + return new Promise((resolve) => { + confirmResolve = resolve; + + const modal = document.getElementById('confirm-modal'); + const titleEl = document.getElementById('confirm-title'); + const messageEl = document.getElementById('confirm-message'); + const yesBtn = document.getElementById('confirm-yes-btn'); + const noBtn = document.getElementById('confirm-no-btn'); + + titleEl.textContent = title || t('confirm.title'); + messageEl.textContent = message; + yesBtn.textContent = t('confirm.yes'); + noBtn.textContent = t('confirm.no'); + + modal.style.display = 'flex'; + document.body.classList.add('modal-open'); + }); +} + +function closeConfirmModal(result) { + const modal = document.getElementById('confirm-modal'); + modal.style.display = 'none'; + document.body.classList.remove('modal-open'); + + if (confirmResolve) { + confirmResolve(result); + confirmResolve = null; + } +} + // Calibration functions async function showCalibration(deviceId) { try { @@ -788,6 +825,7 @@ async function showCalibration(deviceId) { // Show modal const modal = document.getElementById('calibration-modal'); modal.style.display = 'flex'; + document.body.classList.add('modal-open'); } catch (error) { console.error('Failed to load calibration:', error); @@ -800,6 +838,7 @@ function closeCalibrationModal() { const error = document.getElementById('calibration-error'); modal.style.display = 'none'; error.style.display = 'none'; + document.body.classList.remove('modal-open'); } function updateCalibrationPreview() { diff --git a/server/src/wled_controller/static/index.html b/server/src/wled_controller/static/index.html index 9c1b848..8d064f6 100644 --- a/server/src/wled_controller/static/index.html +++ b/server/src/wled_controller/static/index.html @@ -86,6 +86,16 @@ + +
@@ -285,6 +295,22 @@ + + +