CSS: add StaticColorStripSource type with auto-sized LED count
Introduces a new 'static' source type that fills all device LEDs with a single constant RGB color — no screen capture or processing required. - StaticColorStripSource storage model (color + led_count=0 auto-size) - StaticColorStripStream: no background thread, configure() sizes to device LED count at processor start; hot-updates preserve runtime size - ColorStripStreamManager dispatches static sources (no LiveStream needed) - WledTargetProcessor calls stream.configure(device_led_count) on start - API schemas/routes: source_type Literal["picture","static"]; color field; overlay/calibration-test endpoints return 400 for static - Frontend: type selector modal, color picker, type-aware card rendering (🎨 icon + color swatch), LED count field hidden for static type - Locale keys: color_strip.type, color_strip.static_color (en + ru) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,95 +16,123 @@
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-picture-source" data-i18n="color_strip.picture_source">Picture Source:</label>
|
||||
<label for="css-editor-type" data-i18n="color_strip.type">Type:</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.picture_source.hint">Which screen capture source to use as input for LED color calculation</small>
|
||||
<select id="css-editor-picture-source"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-fps">
|
||||
<span data-i18n="color_strip.fps">Target FPS:</span>
|
||||
<span id="css-editor-fps-value">30</span>
|
||||
</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.fps.hint">Target frames per second for LED color updates (10-90)</small>
|
||||
<div class="slider-row">
|
||||
<input type="range" id="css-editor-fps" min="10" max="90" value="30" oninput="document.getElementById('css-editor-fps-value').textContent = this.value">
|
||||
<span class="slider-value">fps</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-interpolation" data-i18n="color_strip.interpolation">Color Mode:</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.interpolation.hint">How to calculate LED color from sampled border pixels</small>
|
||||
<select id="css-editor-interpolation">
|
||||
<option value="average" data-i18n="color_strip.interpolation.average">Average</option>
|
||||
<option value="median" data-i18n="color_strip.interpolation.median">Median</option>
|
||||
<option value="dominant" data-i18n="color_strip.interpolation.dominant">Dominant</option>
|
||||
<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.</small>
|
||||
<select id="css-editor-type" onchange="onCSSTypeChange()">
|
||||
<option value="picture" data-i18n="color_strip.type.picture">Picture Source</option>
|
||||
<option value="static" data-i18n="color_strip.type.static">Static Color</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-smoothing">
|
||||
<span data-i18n="color_strip.smoothing">Smoothing:</span>
|
||||
<span id="css-editor-smoothing-value">0.30</span>
|
||||
</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
<!-- Picture-source-specific fields -->
|
||||
<div id="css-editor-picture-section">
|
||||
<div 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>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.picture_source.hint">Which screen capture source to use as input for LED color calculation</small>
|
||||
<select id="css-editor-picture-source"></select>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.smoothing.hint">Temporal blending between frames (0=none, 1=full). Reduces flicker.</small>
|
||||
<input type="range" id="css-editor-smoothing" min="0.0" max="1.0" step="0.05" value="0.3" oninput="document.getElementById('css-editor-smoothing-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-fps">
|
||||
<span data-i18n="color_strip.fps">Target FPS:</span>
|
||||
<span id="css-editor-fps-value">30</span>
|
||||
</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.fps.hint">Target frames per second for LED color updates (10-90)</small>
|
||||
<div class="slider-row">
|
||||
<input type="range" id="css-editor-fps" min="10" max="90" value="30" oninput="document.getElementById('css-editor-fps-value').textContent = this.value">
|
||||
<span class="slider-value">fps</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-interpolation" data-i18n="color_strip.interpolation">Color Mode:</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.interpolation.hint">How to calculate LED color from sampled border pixels</small>
|
||||
<select id="css-editor-interpolation">
|
||||
<option value="average" data-i18n="color_strip.interpolation.average">Average</option>
|
||||
<option value="median" data-i18n="color_strip.interpolation.median">Median</option>
|
||||
<option value="dominant" data-i18n="color_strip.interpolation.dominant">Dominant</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-smoothing">
|
||||
<span data-i18n="color_strip.smoothing">Smoothing:</span>
|
||||
<span id="css-editor-smoothing-value">0.30</span>
|
||||
</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.smoothing.hint">Temporal blending between frames (0=none, 1=full). Reduces flicker.</small>
|
||||
<input type="range" id="css-editor-smoothing" min="0.0" max="1.0" step="0.05" value="0.3" oninput="document.getElementById('css-editor-smoothing-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<details class="form-collapse">
|
||||
<summary data-i18n="color_strip.color_corrections">Color Corrections</summary>
|
||||
<div class="form-collapse-body">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-brightness">
|
||||
<span data-i18n="color_strip.brightness">Brightness:</span>
|
||||
<span id="css-editor-brightness-value">1.00</span>
|
||||
</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.brightness.hint">Output brightness multiplier (0=off, 1=unchanged, 2=double). Applied after color extraction.</small>
|
||||
<input type="range" id="css-editor-brightness" min="0.0" max="2.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-brightness-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-saturation">
|
||||
<span data-i18n="color_strip.saturation">Saturation:</span>
|
||||
<span id="css-editor-saturation-value">1.00</span>
|
||||
</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.saturation.hint">Color saturation (0=grayscale, 1=unchanged, 2=double saturation)</small>
|
||||
<input type="range" id="css-editor-saturation" min="0.0" max="2.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-saturation-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-gamma">
|
||||
<span data-i18n="color_strip.gamma">Gamma:</span>
|
||||
<span id="css-editor-gamma-value">1.00</span>
|
||||
</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.gamma.hint">Gamma correction (1=none, <1=brighter midtones, >1=darker midtones)</small>
|
||||
<input type="range" id="css-editor-gamma" min="0.1" max="3.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-gamma-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<details class="form-collapse">
|
||||
<summary data-i18n="color_strip.color_corrections">Color Corrections</summary>
|
||||
<div class="form-collapse-body">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-brightness">
|
||||
<span data-i18n="color_strip.brightness">Brightness:</span>
|
||||
<span id="css-editor-brightness-value">1.00</span>
|
||||
</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.brightness.hint">Output brightness multiplier (0=off, 1=unchanged, 2=double). Applied after color extraction.</small>
|
||||
<input type="range" id="css-editor-brightness" min="0.0" max="2.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-brightness-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-saturation">
|
||||
<span data-i18n="color_strip.saturation">Saturation:</span>
|
||||
<span id="css-editor-saturation-value">1.00</span>
|
||||
</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.saturation.hint">Color saturation (0=grayscale, 1=unchanged, 2=double saturation)</small>
|
||||
<input type="range" id="css-editor-saturation" min="0.0" max="2.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-saturation-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-gamma">
|
||||
<span data-i18n="color_strip.gamma">Gamma:</span>
|
||||
<span id="css-editor-gamma-value">1.00</span>
|
||||
</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.gamma.hint">Gamma correction (1=none, <1=brighter midtones, >1=darker midtones)</small>
|
||||
<input type="range" id="css-editor-gamma" min="0.1" max="3.0" step="0.05" value="1.0" oninput="document.getElementById('css-editor-gamma-value').textContent = parseFloat(this.value).toFixed(2)">
|
||||
<!-- Static-color-specific fields -->
|
||||
<div id="css-editor-static-section" style="display:none">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-color" data-i18n="color_strip.static_color">Color:</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.static_color.hint">The solid color that will be sent to all LEDs on the strip.</small>
|
||||
<input type="color" id="css-editor-color" value="#ffffff">
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<!-- LED count — picture type only (auto-sized from device for static) -->
|
||||
<div id="css-editor-led-count-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-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>
|
||||
|
||||
Reference in New Issue
Block a user