Move overlay toggle into calibration visual editor, add tutorial step
Place the overlay button inside the preview screen as a pill toggle, add it as a tutorial step that auto-skips in device calibration mode. Tutorial engine now skips hidden/missing targets in both directions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -416,6 +416,34 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Overlay toggle inside the preview screen */
|
||||||
|
.calibration-overlay-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
height: 26px;
|
||||||
|
padding: 0 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 12px;
|
||||||
|
color: white;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s, border-color 0.2s;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calibration-overlay-toggle:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calibration-overlay-toggle.active {
|
||||||
|
background: rgba(76, 175, 80, 0.35);
|
||||||
|
border-color: rgba(76, 175, 80, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
.preview-hint {
|
.preview-hint {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
|
|||||||
@@ -93,13 +93,7 @@ async function _clearCSSTestMode() {
|
|||||||
function _setOverlayBtnActive(active) {
|
function _setOverlayBtnActive(active) {
|
||||||
const btn = document.getElementById('calibration-overlay-btn');
|
const btn = document.getElementById('calibration-overlay-btn');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
if (active) {
|
btn.classList.toggle('active', active);
|
||||||
btn.style.background = 'var(--primary-color)';
|
|
||||||
btn.style.color = 'white';
|
|
||||||
} else {
|
|
||||||
btn.style.background = '';
|
|
||||||
btn.style.color = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _checkOverlayStatus(cssId) {
|
async function _checkOverlayStatus(cssId) {
|
||||||
@@ -166,7 +160,6 @@ export async function showCalibration(deviceId) {
|
|||||||
document.getElementById('cal-device-led-count-inline').textContent = device.led_count;
|
document.getElementById('cal-device-led-count-inline').textContent = device.led_count;
|
||||||
document.getElementById('cal-css-led-count-group').style.display = 'none';
|
document.getElementById('cal-css-led-count-group').style.display = 'none';
|
||||||
document.getElementById('calibration-overlay-btn').style.display = 'none';
|
document.getElementById('calibration-overlay-btn').style.display = 'none';
|
||||||
document.getElementById('calibration-tutorial-btn').style.marginLeft = '';
|
|
||||||
|
|
||||||
document.getElementById('cal-start-position').value = calibration.start_position;
|
document.getElementById('cal-start-position').value = calibration.start_position;
|
||||||
document.getElementById('cal-layout').value = calibration.layout;
|
document.getElementById('cal-layout').value = calibration.layout;
|
||||||
@@ -324,7 +317,6 @@ export async function showCSSCalibration(cssId) {
|
|||||||
_overlayStartedHere = false;
|
_overlayStartedHere = false;
|
||||||
const overlayBtn = document.getElementById('calibration-overlay-btn');
|
const overlayBtn = document.getElementById('calibration-overlay-btn');
|
||||||
overlayBtn.style.display = '';
|
overlayBtn.style.display = '';
|
||||||
document.getElementById('calibration-tutorial-btn').style.marginLeft = '0';
|
|
||||||
_setOverlayBtnActive(false);
|
_setOverlayBtnActive(false);
|
||||||
_checkOverlayStatus(cssId);
|
_checkOverlayStatus(cssId);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const calibrationTutorialSteps = [
|
|||||||
{ selector: '.direction-toggle', textKey: 'calibration.tip.direction', position: 'bottom' },
|
{ selector: '.direction-toggle', textKey: 'calibration.tip.direction', position: 'bottom' },
|
||||||
{ selector: '.edge-span-bar[data-edge="top"]', textKey: 'calibration.tip.span', position: 'bottom' },
|
{ selector: '.edge-span-bar[data-edge="top"]', textKey: 'calibration.tip.span', position: 'bottom' },
|
||||||
{ selector: '.toggle-top', textKey: 'calibration.tip.test', position: 'top' },
|
{ selector: '.toggle-top', textKey: 'calibration.tip.test', position: 'top' },
|
||||||
|
{ selector: '#calibration-overlay-btn', textKey: 'calibration.tip.overlay', position: 'bottom' },
|
||||||
{ selector: '.preview-screen-total', textKey: 'calibration.tip.toggle_inputs', position: 'top' },
|
{ selector: '.preview-screen-total', textKey: 'calibration.tip.toggle_inputs', position: 'top' },
|
||||||
{ selector: '.preview-screen-border-width', textKey: 'calibration.tip.border_width', position: 'bottom' },
|
{ selector: '.preview-screen-border-width', textKey: 'calibration.tip.border_width', position: 'bottom' },
|
||||||
{ selector: '#cal-offset', textKey: 'calibration.tip.offset', position: 'top' },
|
{ selector: '#cal-offset', textKey: 'calibration.tip.offset', position: 'top' },
|
||||||
@@ -55,7 +56,13 @@ export function startCalibrationTutorial() {
|
|||||||
overlayId: 'tutorial-overlay',
|
overlayId: 'tutorial-overlay',
|
||||||
mode: 'absolute',
|
mode: 'absolute',
|
||||||
container: container,
|
container: container,
|
||||||
resolveTarget: (step) => document.querySelector(step.selector)
|
resolveTarget: (step) => {
|
||||||
|
const el = document.querySelector(step.selector);
|
||||||
|
if (!el) return null;
|
||||||
|
// Skip elements hidden via display:none (e.g. overlay btn in device mode)
|
||||||
|
if (el.style.display === 'none' || getComputedStyle(el).display === 'none') return null;
|
||||||
|
return el;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,11 +109,11 @@ export function tutorialNext() {
|
|||||||
export function tutorialPrev() {
|
export function tutorialPrev() {
|
||||||
if (!activeTutorial) return;
|
if (!activeTutorial) return;
|
||||||
if (activeTutorial.step > 0) {
|
if (activeTutorial.step > 0) {
|
||||||
showTutorialStep(activeTutorial.step - 1);
|
showTutorialStep(activeTutorial.step - 1, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showTutorialStep(index) {
|
function showTutorialStep(index, direction = 1) {
|
||||||
if (!activeTutorial) return;
|
if (!activeTutorial) return;
|
||||||
activeTutorial.step = index;
|
activeTutorial.step = index;
|
||||||
const step = activeTutorial.steps[index];
|
const step = activeTutorial.steps[index];
|
||||||
@@ -119,7 +126,13 @@ function showTutorialStep(index) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const target = activeTutorial.resolveTarget(step);
|
const target = activeTutorial.resolveTarget(step);
|
||||||
if (!target) return;
|
if (!target) {
|
||||||
|
// Auto-skip hidden/missing targets in the current direction
|
||||||
|
const next = index + direction;
|
||||||
|
if (next >= 0 && next < activeTutorial.steps.length) showTutorialStep(next, direction);
|
||||||
|
else closeTutorial();
|
||||||
|
return;
|
||||||
|
}
|
||||||
target.classList.add('tutorial-target');
|
target.classList.add('tutorial-target');
|
||||||
if (isFixed) target.style.zIndex = '10001';
|
if (isFixed) target.style.zIndex = '10001';
|
||||||
|
|
||||||
|
|||||||
@@ -208,11 +208,13 @@
|
|||||||
"calibration.tip.offset": "Set LED offset — distance from LED 0 to the start corner",
|
"calibration.tip.offset": "Set LED offset — distance from LED 0 to the start corner",
|
||||||
"calibration.tip.span": "Drag green bars to adjust coverage span",
|
"calibration.tip.span": "Drag green bars to adjust coverage span",
|
||||||
"calibration.tip.test": "Click an edge to toggle test LEDs",
|
"calibration.tip.test": "Click an edge to toggle test LEDs",
|
||||||
|
"calibration.tip.overlay": "Toggle screen overlay to see LED positions and numbering on your monitor",
|
||||||
"calibration.tip.toggle_inputs": "Click total LED count to toggle edge inputs",
|
"calibration.tip.toggle_inputs": "Click total LED count to toggle edge inputs",
|
||||||
"calibration.tip.border_width": "How many pixels from the screen edge to sample for LED colors",
|
"calibration.tip.border_width": "How many pixels from the screen edge to sample for LED colors",
|
||||||
"calibration.tip.skip_leds_start": "Skip LEDs at the start of the strip — skipped LEDs stay off",
|
"calibration.tip.skip_leds_start": "Skip LEDs at the start of the strip — skipped LEDs stay off",
|
||||||
"calibration.tip.skip_leds_end": "Skip LEDs at the end of the strip — skipped LEDs stay off",
|
"calibration.tip.skip_leds_end": "Skip LEDs at the end of the strip — skipped LEDs stay off",
|
||||||
"calibration.tutorial.start": "Start tutorial",
|
"calibration.tutorial.start": "Start tutorial",
|
||||||
|
"calibration.overlay_toggle": "Overlay",
|
||||||
"calibration.start_position": "Starting Position:",
|
"calibration.start_position": "Starting Position:",
|
||||||
"calibration.position.bottom_left": "Bottom Left",
|
"calibration.position.bottom_left": "Bottom Left",
|
||||||
"calibration.position.bottom_right": "Bottom Right",
|
"calibration.position.bottom_right": "Bottom Right",
|
||||||
|
|||||||
@@ -208,11 +208,13 @@
|
|||||||
"calibration.tip.offset": "Смещение LED — расстояние от LED 0 до стартового угла",
|
"calibration.tip.offset": "Смещение LED — расстояние от LED 0 до стартового угла",
|
||||||
"calibration.tip.span": "Перетащите зелёные полосы для настройки зоны покрытия",
|
"calibration.tip.span": "Перетащите зелёные полосы для настройки зоны покрытия",
|
||||||
"calibration.tip.test": "Нажмите на край для теста LED",
|
"calibration.tip.test": "Нажмите на край для теста LED",
|
||||||
|
"calibration.tip.overlay": "Включите оверлей для отображения позиций и нумерации LED на мониторе",
|
||||||
"calibration.tip.toggle_inputs": "Нажмите на общее количество LED для скрытия боковых полей",
|
"calibration.tip.toggle_inputs": "Нажмите на общее количество LED для скрытия боковых полей",
|
||||||
"calibration.tip.border_width": "Сколько пикселей от края экрана использовать для цветов LED",
|
"calibration.tip.border_width": "Сколько пикселей от края экрана использовать для цветов LED",
|
||||||
"calibration.tip.skip_leds_start": "Пропуск LED в начале ленты — пропущенные LED остаются выключенными",
|
"calibration.tip.skip_leds_start": "Пропуск LED в начале ленты — пропущенные LED остаются выключенными",
|
||||||
"calibration.tip.skip_leds_end": "Пропуск LED в конце ленты — пропущенные LED остаются выключенными",
|
"calibration.tip.skip_leds_end": "Пропуск LED в конце ленты — пропущенные LED остаются выключенными",
|
||||||
"calibration.tutorial.start": "Начать обучение",
|
"calibration.tutorial.start": "Начать обучение",
|
||||||
|
"calibration.overlay_toggle": "Оверлей",
|
||||||
"calibration.start_position": "Начальная Позиция:",
|
"calibration.start_position": "Начальная Позиция:",
|
||||||
"calibration.position.bottom_left": "Нижний Левый",
|
"calibration.position.bottom_left": "Нижний Левый",
|
||||||
"calibration.position.bottom_right": "Нижний Правый",
|
"calibration.position.bottom_right": "Нижний Правый",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
<div class="modal-content" style="max-width: 700px;">
|
<div class="modal-content" style="max-width: 700px;">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h2 id="calibration-modal-title" data-i18n="calibration.title">📐 LED Calibration</h2>
|
<h2 id="calibration-modal-title" data-i18n="calibration.title">📐 LED Calibration</h2>
|
||||||
<button id="calibration-overlay-btn" class="tutorial-trigger-btn" onclick="toggleCalibrationOverlay()" data-i18n-title="overlay.button.show" title="Show overlay visualization" style="display:none">💡</button>
|
|
||||||
<button id="calibration-tutorial-btn" class="tutorial-trigger-btn" onclick="startCalibrationTutorial()" data-i18n-title="calibration.tutorial.start" title="Start tutorial">?</button>
|
<button id="calibration-tutorial-btn" class="tutorial-trigger-btn" onclick="startCalibrationTutorial()" data-i18n-title="calibration.tutorial.start" title="Start tutorial">?</button>
|
||||||
<button class="modal-close-btn" onclick="closeCalibrationModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
<button class="modal-close-btn" onclick="closeCalibrationModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -42,6 +41,9 @@
|
|||||||
<label for="cal-border-width" data-i18n="calibration.border_width">Border (px):</label>
|
<label for="cal-border-width" data-i18n="calibration.border_width">Border (px):</label>
|
||||||
<input type="number" id="cal-border-width" min="1" max="100" value="10">
|
<input type="number" id="cal-border-width" min="1" max="100" value="10">
|
||||||
</div>
|
</div>
|
||||||
|
<button id="calibration-overlay-btn" class="calibration-overlay-toggle" onclick="toggleCalibrationOverlay()" data-i18n-title="overlay.button.show" title="Show overlay visualization" style="display:none">
|
||||||
|
💡 <span data-i18n="calibration.overlay_toggle">Overlay</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Edge bars with span controls and LED count inputs -->
|
<!-- Edge bars with span controls and LED count inputs -->
|
||||||
|
|||||||
Reference in New Issue
Block a user