From c34f10f7de0eecdb73d603f5abed800b76b1eb2b Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sun, 8 Feb 2026 04:43:56 +0300 Subject: [PATCH] Streamline calibration modal: inline controls, dynamic aspect ratio, offset fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move total LEDs counter, direction toggle, and offset input into the screen area of the calibration preview - Remove description paragraph, standalone offset form, and total LEDs banner - Add mismatch warning (yellow + ⚠) when configured LEDs ≠ device count - Use actual display aspect ratio for calibration preview - Fix offset not updating tick labels (buildSegments now starts at offset) - Remove max-width constraint on preview, add padding for breathing room - Clean up unused i18n keys from both locale files Co-Authored-By: Claude Opus 4.6 --- server/src/wled_controller/static/app.js | 47 ++++++++++++----- server/src/wled_controller/static/index.html | 31 +++++------ .../wled_controller/static/locales/en.json | 5 -- .../wled_controller/static/locales/ru.json | 5 -- server/src/wled_controller/static/style.css | 51 ++++++++++++++++++- 5 files changed, 95 insertions(+), 44 deletions(-) diff --git a/server/src/wled_controller/static/app.js b/server/src/wled_controller/static/app.js index f3cd461..72e41b4 100644 --- a/server/src/wled_controller/static/app.js +++ b/server/src/wled_controller/static/app.js @@ -980,10 +980,11 @@ function closeConfirmModal(result) { // Calibration functions async function showCalibration(deviceId) { try { - // Fetch current device data - const response = await fetch(`${API_BASE}/devices/${deviceId}`, { - headers: getHeaders() - }); + // Fetch device data and displays in parallel + const [response, displaysResponse] = await Promise.all([ + fetch(`${API_BASE}/devices/${deviceId}`, { headers: getHeaders() }), + fetch(`${API_BASE}/config/displays`, { headers: getHeaders() }), + ]); if (response.status === 401) { handle401Error(); @@ -998,9 +999,24 @@ async function showCalibration(deviceId) { const device = await response.json(); const calibration = device.calibration; + // Set aspect ratio from device's display + const preview = document.querySelector('.calibration-preview'); + if (displaysResponse.ok) { + const displaysData = await displaysResponse.json(); + const displayIndex = device.settings?.display_index ?? 0; + const display = (displaysData.displays || []).find(d => d.index === displayIndex); + if (display && display.width && display.height) { + preview.style.aspectRatio = `${display.width} / ${display.height}`; + } else { + preview.style.aspectRatio = ''; + } + } else { + preview.style.aspectRatio = ''; + } + // Store device ID and LED count document.getElementById('calibration-device-id').value = device.id; - document.getElementById('cal-device-led-count').textContent = device.led_count; + document.getElementById('cal-device-led-count-inline').textContent = device.led_count; // Set layout document.getElementById('cal-start-position').value = calibration.start_position; @@ -1083,7 +1099,14 @@ function updateCalibrationPreview() { parseInt(document.getElementById('cal-right-leds').value || 0) + parseInt(document.getElementById('cal-bottom-leds').value || 0) + parseInt(document.getElementById('cal-left-leds').value || 0); - document.getElementById('cal-total-leds').textContent = total; + // Warning if total doesn't match device LED count + const totalEl = document.querySelector('.preview-screen-total'); + const deviceCount = parseInt(document.getElementById('cal-device-led-count-inline').textContent || 0); + const mismatch = total !== deviceCount; + document.getElementById('cal-total-leds-inline').textContent = (mismatch ? '\u26A0 ' : '') + total; + if (totalEl) { + totalEl.classList.toggle('mismatch', mismatch); + } // Update corner dot highlights for start position const startPos = document.getElementById('cal-start-position').value; @@ -1174,11 +1197,9 @@ function renderCalibrationCanvas() { const segments = buildSegments(calibration); if (segments.length === 0) return; - // Edge bar geometry (matches CSS: corner zones 56px × 36px proportional) - const cornerFracW = 56 / 500; - const cornerFracH = 36 / 312.5; - const cw = cornerFracW * cW; - const ch = cornerFracH * cH; + // Edge bar geometry (matches CSS: corner zones 56px × 36px fixed) + const cw = 56; + const ch = 36; // Edge midlines (center of each edge bar) - in canvas coords const edgeGeometry = { @@ -1371,7 +1392,7 @@ async function clearTestMode(deviceId) { async function saveCalibration() { const deviceId = document.getElementById('calibration-device-id').value; - const deviceLedCount = parseInt(document.getElementById('cal-device-led-count').textContent); + const deviceLedCount = parseInt(document.getElementById('cal-device-led-count-inline').textContent); const error = document.getElementById('calibration-error'); // Clear test mode before saving @@ -1476,7 +1497,7 @@ function buildSegments(calibration) { }; const segments = []; - let ledStart = 0; + let ledStart = calibration.offset || 0; edgeOrder.forEach(edge => { const count = edgeCounts[edge]; diff --git a/server/src/wled_controller/static/index.html b/server/src/wled_controller/static/index.html index e03c279..d579ad3 100644 --- a/server/src/wled_controller/static/index.html +++ b/server/src/wled_controller/static/index.html @@ -83,19 +83,21 @@