From 43accba61c6fc511fbc758e5a2b85ff589707fb6 Mon Sep 17 00:00:00 2001 From: CODEX Date: Thu, 4 Jun 2026 23:33:28 +0300 Subject: [PATCH] beam: align zoom slider with engine controls --- frontend/dcViewer.css | 113 ++++++++++++++++++++--------- frontend/index.html | 4 +- frontend/src/ui/controls/slider.js | 24 +++++- 3 files changed, 104 insertions(+), 37 deletions(-) diff --git a/frontend/dcViewer.css b/frontend/dcViewer.css index 8427200..39323ac 100644 --- a/frontend/dcViewer.css +++ b/frontend/dcViewer.css @@ -1167,58 +1167,105 @@ header { } .inspector-slider.slider-row { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - grid-template-areas: - "label value" - "input input"; - gap: 8px; - align-items: center; - padding: 0; + position: relative; + display: block; + width: 100%; + height: 40px; + overflow: hidden; + border-radius: 14px; + background: var(--nodedc-glass-control-bg); + box-shadow: var(--nodedc-glass-control-shadow); + backdrop-filter: blur(24px) saturate(128%) brightness(1.05); + -webkit-backdrop-filter: blur(24px) saturate(128%) brightness(1.05); +} + +.inspector-slider.slider-row::before { + content: ""; + position: absolute; + inset: 0 auto 0 0; + z-index: 1; + width: var(--slider-percent, 0%); + border-radius: inherit; + background: var(--modal-btn-primary, var(--accent)); } .inspector-slider .slider-label { - grid-area: label; - min-width: 0; - color: var(--muted); - font-size: 11px; + position: absolute; + top: 50%; + left: 16px; + z-index: 2; + max-width: calc(100% - 116px); + overflow: hidden; + color: rgba(255, 255, 255, 0.92); + font-size: 12px; font-weight: 760; - line-height: 1.2; + line-height: 1; + text-overflow: ellipsis; + white-space: nowrap; + transform: translateY(-50%); + pointer-events: none; } .inspector-slider .slider-value { - grid-area: value; - min-width: 38px; - color: rgba(245, 245, 250, 0.82); + position: absolute; + top: 50%; + right: 16px; + z-index: 2; + color: rgba(245, 245, 250, 0.9); + font-size: 12px; + font-weight: 760; + line-height: 1; text-align: right; + transform: translateY(-50%); + pointer-events: none; } .inspector-slider .slider-input { - grid-area: input; - height: 40px; - border-radius: 14px; - background: linear-gradient( - 90deg, - var(--modal-btn-primary, var(--accent)) var(--slider-percent, 0%), - var(--nodedc-glass-control-bg) var(--slider-percent, 0%) - ); - box-shadow: var(--nodedc-glass-control-shadow); + position: absolute; + inset: 0; + z-index: 4; + width: 100%; + height: 100%; + margin: 0; + appearance: none; + -webkit-appearance: none; + border-radius: inherit; + background: transparent; + opacity: 0; + cursor: pointer; } .inspector-slider .slider-input::-webkit-slider-thumb { - width: 20px; - height: 20px; - background: var(--modal-btn-primary, var(--accent)); + width: 24px; + height: 40px; + margin-top: 0; + appearance: none; + -webkit-appearance: none; border: 0; - box-shadow: 0 8px 18px rgba(0, 0, 0, 0.32); + background: transparent; + box-shadow: none; } .inspector-slider .slider-input::-moz-range-thumb { - width: 20px; - height: 20px; - background: var(--modal-btn-primary, var(--accent)); + width: 24px; + height: 40px; border: 0; - box-shadow: 0 8px 18px rgba(0, 0, 0, 0.32); + background: transparent; + box-shadow: none; +} + +.inspector-slider .slider-fill-text { + position: absolute; + inset: 0; + z-index: 3; + overflow: hidden; + clip-path: inset(0 calc(100% - var(--slider-percent, 0%)) 0 0); + pointer-events: none; +} + +.inspector-slider .slider-fill-text .slider-label, +.inspector-slider .slider-fill-text .slider-value { + color: var(--modal-btn-primary-contrast, #15170f); } .settings-panel input[type="color"] { diff --git a/frontend/index.html b/frontend/index.html index 49e183f..a812de4 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -87,7 +87,7 @@ - +
@@ -239,6 +239,6 @@ - + diff --git a/frontend/src/ui/controls/slider.js b/frontend/src/ui/controls/slider.js index 06314d5..22af191 100644 --- a/frontend/src/ui/controls/slider.js +++ b/frontend/src/ui/controls/slider.js @@ -27,11 +27,30 @@ export function createSliderControl({ const valueEl = document.createElement("div"); valueEl.className = "slider-value"; + const fillText = document.createElement("span"); + fillText.className = "slider-fill-text"; + fillText.setAttribute("aria-hidden", "true"); + + const fillLabel = document.createElement("span"); + fillLabel.textContent = label; + fillLabel.className = "slider-label"; + + const fillValue = document.createElement("span"); + fillValue.className = "slider-value"; + fillText.appendChild(fillLabel); + fillText.appendChild(fillValue); + const updateFill = () => { - const percent = ((input.value - input.min) / (input.max - input.min)) * 100; + const range = Number(input.max) - Number(input.min); + const percent = range + ? Math.max(0, Math.min(100, ((Number(input.value) - Number(input.min)) / range) * 100)) + : 0; + row.style.setProperty("--slider-percent", `${percent}%`); input.style.setProperty("--slider-percent", `${percent}%`); if (showValue) { - valueEl.textContent = formatValue(Number(input.value)); + const formattedValue = formatValue(Number(input.value)); + valueEl.textContent = formattedValue; + fillValue.textContent = formattedValue; } }; @@ -47,6 +66,7 @@ export function createSliderControl({ row.appendChild(input); if (showValue) { row.appendChild(valueEl); + row.appendChild(fillText); } row.setValue = (nextValue) => { input.value = nextValue;