Apply IconSelect to all type selectors across the app

- Value source type (5 types, static icons)
- Device type (7 types, new wifi/usb icon paths + device icon map)
- Capture engine (dynamic from API, uses getEngineIcon)
- Audio engine (dynamic from API, new getAudioEngineIcon)
- Add i18n description keys for value source and device types
- Fix trigger button styling to match native input height

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 23:57:37 +03:00
parent d95eb683e1
commit b4d89e271d
9 changed files with 153 additions and 4 deletions

View File

@@ -41,13 +41,14 @@ import { updateSubTabHash } from './tabs.js';
import { createValueSourceCard } from './value-sources.js';
import { createSyncClockCard } from './sync-clocks.js';
import {
getEngineIcon, getPictureSourceIcon, getAudioSourceIcon,
getEngineIcon, getAudioEngineIcon, getPictureSourceIcon, getAudioSourceIcon,
ICON_TEMPLATE, ICON_CLONE, ICON_EDIT, ICON_TEST, ICON_LINK_SOURCE,
ICON_FPS, ICON_WEB, ICON_VALUE_SOURCE, ICON_CLOCK, ICON_AUDIO_LOOPBACK, ICON_AUDIO_INPUT,
ICON_AUDIO_TEMPLATE, ICON_MONITOR, ICON_WRENCH, ICON_RADIO,
ICON_CAPTURE_TEMPLATE, ICON_PP_TEMPLATE, ICON_HELP,
} from '../core/icons.js';
import { wrapCard } from '../core/card-colors.js';
import { IconSelect } from '../core/icon-select.js';
// ── Card section instances ──
const csRawStreams = new CardSection('raw-streams', { titleKey: 'streams.section.streams', gridClass: 'templates-grid', addCardOnclick: "showAddStreamModal('raw')", keyAttr: 'data-stream-id' });
@@ -296,14 +297,25 @@ async function loadAvailableEngines() {
const firstAvailable = availableEngines.find(e => e.available);
if (firstAvailable) select.value = firstAvailable.type;
}
// Update icon-grid selector with dynamic engine list
const items = availableEngines
.filter(e => e.available)
.map(e => ({ value: e.type, icon: getEngineIcon(e.type), label: e.name, desc: '' }));
if (_engineIconSelect) { _engineIconSelect.updateItems(items); }
else { _engineIconSelect = new IconSelect({ target: select, items, columns: 2 }); }
_engineIconSelect.setValue(select.value);
} catch (error) {
console.error('Error loading engines:', error);
showToast(t('templates.error.engines') + ': ' + error.message, 'error');
}
}
let _engineIconSelect = null;
export async function onEngineChange() {
const engineType = document.getElementById('template-engine').value;
if (_engineIconSelect) _engineIconSelect.setValue(engineType);
const configSection = document.getElementById('engine-config-section');
const configFields = document.getElementById('engine-config-fields');
@@ -667,14 +679,25 @@ async function loadAvailableAudioEngines() {
const firstAvailable = availableAudioEngines.find(e => e.available);
if (firstAvailable) select.value = firstAvailable.type;
}
// Update icon-grid selector with dynamic engine list
const items = availableAudioEngines
.filter(e => e.available)
.map(e => ({ value: e.type, icon: getAudioEngineIcon(e.type), label: e.type.toUpperCase(), desc: '' }));
if (_audioEngineIconSelect) { _audioEngineIconSelect.updateItems(items); }
else { _audioEngineIconSelect = new IconSelect({ target: select, items, columns: 2 }); }
_audioEngineIconSelect.setValue(select.value);
} catch (error) {
console.error('Error loading audio engines:', error);
showToast(t('audio_template.error.engines') + ': ' + error.message, 'error');
}
}
let _audioEngineIconSelect = null;
export async function onAudioEngineChange() {
const engineType = document.getElementById('audio-template-engine').value;
if (_audioEngineIconSelect) _audioEngineIconSelect.setValue(engineType);
const configSection = document.getElementById('audio-engine-config-section');
const configFields = document.getElementById('audio-engine-config-fields');