refactor: key colors targets → CSS source type, HA target improvements
Lint & Test / test (push) Successful in 1m26s

Key Colors refactor:
- New `key_colors` CSS source type with inline rectangles
- KeyColorsColorStripStream: extracts N colors from screen regions
- CSS editor: EntitySelect for picture source, IconSelect for color mode
- Configure Regions button on card opens pattern canvas editor
- Live WS preview at 5 FPS with rectangle overlay + color swatches
- Removed KC target type, pattern template entity, and related API routes
- Removed KC/pattern template sections from Targets tab

HA light target improvements:
- Update rate, transition, mappings, brightness VS now editable via PUT
- Card crosslinks for HA source, CSS source, brightness VS
- HA connection status icon, text metrics (Hz, uptime)
- Brightness value source selector in editor
This commit is contained in:
2026-03-28 15:28:22 +03:00
parent 89d1b13854
commit 3e6760f726
46 changed files with 2707 additions and 789 deletions
@@ -191,7 +191,6 @@
{% include 'modals/gradient-editor.html' %}
{% include 'modals/test-css-source.html' %}
{% include 'modals/notification-history.html' %}
{% include 'modals/kc-editor.html' %}
{% include 'modals/pattern-template.html' %}
{% include 'modals/api-key.html' %}
{% include 'modals/confirm.html' %}
@@ -37,6 +37,7 @@
<option value="candlelight" data-i18n="color_strip.type.candlelight">Candlelight</option>
<option value="weather" data-i18n="color_strip.type.weather">Weather</option>
<option value="processed" data-i18n="color_strip.type.processed">Processed</option>
<option value="key_colors" data-i18n="color_strip.type.key_colors">Key Colors</option>
</select>
</div>
@@ -676,6 +677,40 @@
</div>
</div>
<!-- Key Colors section -->
<div id="css-editor-key-colors-section" style="display:none">
<div class="form-group">
<div class="label-row">
<label for="css-editor-kc-picture-source" data-i18n="color_strip.key_colors.picture_source">Picture Source:</label>
</div>
<select id="css-editor-kc-picture-source"></select>
</div>
<div class="form-group">
<div class="label-row">
<label for="css-editor-kc-interpolation" data-i18n="color_strip.key_colors.interpolation">Color Mode:</label>
</div>
<select id="css-editor-kc-interpolation">
<option value="average">Average</option>
<option value="median">Median</option>
<option value="dominant">Dominant</option>
</select>
</div>
<div class="form-group">
<div class="label-row">
<label for="css-editor-kc-smoothing"><span data-i18n="color_strip.key_colors.smoothing">Smoothing:</span> <span id="css-editor-kc-smoothing-val">0.30</span></label>
</div>
<input type="range" id="css-editor-kc-smoothing" min="0" max="1" step="0.05" value="0.3"
oninput="document.getElementById('css-editor-kc-smoothing-val').textContent = parseFloat(this.value).toFixed(2)">
</div>
<div class="form-group">
<div class="label-row">
<label for="css-editor-kc-brightness"><span data-i18n="color_strip.key_colors.brightness">Brightness:</span> <span id="css-editor-kc-brightness-val">1.00</span></label>
</div>
<input type="range" id="css-editor-kc-brightness" min="0" max="1" step="0.05" value="1.0"
oninput="document.getElementById('css-editor-kc-brightness-val').textContent = parseFloat(this.value).toFixed(2)">
</div>
</div>
<!-- Shared LED count field -->
<div id="css-editor-led-count-group" class="form-group">
<div class="label-row">
@@ -64,14 +64,27 @@
oninput="document.getElementById('ha-light-editor-transition-display').textContent = parseFloat(this.value).toFixed(1)">
</div>
<!-- Brightness Value Source -->
<div class="form-group">
<div class="label-row">
<label for="ha-light-editor-brightness-vs" data-i18n="targets.brightness_vs">Brightness Source:</label>
</div>
<select id="ha-light-editor-brightness-vs">
<option value="">None</option>
</select>
</div>
<!-- Light Mappings -->
<div class="form-group">
<div class="label-row">
<label data-i18n="ha_light.mappings">Light Mappings:</label>
<button type="button" class="btn btn-sm btn-secondary" onclick="addHALightMapping()" data-i18n-title="ha_light.mappings.add">+</button>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
</div>
<small class="input-hint" data-i18n="ha_light.mappings.hint">Map LED ranges to HA light entities. Each mapping averages the LED segment to a single color.</small>
<small class="input-hint" style="display:none" data-i18n="ha_light.mappings.hint">Map LED ranges to HA light entities. Each mapping averages the LED segment to a single color.</small>
<div id="ha-light-mappings-list"></div>
<button type="button" class="btn btn-sm btn-secondary" onclick="addHALightMapping()" style="margin-top: 4px;">
+ <span data-i18n="ha_light.mappings.add">Add Mapping</span>
</button>
</div>
<!-- Description -->
@@ -9,7 +9,7 @@
<form id="pattern-template-form">
<input type="hidden" id="pattern-template-id">
<div class="form-group">
<div id="pattern-name-group" class="form-group">
<div class="label-row">
<label for="pattern-template-name" data-i18n="pattern.name">Template Name:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
@@ -19,7 +19,7 @@
<div id="pattern-tags-container"></div>
</div>
<div class="form-group">
<div id="pattern-desc-group" class="form-group">
<div class="label-row">
<label for="pattern-template-description" data-i18n="pattern.description_label">Description (optional):</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>