Live KC test WS, sync clock fix, device card perf, camera icons, tab indicator

Key Colors test:
- New WS endpoint for live KC target test streaming (replaces REST polling)
- Auto-connect on lightbox open, auto-disconnect on close
- Uses same FPS/preview_width as CSS source test (no separate controls)
- Removed FPS selector, start/stop toggle, and updateAutoRefreshButton

Device cards:
- Fix full re-render on every poll caused by relative "Last seen" time in HTML
- Last seen label now patched in-place via data attribute (like FPS metrics)
- Remove overlay visualization button from LED target cards

Sync clocks:
- Fix card not updating start/stop icon: invalidate cache before reload

Other:
- Tab indicator respects bg-anim toggle (hidden when dynamic background off)
- Camera backend icon grid uses SVG icons instead of emoji
- Frontend context rule: no emoji in IconSelect items

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-17 02:03:07 +03:00
parent bcba5f33fc
commit 00c9ad3a86
16 changed files with 430 additions and 85 deletions

View File

@@ -56,6 +56,9 @@ import {
ICON_AUDIO_TEMPLATE, ICON_MONITOR, ICON_WRENCH, ICON_RADIO,
ICON_CAPTURE_TEMPLATE, ICON_PP_TEMPLATE, ICON_CSPT, ICON_HELP,
} from '../core/icons.js';
import * as P from '../core/icon-paths.js';
const _icon = (d) => `<svg class="icon" viewBox="0 0 24 24">${d}</svg>`;
import { wrapCard } from '../core/card-colors.js';
import { TagInput, renderTagChips } from '../core/tag-input.js';
import { IconSelect } from '../core/icon-select.js';
@@ -407,6 +410,19 @@ export async function onEngineChange() {
camera_backend: ['auto', 'dshow', 'msmf', 'v4l2'],
};
// IconSelect definitions for specific config keys
const CONFIG_ICON_SELECT = {
camera_backend: {
columns: 2,
items: [
{ value: 'auto', icon: _icon(P.refreshCw), label: 'Auto', desc: t('templates.config.camera_backend.auto') },
{ value: 'dshow', icon: _icon(P.camera), label: 'DShow', desc: t('templates.config.camera_backend.dshow') },
{ value: 'msmf', icon: _icon(P.film), label: 'MSMF', desc: t('templates.config.camera_backend.msmf') },
{ value: 'v4l2', icon: _icon(P.monitor), label: 'V4L2', desc: t('templates.config.camera_backend.v4l2') },
],
},
};
if (Object.keys(defaultConfig).length === 0) {
configSection.style.display = 'none';
return;
@@ -436,6 +452,12 @@ export async function onEngineChange() {
});
gridHtml += '</div>';
configFields.innerHTML = gridHtml;
// Apply IconSelect to known config selects
for (const [key, cfg] of Object.entries(CONFIG_ICON_SELECT)) {
const sel = document.getElementById(`config-${key}`);
if (sel) new IconSelect({ target: sel, items: cfg.items, columns: cfg.columns });
}
}
configSection.style.display = 'block';