From 9fc15e32136b8c763636549243cf37ba7c159ad5 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Mon, 9 Feb 2026 02:48:14 +0300 Subject: [PATCH] Move test toggle zones outside border, improve span handle hit areas Separate test edge toggles into dedicated elements outside the calibration preview border so they don't conflict with span bar interactions. Expand span handle hit areas to 16px with 4px visible indicators. Increase canvas padding to 36px on all sides and reposition tick labels outside toggle zones. Co-Authored-By: Claude Opus 4.6 --- server/src/wled_controller/static/app.js | 31 +++--- server/src/wled_controller/static/index.html | 24 +++-- server/src/wled_controller/static/style.css | 106 ++++++++++++++----- 3 files changed, 110 insertions(+), 51 deletions(-) diff --git a/server/src/wled_controller/static/app.js b/server/src/wled_controller/static/app.js index 85f0bb2..29b90f0 100644 --- a/server/src/wled_controller/static/app.js +++ b/server/src/wled_controller/static/app.js @@ -1172,18 +1172,16 @@ function updateCalibrationPreview() { const activeEdges = calibrationTestState[deviceId] || new Set(); ['top', 'right', 'bottom', 'left'].forEach(edge => { - const edgeEl = document.querySelector(`.preview-edge.edge-${edge}`); - if (!edgeEl) return; + const toggleEl = document.querySelector(`.edge-toggle.toggle-${edge}`); + if (!toggleEl) return; if (activeEdges.has(edge)) { const [r, g, b] = EDGE_TEST_COLORS[edge]; - edgeEl.classList.add('active'); - edgeEl.style.background = `rgba(${r}, ${g}, ${b}, 0.7)`; - edgeEl.style.boxShadow = `0 0 8px rgba(${r}, ${g}, ${b}, 0.5)`; + toggleEl.style.background = `rgba(${r}, ${g}, ${b}, 0.35)`; + toggleEl.style.boxShadow = `inset 0 0 6px rgba(${r}, ${g}, ${b}, 0.5)`; } else { - edgeEl.classList.remove('active'); - edgeEl.style.background = ''; - edgeEl.style.boxShadow = ''; + toggleEl.style.background = ''; + toggleEl.style.boxShadow = ''; } }); @@ -1200,9 +1198,9 @@ function renderCalibrationCanvas() { const containerRect = container.getBoundingClientRect(); if (containerRect.width === 0 || containerRect.height === 0) return; - // Canvas extends beyond the container (matches CSS: left:-32px, top:-18px, +64px/+36px) - const padX = 32; - const padY = 18; + // Canvas extends beyond the container (matches CSS: left:-36px, top:-36px, +72px/+72px) + const padX = 36; + const padY = 36; const dpr = window.devicePixelRatio || 1; const canvasW = containerRect.width + padX * 2; @@ -1261,12 +1259,13 @@ function renderCalibrationCanvas() { right: { y1: oy + ch + (spans.right?.start || 0) * edgeLenV, y2: oy + ch + (spans.right?.end || 1) * edgeLenV, midX: ox + cW - cw / 2, horizontal: false }, }; - // Axis positions for labels (outside the container bounds, in the padding area) + // Axis positions for labels (outside the 12px toggle zones) + const toggleSize = 12; const axisPos = { - top: oy - 3, // labels above top edge - bottom: oy + cH + 3, // labels below bottom edge - left: ox - 3, // labels left of left edge - right: ox + cW + 3, // labels right of right edge + top: oy - toggleSize - 3, + bottom: oy + cH + toggleSize + 3, + left: ox - toggleSize - 3, + right: ox + cW + toggleSize + 3, }; // Arrow positions (inside the screen area, near each edge bar) diff --git a/server/src/wled_controller/static/index.html b/server/src/wled_controller/static/index.html index 3dfbf69..0ea4dbb 100644 --- a/server/src/wled_controller/static/index.html +++ b/server/src/wled_controller/static/index.html @@ -100,40 +100,46 @@ - -
+ +
+ oninput="updateCalibrationPreview()">
-
+
+ oninput="updateCalibrationPreview()">
-
+
+ oninput="updateCalibrationPreview()">
-
+
+ oninput="updateCalibrationPreview()">
+ +
+
+
+
+
diff --git a/server/src/wled_controller/static/style.css b/server/src/wled_controller/static/style.css index da1b71a..28bc8c7 100644 --- a/server/src/wled_controller/static/style.css +++ b/server/src/wled_controller/static/style.css @@ -920,10 +920,10 @@ input:-webkit-autofill:focus { #calibration-preview-canvas { position: absolute; - top: -18px; - left: -32px; - width: calc(100% + 64px); - height: calc(100% + 36px); + top: -36px; + left: -36px; + width: calc(100% + 72px); + height: calc(100% + 72px); pointer-events: none; z-index: 3; } @@ -1001,20 +1001,52 @@ input:-webkit-autofill:focus { font-size: 11px; color: var(--text-secondary); background: rgba(128, 128, 128, 0.15); - cursor: pointer; - transition: background 0.2s, box-shadow 0.2s; + transition: background 0.2s; z-index: 2; user-select: none; } -.preview-edge:hover { - background: rgba(128, 128, 128, 0.3); +/* Edge test toggle zones — positioned outside the container border */ +.edge-toggle { + position: absolute; + cursor: pointer; + z-index: 1; + background: rgba(128, 128, 128, 0.08); + border: 1px solid rgba(128, 128, 128, 0.15); + border-radius: 3px; + transition: background 0.2s, box-shadow 0.2s; } -.preview-edge.active { - color: white; - font-weight: 600; - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); +.edge-toggle:hover { + background: rgba(128, 128, 128, 0.25); +} + +.toggle-top { + top: -12px; + left: 56px; + right: 56px; + height: 12px; +} + +.toggle-bottom { + bottom: -12px; + left: 56px; + right: 56px; + height: 12px; +} + +.toggle-left { + left: -12px; + top: 36px; + bottom: 36px; + width: 12px; +} + +.toggle-right { + right: -12px; + top: 36px; + bottom: 36px; + width: 12px; } .edge-top { @@ -1123,17 +1155,23 @@ input:-webkit-autofill:focus { right: 2px; } -/* Resize handles */ +/* Resize handles — large transparent hit area with narrow visible strip */ .edge-span-handle { position: absolute; - background: rgba(255, 255, 255, 0.7); - border: 1px solid rgba(76, 175, 80, 0.7); - border-radius: 2px; + background: transparent; z-index: 2; opacity: 0; transition: opacity 0.15s; } +.edge-span-handle::after { + content: ''; + position: absolute; + background: rgba(255, 255, 255, 0.75); + border: 1px solid rgba(76, 175, 80, 0.7); + border-radius: 2px; +} + .edge-span-bar:hover .edge-span-handle { opacity: 1; } @@ -1141,39 +1179,55 @@ input:-webkit-autofill:focus { /* Horizontal handles */ .edge-top .edge-span-handle, .edge-bottom .edge-span-handle { - top: 2px; - bottom: 2px; - width: 6px; + top: 0; + bottom: 0; + width: 16px; cursor: ew-resize; } +.edge-top .edge-span-handle::after, +.edge-bottom .edge-span-handle::after { + top: 3px; + bottom: 3px; + left: 6px; + width: 4px; +} + .edge-top .edge-span-handle-start, .edge-bottom .edge-span-handle-start { - left: 0; + left: -8px; } .edge-top .edge-span-handle-end, .edge-bottom .edge-span-handle-end { - right: 0; + right: -8px; } /* Vertical handles */ .edge-left .edge-span-handle, .edge-right .edge-span-handle { - left: 2px; - right: 2px; - height: 6px; + left: 0; + right: 0; + height: 16px; cursor: ns-resize; } +.edge-left .edge-span-handle::after, +.edge-right .edge-span-handle::after { + left: 3px; + right: 3px; + top: 6px; + height: 4px; +} + .edge-left .edge-span-handle-start, .edge-right .edge-span-handle-start { - top: 0; + top: -8px; } .edge-left .edge-span-handle-end, .edge-right .edge-span-handle-end { - bottom: 0; + bottom: -8px; } /* Ensure LED input is above span bar */