Add EntitySelect/IconSelect UI improvements across modals
- Portal IconSelect popups to document.body with position:fixed to prevent clipping by modal overflow-y:auto - Replace custom scene selectors in automation editor with EntitySelect command-palette pickers (main scene + fallback scene) - Add IconSelect grid for automation deactivation mode (none/revert/fallback) - Add IconSelect grid for automation condition type and match type - Replace mapped zone source dropdowns with EntitySelect pickers - Replace scene target selector with EntityPalette.pick() pattern - Remove effect palette preview bar from CSS editor - Remove sensitivity badge from audio color strip source cards - Clean up unused scene-selector CSS and scene-target-add-row CSS - Add locale keys for all new UI elements across en/ru/zh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
<!-- Advanced Calibration Modal (multimonitor line-based) -->
|
||||
<div id="advanced-calibration-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="advcal-modal-title">
|
||||
<div class="modal-content" style="max-width: 900px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="advcal-modal-title"><svg class="icon" viewBox="0 0 24 24"><path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/></svg> <span data-i18n="calibration.advanced.title">Advanced Calibration</span></h2>
|
||||
<button class="modal-close-btn" onclick="closeAdvancedCalibration()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="advcal-css-id">
|
||||
|
||||
<!-- Two-column layout: canvas + line list -->
|
||||
<div class="advcal-layout">
|
||||
<!-- Left: Canvas showing monitor rectangles with lines -->
|
||||
<div class="advcal-canvas-panel">
|
||||
<canvas id="advcal-canvas" width="560" height="340"></canvas>
|
||||
<div class="advcal-canvas-hint">
|
||||
<small data-i18n="calibration.advanced.canvas_hint">Drag monitors to reposition. Click edges to select lines. Scroll to zoom, drag empty space to pan.</small>
|
||||
<button class="btn-micro" onclick="resetCalibrationView()" title="Reset view" data-i18n-title="calibration.advanced.reset_view">↺</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Line list -->
|
||||
<div class="advcal-lines-panel">
|
||||
<div id="advcal-line-list" class="advcal-line-list">
|
||||
<!-- Line items rendered dynamically -->
|
||||
</div>
|
||||
<div class="advcal-leds-counter"><span id="advcal-total-leds">0</span> LEDs</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selected line properties -->
|
||||
<div id="advcal-line-props" class="advcal-line-props" style="display:none">
|
||||
<h3 style="margin: 0 0 8px; font-size: 0.9em;" data-i18n="calibration.advanced.line_properties">Line Properties</h3>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px;">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-source" data-i18n="calibration.advanced.picture_source">Source:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.picture_source.hint">The picture source (monitor) this line samples from</small>
|
||||
<select id="advcal-line-source" onchange="updateCalibrationLine()"></select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-edge" data-i18n="calibration.advanced.edge">Edge:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.edge.hint">Which screen edge to sample pixels from</small>
|
||||
<select id="advcal-line-edge" onchange="updateCalibrationLine()">
|
||||
<option value="top">Top</option>
|
||||
<option value="right">Right</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
<option value="left">Left</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-leds" data-i18n="calibration.advanced.led_count">LEDs:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.led_count.hint">Number of LEDs mapped to this line</small>
|
||||
<input type="number" id="advcal-line-leds" min="1" max="1500" value="10" onchange="updateCalibrationLine()">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 12px; margin-top: 8px;">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-span-start" data-i18n="calibration.advanced.span_start">Span Start:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.span_start.hint">Where sampling begins along the edge (0 = start, 1 = end). Use to cover only part of an edge.</small>
|
||||
<input type="number" id="advcal-line-span-start" min="0" max="1" step="0.01" value="0" onchange="updateCalibrationLine()">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-span-end" data-i18n="calibration.advanced.span_end">Span End:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.span_end.hint">Where sampling ends along the edge (0 = start, 1 = end). Together with Span Start, defines the active portion.</small>
|
||||
<input type="number" id="advcal-line-span-end" min="0" max="1" step="0.01" value="1" onchange="updateCalibrationLine()">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-line-border-width" data-i18n="calibration.advanced.border_width">Depth (px):</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.advanced.border_width.hint">How many pixels deep from the edge to sample. Larger values capture more of the screen interior.</small>
|
||||
<input type="number" id="advcal-line-border-width" min="1" max="100" value="10" onchange="updateCalibrationLine()">
|
||||
</div>
|
||||
<div class="form-group" style="display:flex; align-items:end; gap:8px;">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="advcal-line-reverse" onchange="updateCalibrationLine()">
|
||||
<span data-i18n="calibration.advanced.reverse">Reverse</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Global strip settings (offset, skip) -->
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin-top: 12px;">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-offset" data-i18n="calibration.offset">LED Offset:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.offset.hint">Distance from physical LED 0 to the start corner (along strip direction)</small>
|
||||
<input type="number" id="advcal-offset" min="0" value="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-skip-start" data-i18n="calibration.skip_start">Skip LEDs (Start):</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.skip_start.hint">Number of LEDs to turn off at the beginning of the strip (0 = none)</small>
|
||||
<input type="number" id="advcal-skip-start" min="0" value="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="advcal-skip-end" data-i18n="calibration.skip_end">Skip LEDs (End):</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="calibration.skip_end.hint">Number of LEDs to turn off at the end of the strip (0 = none)</small>
|
||||
<input type="number" id="advcal-skip-end" min="0" value="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="advcal-error" class="error-message" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeAdvancedCalibration()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveAdvancedCalibration()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,18 +56,11 @@
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label data-i18n="automations.scene">Scene:</label>
|
||||
<label for="automation-scene-id" data-i18n="automations.scene">Scene:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="automations.scene.hint">Scene preset to activate when conditions are met</small>
|
||||
<div id="automation-scene-selector" class="scene-selector">
|
||||
<input type="hidden" id="automation-scene-id">
|
||||
<div class="scene-selector-input-wrap">
|
||||
<input type="text" id="automation-scene-search" class="scene-selector-input" placeholder="Search scenes..." autocomplete="off" data-i18n-placeholder="automations.scene.search_placeholder">
|
||||
<button type="button" class="scene-selector-clear" id="automation-scene-clear" title="Clear">×</button>
|
||||
</div>
|
||||
<div class="scene-selector-dropdown" id="automation-scene-dropdown"></div>
|
||||
</div>
|
||||
<select id="automation-scene-id"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -85,18 +78,11 @@
|
||||
|
||||
<div class="form-group" id="automation-fallback-scene-group" style="display:none">
|
||||
<div class="label-row">
|
||||
<label data-i18n="automations.deactivation_scene">Fallback Scene:</label>
|
||||
<label for="automation-fallback-scene-id" data-i18n="automations.deactivation_scene">Fallback Scene:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="automations.deactivation_scene.hint">Scene to activate when this automation deactivates</small>
|
||||
<div id="automation-fallback-scene-selector" class="scene-selector">
|
||||
<input type="hidden" id="automation-fallback-scene-id">
|
||||
<div class="scene-selector-input-wrap">
|
||||
<input type="text" id="automation-fallback-scene-search" class="scene-selector-input" placeholder="Search scenes..." autocomplete="off" data-i18n-placeholder="automations.scene.search_placeholder">
|
||||
<button type="button" class="scene-selector-clear" id="automation-fallback-scene-clear" title="Clear">×</button>
|
||||
</div>
|
||||
<div class="scene-selector-dropdown" id="automation-fallback-scene-dropdown"></div>
|
||||
</div>
|
||||
<select id="automation-fallback-scene-id"></select>
|
||||
</div>
|
||||
|
||||
<div id="automation-editor-error" class="error-message" style="display: none;"></div>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.type.hint">Picture Source derives colors from a screen capture. Static Color fills all LEDs with one constant color. Gradient distributes a color gradient across all LEDs.</small>
|
||||
<select id="css-editor-type" onchange="onCSSTypeChange()">
|
||||
<option value="picture" data-i18n="color_strip.type.picture">Picture Source</option>
|
||||
<option value="picture_advanced" data-i18n="color_strip.type.picture_advanced">Multi-Monitor</option>
|
||||
<option value="static" data-i18n="color_strip.type.static">Static Color</option>
|
||||
<option value="gradient" data-i18n="color_strip.type.gradient">Gradient</option>
|
||||
<option value="color_cycle" data-i18n="color_strip.type.color_cycle">Color Cycle</option>
|
||||
@@ -36,7 +37,7 @@
|
||||
|
||||
<!-- Picture-source-specific fields -->
|
||||
<div id="css-editor-picture-section">
|
||||
<div class="form-group">
|
||||
<div id="css-editor-picture-source-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-picture-source" data-i18n="color_strip.picture_source">Picture Source:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
@@ -211,7 +212,6 @@
|
||||
<option value="aurora" data-i18n="color_strip.effect.aurora">Aurora</option>
|
||||
</select>
|
||||
<small id="css-editor-effect-type-desc" class="field-desc"></small>
|
||||
<div id="css-editor-effect-preview" class="effect-palette-preview"></div>
|
||||
</div>
|
||||
|
||||
<div id="css-editor-effect-palette-group" class="form-group">
|
||||
@@ -220,7 +220,7 @@
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.effect.palette.hint">Color palette used by the effect.</small>
|
||||
<select id="css-editor-effect-palette" onchange="updateEffectPreview()">
|
||||
<select id="css-editor-effect-palette">
|
||||
<option value="fire" data-i18n="color_strip.palette.fire">Fire</option>
|
||||
<option value="ocean" data-i18n="color_strip.palette.ocean">Ocean</option>
|
||||
<option value="lava" data-i18n="color_strip.palette.lava">Lava</option>
|
||||
|
||||
@@ -33,11 +33,8 @@
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="scenes.targets.hint">Select which targets to include in this scene snapshot</small>
|
||||
<div class="scene-target-add-row">
|
||||
<select id="scene-target-select"></select>
|
||||
<button type="button" class="btn btn-sm btn-secondary" onclick="addSceneTarget()">+</button>
|
||||
</div>
|
||||
<div id="scene-target-list" class="scene-target-list"></div>
|
||||
<button type="button" id="scene-target-add-btn" class="btn btn-sm btn-secondary" onclick="addSceneTarget()" style="margin-top: 6px;">+ <span data-i18n="scenes.targets.add">Add Target</span></button>
|
||||
</div>
|
||||
|
||||
<div id="scene-preset-editor-error" class="error-message" style="display: none;"></div>
|
||||
|
||||
Reference in New Issue
Block a user