Replace all emoji icons with Lucide SVGs, add accent color picker
- Replace all emoji characters across WebUI with inline Lucide SVG icons for cross-platform consistency (icon paths in icon-paths.js) - Add accent color picker popover with 9 preset colors + custom picker, persisted to localStorage, updates all CSS custom properties - Remove subtab separator line for cleaner look - Color badge icons with accent color for visual pop - Remove processing badge from target cards - Fix hardcoded #4CAF50 in FPS labels and active badges to use CSS vars - Replace CSS content emoji (▶) with pure CSS triangle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,8 @@ import {
|
||||
getEngineIcon, getPictureSourceIcon, getAudioSourceIcon,
|
||||
ICON_TEMPLATE, ICON_CLONE, ICON_EDIT, ICON_TEST, ICON_LINK_SOURCE,
|
||||
ICON_FPS, ICON_WEB, ICON_VALUE_SOURCE, ICON_AUDIO_LOOPBACK, ICON_AUDIO_INPUT,
|
||||
ICON_AUDIO_TEMPLATE,
|
||||
ICON_AUDIO_TEMPLATE, ICON_MONITOR, ICON_WRENCH, ICON_RADIO,
|
||||
ICON_CAPTURE_TEMPLATE, ICON_PP_TEMPLATE, ICON_HELP,
|
||||
} from '../core/icons.js';
|
||||
|
||||
// ── Card section instances ──
|
||||
@@ -166,7 +167,7 @@ async function loadCaptureTemplates() {
|
||||
|
||||
export async function showAddTemplateModal(cloneData = null) {
|
||||
setCurrentEditingTemplateId(null);
|
||||
document.getElementById('template-modal-title').textContent = t('templates.add');
|
||||
document.getElementById('template-modal-title').innerHTML = `${ICON_CAPTURE_TEMPLATE} ${t('templates.add')}`;
|
||||
document.getElementById('template-form').reset();
|
||||
document.getElementById('template-id').value = '';
|
||||
document.getElementById('engine-config-section').style.display = 'none';
|
||||
@@ -197,7 +198,7 @@ export async function editTemplate(templateId) {
|
||||
const template = await response.json();
|
||||
|
||||
setCurrentEditingTemplateId(templateId);
|
||||
document.getElementById('template-modal-title').textContent = t('templates.edit');
|
||||
document.getElementById('template-modal-title').innerHTML = `${ICON_CAPTURE_TEMPLATE} ${t('templates.edit')}`;
|
||||
document.getElementById('template-id').value = templateId;
|
||||
document.getElementById('template-name').value = template.name;
|
||||
document.getElementById('template-description').value = template.description || '';
|
||||
@@ -751,7 +752,7 @@ async function loadAudioTemplates() {
|
||||
|
||||
export async function showAddAudioTemplateModal(cloneData = null) {
|
||||
setCurrentEditingAudioTemplateId(null);
|
||||
document.getElementById('audio-template-modal-title').textContent = t('audio_template.add');
|
||||
document.getElementById('audio-template-modal-title').innerHTML = `${ICON_AUDIO_TEMPLATE} ${t('audio_template.add')}`;
|
||||
document.getElementById('audio-template-form').reset();
|
||||
document.getElementById('audio-template-id').value = '';
|
||||
document.getElementById('audio-engine-config-section').style.display = 'none';
|
||||
@@ -781,7 +782,7 @@ export async function editAudioTemplate(templateId) {
|
||||
const template = await response.json();
|
||||
|
||||
setCurrentEditingAudioTemplateId(templateId);
|
||||
document.getElementById('audio-template-modal-title').textContent = t('audio_template.edit');
|
||||
document.getElementById('audio-template-modal-title').innerHTML = `${ICON_AUDIO_TEMPLATE} ${t('audio_template.edit')}`;
|
||||
document.getElementById('audio-template-id').value = templateId;
|
||||
document.getElementById('audio-template-name').value = template.name;
|
||||
document.getElementById('audio-template-description').value = template.description || '';
|
||||
@@ -900,7 +901,7 @@ export async function showTestAudioTemplateModal(templateId) {
|
||||
const data = await resp.json();
|
||||
const devices = data.devices || [];
|
||||
deviceSelect.innerHTML = devices.map(d => {
|
||||
const label = d.is_loopback ? `🔊 ${d.name}` : `🎤 ${d.name}`;
|
||||
const label = d.name;
|
||||
const val = `${d.index}:${d.is_loopback ? '1' : '0'}`;
|
||||
return `<option value="${val}">${escapeHtml(label)}</option>`;
|
||||
}).join('');
|
||||
@@ -1182,7 +1183,7 @@ function renderPictureSourcesList(streams) {
|
||||
if (capTmpl) capTmplName = escapeHtml(capTmpl.name);
|
||||
}
|
||||
detailsHtml = `<div class="stream-card-props">
|
||||
<span class="stream-card-prop" title="${t('streams.display')}">🖥️ ${stream.display_index ?? 0}</span>
|
||||
<span class="stream-card-prop" title="${t('streams.display')}">${ICON_MONITOR} ${stream.display_index ?? 0}</span>
|
||||
<span class="stream-card-prop" title="${t('streams.target_fps')}">${ICON_FPS} ${stream.target_fps ?? 30}</span>
|
||||
${capTmplName ? `<span class="stream-card-prop stream-card-link" title="${t('streams.capture_template')}" onclick="event.stopPropagation(); navigateToCard('streams','raw','raw-templates','data-id','${stream.capture_template_id}')">${ICON_TEMPLATE} ${capTmplName}</span>` : ''}
|
||||
</div>`;
|
||||
@@ -1236,7 +1237,7 @@ function renderPictureSourcesList(streams) {
|
||||
${template.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(template.description)}</div>` : ''}
|
||||
<div class="stream-card-props">
|
||||
<span class="stream-card-prop" title="${t('templates.engine')}">${getEngineIcon(template.engine_type)} ${template.engine_type.toUpperCase()}</span>
|
||||
${configEntries.length > 0 ? `<span class="stream-card-prop" title="${t('templates.config.show')}">🔧 ${configEntries.length}</span>` : ''}
|
||||
${configEntries.length > 0 ? `<span class="stream-card-prop" title="${t('templates.config.show')}">${ICON_WRENCH} ${configEntries.length}</span>` : ''}
|
||||
</div>
|
||||
${configEntries.length > 0 ? `
|
||||
<details class="template-config-details">
|
||||
@@ -1301,7 +1302,7 @@ function renderPictureSourcesList(streams) {
|
||||
|
||||
const tabBar = `<div class="stream-tab-bar">${tabs.map(tab =>
|
||||
`<button class="stream-tab-btn${tab.key === activeTab ? ' active' : ''}" data-stream-tab="${tab.key}" onclick="switchStreamTab('${tab.key}')">${tab.icon} ${t(tab.titleKey)} <span class="stream-tab-count">${tab.count}</span></button>`
|
||||
).join('')}<span class="cs-expand-collapse-group"><button class="btn-expand-collapse" onclick="expandAllStreamSections()" title="${t('section.expand_all')}">⊞</button><button class="btn-expand-collapse" onclick="collapseAllStreamSections()" title="${t('section.collapse_all')}">⊟</button><button class="tutorial-trigger-btn" onclick="startSourcesTutorial()" title="${t('tour.restart')}">?</button></span></div>`;
|
||||
).join('')}<span class="cs-expand-collapse-group"><button class="btn-expand-collapse" onclick="expandAllStreamSections()" title="${t('section.expand_all')}">⊞</button><button class="btn-expand-collapse" onclick="collapseAllStreamSections()" title="${t('section.collapse_all')}">⊟</button><button class="tutorial-trigger-btn" onclick="startSourcesTutorial()" title="${t('tour.restart')}">${ICON_HELP}</button></span></div>`;
|
||||
|
||||
const renderAudioSourceCard = (src) => {
|
||||
const isMono = src.source_type === 'mono';
|
||||
@@ -1317,7 +1318,7 @@ function renderPictureSourcesList(streams) {
|
||||
: `<span class="stream-card-prop" title="${escapeHtml(t('audio_source.parent'))}">${ICON_AUDIO_LOOPBACK} ${escapeHtml(parentName)}</span>`;
|
||||
propsHtml = `
|
||||
${parentBadge}
|
||||
<span class="stream-card-prop" title="${escapeHtml(t('audio_source.channel'))}">📻 ${chLabel}</span>
|
||||
<span class="stream-card-prop" title="${escapeHtml(t('audio_source.channel'))}">${ICON_RADIO} ${chLabel}</span>
|
||||
`;
|
||||
} else {
|
||||
const devIdx = src.device_index ?? -1;
|
||||
@@ -1356,7 +1357,7 @@ function renderPictureSourcesList(streams) {
|
||||
${template.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(template.description)}</div>` : ''}
|
||||
<div class="stream-card-props">
|
||||
<span class="stream-card-prop" title="${t('audio_template.engine')}">${ICON_AUDIO_TEMPLATE} ${template.engine_type.toUpperCase()}</span>
|
||||
${configEntries.length > 0 ? `<span class="stream-card-prop" title="${t('audio_template.config.show')}">🔧 ${configEntries.length}</span>` : ''}
|
||||
${configEntries.length > 0 ? `<span class="stream-card-prop" title="${t('audio_template.config.show')}">${ICON_WRENCH} ${configEntries.length}</span>` : ''}
|
||||
</div>
|
||||
${configEntries.length > 0 ? `
|
||||
<details class="template-config-details">
|
||||
@@ -1456,7 +1457,7 @@ function _autoGenerateStreamName() {
|
||||
export async function showAddStreamModal(presetType, cloneData = null) {
|
||||
const streamType = (cloneData && cloneData.stream_type) || presetType || 'raw';
|
||||
const titleKeys = { raw: 'streams.add.raw', processed: 'streams.add.processed', static_image: 'streams.add.static_image' };
|
||||
document.getElementById('stream-modal-title').textContent = t(titleKeys[streamType] || 'streams.add');
|
||||
document.getElementById('stream-modal-title').innerHTML = `${getPictureSourceIcon(streamType)} ${t(titleKeys[streamType] || 'streams.add')}`;
|
||||
document.getElementById('stream-form').reset();
|
||||
document.getElementById('stream-id').value = '';
|
||||
document.getElementById('stream-display-index').value = '';
|
||||
@@ -1513,7 +1514,7 @@ export async function editStream(streamId) {
|
||||
const stream = await response.json();
|
||||
|
||||
const editTitleKeys = { raw: 'streams.edit.raw', processed: 'streams.edit.processed', static_image: 'streams.edit.static_image' };
|
||||
document.getElementById('stream-modal-title').textContent = t(editTitleKeys[stream.stream_type] || 'streams.edit');
|
||||
document.getElementById('stream-modal-title').innerHTML = `${getPictureSourceIcon(stream.stream_type)} ${t(editTitleKeys[stream.stream_type] || 'streams.edit')}`;
|
||||
document.getElementById('stream-id').value = streamId;
|
||||
document.getElementById('stream-name').value = stream.name;
|
||||
document.getElementById('stream-description').value = stream.description || '';
|
||||
@@ -2108,7 +2109,7 @@ function _autoGeneratePPTemplateName() {
|
||||
export async function showAddPPTemplateModal(cloneData = null) {
|
||||
if (_availableFilters.length === 0) await loadAvailableFilters();
|
||||
|
||||
document.getElementById('pp-template-modal-title').textContent = t('postprocessing.add');
|
||||
document.getElementById('pp-template-modal-title').innerHTML = `${ICON_PP_TEMPLATE} ${t('postprocessing.add')}`;
|
||||
document.getElementById('pp-template-form').reset();
|
||||
document.getElementById('pp-template-id').value = '';
|
||||
document.getElementById('pp-template-error').style.display = 'none';
|
||||
@@ -2146,7 +2147,7 @@ export async function editPPTemplate(templateId) {
|
||||
if (!response.ok) throw new Error(`Failed to load template: ${response.status}`);
|
||||
const tmpl = await response.json();
|
||||
|
||||
document.getElementById('pp-template-modal-title').textContent = t('postprocessing.edit');
|
||||
document.getElementById('pp-template-modal-title').innerHTML = `${ICON_PP_TEMPLATE} ${t('postprocessing.edit')}`;
|
||||
document.getElementById('pp-template-id').value = templateId;
|
||||
document.getElementById('pp-template-name').value = tmpl.name;
|
||||
document.getElementById('pp-template-description').value = tmpl.description || '';
|
||||
|
||||
Reference in New Issue
Block a user