Unify value source icons across dropdowns and card badges

Extract getValueSourceIcon() into value-sources.js and use it for
brightness source dropdowns and card badges in both LED and KC targets.
Icons now match value source cards: 📊 static, 🔄 animated, 🎵 audio,
🕐 adaptive_time, 🌤️ adaptive_scene.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 01:41:13 +03:00
parent 16f29bee30
commit e0e744095e
3 changed files with 16 additions and 6 deletions

View File

@@ -14,6 +14,7 @@ import { API_BASE, getHeaders, fetchWithAuth, escapeHtml } from '../core/api.js'
import { t } from '../core/i18n.js';
import { lockBody, showToast, showConfirm, formatUptime } from '../core/ui.js';
import { Modal } from '../core/modal.js';
import { getValueSourceIcon } from './value-sources.js';
class KCEditorModal extends Modal {
constructor() {
@@ -81,7 +82,7 @@ export function createKCTargetCard(target, sourceMap, patternTemplateMap, valueS
<span class="stream-card-prop" title="${t('kc.pattern_template')}">📄 ${escapeHtml(patternName)}</span>
<span class="stream-card-prop">▭ ${rectCount} rect${rectCount !== 1 ? 's' : ''}</span>
<span class="stream-card-prop" title="${t('kc.fps')}">⚡ ${kcSettings.fps ?? 10}</span>
${bvs ? `<span class="stream-card-prop stream-card-prop-full" title="${t('targets.brightness_vs')}">🔆 ${escapeHtml(bvs.name)}</span>` : ''}
${bvs ? `<span class="stream-card-prop stream-card-prop-full" title="${t('targets.brightness_vs')}">${getValueSourceIcon(bvs.source_type)} ${escapeHtml(bvs.name)}</span>` : ''}
</div>
<div class="brightness-control" data-kc-brightness-wrap="${target.id}">
<input type="range" class="brightness-slider" min="0" max="255"
@@ -363,9 +364,10 @@ function _populateKCBrightnessVsDropdown(selectedId = '') {
// Keep the first "None" option, remove the rest
while (sel.options.length > 1) sel.remove(1);
_cachedValueSources.forEach(vs => {
const icon = getValueSourceIcon(vs.source_type);
const opt = document.createElement('option');
opt.value = vs.id;
opt.textContent = `🔢 ${vs.name}`;
opt.textContent = `${icon} ${vs.name}`;
sel.appendChild(opt);
});
sel.value = selectedId || '';

View File

@@ -17,6 +17,7 @@ import { Modal } from '../core/modal.js';
import { createDeviceCard, attachDeviceListeners, fetchDeviceBrightness, _computeMaxFps } from './devices.js';
import { createKCTargetCard, connectKCWebSocket, disconnectKCWebSocket } from './kc-targets.js';
import { createColorStripCard } from './color-strips.js';
import { getValueSourceIcon } from './value-sources.js';
import { CardSection } from '../core/card-sections.js';
// createPatternTemplateCard is imported via window.* to avoid circular deps
@@ -184,7 +185,8 @@ function _populateBrightnessVsDropdown(selectedId = '') {
const select = document.getElementById('target-editor-brightness-vs');
let html = `<option value="">${t('targets.brightness_vs.none')}</option>`;
_cachedValueSources.forEach(vs => {
html += `<option value="${vs.id}"${vs.id === selectedId ? ' selected' : ''}>🔢 ${escapeHtml(vs.name)}</option>`;
const icon = getValueSourceIcon(vs.source_type);
html += `<option value="${vs.id}"${vs.id === selectedId ? ' selected' : ''}>${icon} ${escapeHtml(vs.name)}</option>`;
});
select.innerHTML = html;
}
@@ -677,7 +679,7 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
<span class="stream-card-prop" title="${t('targets.device')}">💡 ${escapeHtml(deviceName)}</span>
<span class="stream-card-prop" title="${t('targets.fps')}">⚡ ${target.fps || 30}</span>
<span class="stream-card-prop stream-card-prop-full" title="${t('targets.color_strip_source')}">🎞️ ${cssSummary}</span>
${bvs ? `<span class="stream-card-prop stream-card-prop-full" title="${t('targets.brightness_vs')}">🔆 ${escapeHtml(bvs.name)}</span>` : ''}
${bvs ? `<span class="stream-card-prop stream-card-prop-full" title="${t('targets.brightness_vs')}">${getValueSourceIcon(bvs.source_type)} ${escapeHtml(bvs.name)}</span>` : ''}
</div>
<div class="card-content">
${isProcessing ? `

View File

@@ -255,9 +255,15 @@ export async function deleteValueSource(sourceId) {
// ── Card rendering (used by streams.js) ───────────────────────
const _vsTypeIcons = { static: '📊', animated: '🔄', audio: '🎵', adaptive_time: '🕐', adaptive_scene: '🌤️' };
/** Return the emoji icon for a given value source type. */
export function getValueSourceIcon(sourceType) {
return _vsTypeIcons[sourceType] || '🎚️';
}
export function createValueSourceCard(src) {
const typeIcons = { static: '📊', animated: '🔄', audio: '🎵', adaptive_time: '🕐', adaptive_scene: '🌤️' };
const icon = typeIcons[src.source_type] || '🎚️';
const icon = getValueSourceIcon(src.source_type);
let propsHtml = '';
if (src.source_type === 'static') {