- Replace all emoji characters across WebUI with inline Lucide SVG icons for cross-platform consistency (icon paths in icon-paths.js) - Add accent color picker popover with 9 preset colors + custom picker, persisted to localStorage, updates all CSS custom properties - Remove subtab separator line for cleaner look - Color badge icons with accent color for visual pop - Remove processing badge from target cards - Fix hardcoded #4CAF50 in FPS labels and active badges to use CSS vars - Replace CSS content emoji (▶) with pure CSS triangle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
168 lines
12 KiB
HTML
168 lines
12 KiB
HTML
<!-- Calibration Modal -->
|
|
<div id="calibration-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="calibration-modal-title">
|
|
<div class="modal-content" style="max-width: 700px;">
|
|
<div class="modal-header">
|
|
<h2 id="calibration-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.title">LED Calibration</span></h2>
|
|
<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>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" id="calibration-device-id">
|
|
<input type="hidden" id="calibration-css-id">
|
|
<!-- Device picker shown in CSS calibration mode for edge testing -->
|
|
<div id="calibration-css-test-group" class="form-group" style="display:none; margin-bottom: 12px; padding: 0 4px;">
|
|
<div class="label-row">
|
|
<label for="calibration-test-device" data-i18n="color_strip.test_device">Test on Device:</label>
|
|
<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.test_device.hint">Select a device to send test pixels to when clicking edge toggles</small>
|
|
<select id="calibration-test-device"></select>
|
|
</div>
|
|
<!-- LED count input (CSS calibration mode only) -->
|
|
<div id="cal-css-led-count-group" class="form-group" style="display:none; margin-bottom: 12px; padding: 0 4px;">
|
|
<div class="label-row">
|
|
<label for="cal-css-led-count" data-i18n="color_strip.led_count">LED Count:</label>
|
|
<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.led_count.hint">Total number of LEDs on the physical strip. Set to 0 to use the sum from calibration. If your strip has LEDs behind the TV that are not mapped to screen edges, set the exact count here and they will be filled with black.</small>
|
|
<input type="number" id="cal-css-led-count" min="0" max="1500" step="1" value="0" oninput="updateCalibrationPreview()">
|
|
</div>
|
|
|
|
<!-- Interactive Preview with integrated LED inputs and test toggles -->
|
|
<div style="margin-bottom: 12px; padding: 0 24px;">
|
|
<div class="calibration-preview">
|
|
<!-- Screen with direction toggle, total LEDs, and offset -->
|
|
<div class="preview-screen">
|
|
<button type="button" class="direction-toggle" onclick="toggleDirection()" title="Toggle direction">
|
|
<span id="direction-icon"><svg class="icon" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/></svg></span> <span id="direction-label">CW</span>
|
|
</button>
|
|
<div class="preview-screen-total" onclick="toggleEdgeInputs()" title="Toggle edge LED inputs"><span id="cal-total-leds-inline">0</span> / <span id="cal-device-led-count-inline">0</span></div>
|
|
<div class="preview-screen-border-width">
|
|
<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">
|
|
</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">
|
|
<svg class="icon" viewBox="0 0 24 24"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg> <span data-i18n="calibration.overlay_toggle">Overlay</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Edge bars with span controls and LED count inputs -->
|
|
<div class="preview-edge edge-top">
|
|
<div class="edge-span-bar" data-edge="top">
|
|
<div class="edge-span-handle edge-span-handle-start" data-edge="top" data-handle="start"></div>
|
|
<div class="edge-span-handle edge-span-handle-end" data-edge="top" data-handle="end"></div>
|
|
</div>
|
|
<input type="number" id="cal-top-leds" class="edge-led-input" min="0" value="0"
|
|
oninput="updateCalibrationPreview()">
|
|
</div>
|
|
<div class="preview-edge edge-right">
|
|
<div class="edge-span-bar" data-edge="right">
|
|
<div class="edge-span-handle edge-span-handle-start" data-edge="right" data-handle="start"></div>
|
|
<div class="edge-span-handle edge-span-handle-end" data-edge="right" data-handle="end"></div>
|
|
</div>
|
|
<input type="number" id="cal-right-leds" class="edge-led-input" min="0" value="0"
|
|
oninput="updateCalibrationPreview()">
|
|
</div>
|
|
<div class="preview-edge edge-bottom">
|
|
<div class="edge-span-bar" data-edge="bottom">
|
|
<div class="edge-span-handle edge-span-handle-start" data-edge="bottom" data-handle="start"></div>
|
|
<div class="edge-span-handle edge-span-handle-end" data-edge="bottom" data-handle="end"></div>
|
|
</div>
|
|
<input type="number" id="cal-bottom-leds" class="edge-led-input" min="0" value="0"
|
|
oninput="updateCalibrationPreview()">
|
|
</div>
|
|
<div class="preview-edge edge-left">
|
|
<div class="edge-span-bar" data-edge="left">
|
|
<div class="edge-span-handle edge-span-handle-start" data-edge="left" data-handle="start"></div>
|
|
<div class="edge-span-handle edge-span-handle-end" data-edge="left" data-handle="end"></div>
|
|
</div>
|
|
<input type="number" id="cal-left-leds" class="edge-led-input" min="0" value="0"
|
|
oninput="updateCalibrationPreview()">
|
|
</div>
|
|
|
|
<!-- Edge test toggle zones (outside container border, in tick area) -->
|
|
<div class="edge-toggle toggle-top" onclick="toggleTestEdge('top')"></div>
|
|
<div class="edge-toggle toggle-right" onclick="toggleTestEdge('right')"></div>
|
|
<div class="edge-toggle toggle-bottom" onclick="toggleTestEdge('bottom')"></div>
|
|
<div class="edge-toggle toggle-left" onclick="toggleTestEdge('left')"></div>
|
|
|
|
<!-- Corner start position buttons -->
|
|
<div class="preview-corner corner-top-left" onclick="setStartPosition('top_left')">●</div>
|
|
<div class="preview-corner corner-top-right" onclick="setStartPosition('top_right')">●</div>
|
|
<div class="preview-corner corner-bottom-left" onclick="setStartPosition('bottom_left')">●</div>
|
|
<div class="preview-corner corner-bottom-right" onclick="setStartPosition('bottom_right')">●</div>
|
|
|
|
<!-- Canvas overlay for ticks, arrows, start label -->
|
|
<canvas id="calibration-preview-canvas"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hidden selects (used by saveCalibration) -->
|
|
<div style="display: none;">
|
|
<select id="cal-start-position">
|
|
<option value="bottom_left">Bottom Left</option>
|
|
<option value="bottom_right">Bottom Right</option>
|
|
<option value="top_left">Top Left</option>
|
|
<option value="top_right">Top Right</option>
|
|
</select>
|
|
<select id="cal-layout">
|
|
<option value="clockwise">Clockwise</option>
|
|
<option value="counterclockwise">Counterclockwise</option>
|
|
</select>
|
|
</div>
|
|
|
|
|
|
<!-- Offset & Skip LEDs -->
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; padding: 0 24px;">
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="cal-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="cal-offset" min="0" value="0" oninput="updateOffsetSkipLock(); updateCalibrationPreview()">
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="cal-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="cal-skip-start" min="0" value="0" oninput="updateOffsetSkipLock(); updateCalibrationPreview()">
|
|
</div>
|
|
<div class="form-group">
|
|
<div class="label-row">
|
|
<label for="cal-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="cal-skip-end" min="0" value="0" oninput="updateOffsetSkipLock(); updateCalibrationPreview()">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tutorial Overlay -->
|
|
<div id="tutorial-overlay" class="tutorial-overlay">
|
|
<div class="tutorial-backdrop"></div>
|
|
<div class="tutorial-ring"></div>
|
|
<div class="tutorial-tooltip">
|
|
<div class="tutorial-tooltip-header">
|
|
<span class="tutorial-step-counter"></span>
|
|
<button class="tutorial-close-btn" onclick="closeTutorial()">×</button>
|
|
</div>
|
|
<p class="tutorial-tooltip-text"></p>
|
|
<div class="tutorial-tooltip-nav">
|
|
<button class="tutorial-prev-btn" onclick="tutorialPrev()">←</button>
|
|
<button class="tutorial-next-btn" onclick="tutorialNext()">→</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="calibration-error" class="error-message" style="display: none;"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-icon btn-secondary" onclick="closeCalibrationModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
|
<button class="btn btn-icon btn-primary" onclick="saveCalibration()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
|
</div>
|
|
</div>
|
|
</div>
|