Add dynamic brightness value source support for KC targets, fix subtab selector collision
Extend value source brightness modulation to Key Colors targets (matching LED target support). Also fix stream subtab CSS selector collision that broke target subtab selection, and use 🔢 emoji for value source UI elements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
_kcNameManuallyEdited, set_kcNameManuallyEdited,
|
||||
kcWebSockets,
|
||||
PATTERN_RECT_BORDERS,
|
||||
_cachedValueSources, set_cachedValueSources,
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml } from '../core/api.js';
|
||||
import { t } from '../core/i18n.js';
|
||||
@@ -27,6 +28,7 @@ class KCEditorModal extends Modal {
|
||||
interpolation: document.getElementById('kc-editor-interpolation').value,
|
||||
smoothing: document.getElementById('kc-editor-smoothing').value,
|
||||
patternTemplateId: document.getElementById('kc-editor-pattern-template').value,
|
||||
brightness_vs: document.getElementById('kc-editor-brightness-vs').value,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -348,15 +350,33 @@ function _autoGenerateKCName() {
|
||||
document.getElementById('kc-editor-name').value = `${sourceName} \u00b7 ${patName} (${modeName})`;
|
||||
}
|
||||
|
||||
function _populateKCBrightnessVsDropdown(selectedId = '') {
|
||||
const sel = document.getElementById('kc-editor-brightness-vs');
|
||||
// Keep the first "None" option, remove the rest
|
||||
while (sel.options.length > 1) sel.remove(1);
|
||||
_cachedValueSources.forEach(vs => {
|
||||
const typeIcons = { static: '📊', animated: '🔄', audio: '🎵' };
|
||||
const icon = typeIcons[vs.source_type] || '🔢';
|
||||
const opt = document.createElement('option');
|
||||
opt.value = vs.id;
|
||||
opt.textContent = `${icon} ${vs.name}`;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
sel.value = selectedId || '';
|
||||
}
|
||||
|
||||
export async function showKCEditor(targetId = null, cloneData = null) {
|
||||
try {
|
||||
// Load sources and pattern templates in parallel
|
||||
const [sourcesResp, patResp] = await Promise.all([
|
||||
// Load sources, pattern templates, and value sources in parallel
|
||||
const [sourcesResp, patResp, vsResp] = await Promise.all([
|
||||
fetchWithAuth('/picture-sources').catch(() => null),
|
||||
fetchWithAuth('/pattern-templates').catch(() => null),
|
||||
fetchWithAuth('/value-sources').catch(() => null),
|
||||
]);
|
||||
const sources = (sourcesResp && sourcesResp.ok) ? (await sourcesResp.json()).streams || [] : [];
|
||||
const patTemplates = (patResp && patResp.ok) ? (await patResp.json()).templates || [] : [];
|
||||
const valueSources = (vsResp && vsResp.ok) ? (await vsResp.json()).sources || [] : [];
|
||||
set_cachedValueSources(valueSources);
|
||||
|
||||
// Populate source select
|
||||
const sourceSelect = document.getElementById('kc-editor-source');
|
||||
@@ -397,6 +417,7 @@ export async function showKCEditor(targetId = null, cloneData = null) {
|
||||
document.getElementById('kc-editor-smoothing').value = kcSettings.smoothing ?? 0.3;
|
||||
document.getElementById('kc-editor-smoothing-value').textContent = kcSettings.smoothing ?? 0.3;
|
||||
patSelect.value = kcSettings.pattern_template_id || '';
|
||||
_populateKCBrightnessVsDropdown(kcSettings.brightness_value_source_id || '');
|
||||
document.getElementById('kc-editor-title').textContent = t('kc.edit');
|
||||
} else if (cloneData) {
|
||||
const kcSettings = cloneData.key_colors_settings || {};
|
||||
@@ -409,6 +430,7 @@ export async function showKCEditor(targetId = null, cloneData = null) {
|
||||
document.getElementById('kc-editor-smoothing').value = kcSettings.smoothing ?? 0.3;
|
||||
document.getElementById('kc-editor-smoothing-value').textContent = kcSettings.smoothing ?? 0.3;
|
||||
patSelect.value = kcSettings.pattern_template_id || '';
|
||||
_populateKCBrightnessVsDropdown(kcSettings.brightness_value_source_id || '');
|
||||
document.getElementById('kc-editor-title').textContent = t('kc.add');
|
||||
} else {
|
||||
document.getElementById('kc-editor-id').value = '';
|
||||
@@ -420,6 +442,7 @@ export async function showKCEditor(targetId = null, cloneData = null) {
|
||||
document.getElementById('kc-editor-smoothing').value = 0.3;
|
||||
document.getElementById('kc-editor-smoothing-value').textContent = '0.3';
|
||||
if (patTemplates.length > 0) patSelect.value = patTemplates[0].id;
|
||||
_populateKCBrightnessVsDropdown('');
|
||||
document.getElementById('kc-editor-title').textContent = t('kc.add');
|
||||
}
|
||||
|
||||
@@ -464,6 +487,7 @@ export async function saveKCEditor() {
|
||||
const interpolation = document.getElementById('kc-editor-interpolation').value;
|
||||
const smoothing = parseFloat(document.getElementById('kc-editor-smoothing').value);
|
||||
const patternTemplateId = document.getElementById('kc-editor-pattern-template').value;
|
||||
const brightnessVsId = document.getElementById('kc-editor-brightness-vs').value;
|
||||
|
||||
if (!name) {
|
||||
kcEditorModal.showError(t('kc.error.required'));
|
||||
@@ -483,6 +507,7 @@ export async function saveKCEditor() {
|
||||
interpolation_mode: interpolation,
|
||||
smoothing,
|
||||
pattern_template_id: patternTemplateId,
|
||||
brightness_value_source_id: brightnessVsId,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -492,10 +492,10 @@ export async function loadPictureSources() {
|
||||
}
|
||||
|
||||
export function switchStreamTab(tabKey) {
|
||||
document.querySelectorAll('.stream-tab-btn').forEach(btn =>
|
||||
document.querySelectorAll('.stream-tab-btn[data-stream-tab]').forEach(btn =>
|
||||
btn.classList.toggle('active', btn.dataset.streamTab === tabKey)
|
||||
);
|
||||
document.querySelectorAll('.stream-tab-panel').forEach(panel =>
|
||||
document.querySelectorAll('.stream-tab-panel[id^="stream-tab-"]').forEach(panel =>
|
||||
panel.classList.toggle('active', panel.id === `stream-tab-${tabKey}`)
|
||||
);
|
||||
localStorage.setItem('activeStreamTab', tabKey);
|
||||
@@ -629,7 +629,7 @@ function renderPictureSourcesList(streams) {
|
||||
{ key: 'static_image', icon: '🖼️', titleKey: 'streams.group.static_image', count: staticImageStreams.length },
|
||||
{ key: 'processed', icon: '🎨', titleKey: 'streams.group.processed', count: processedStreams.length },
|
||||
{ key: 'audio', icon: '🔊', titleKey: 'streams.group.audio', count: _cachedAudioSources.length },
|
||||
{ key: 'value', icon: '🎚️', titleKey: 'streams.group.value', count: _cachedValueSources.length },
|
||||
{ key: 'value', icon: '🔢', titleKey: 'streams.group.value', count: _cachedValueSources.length },
|
||||
];
|
||||
|
||||
const tabBar = `<div class="stream-tab-bar">${tabs.map(tab =>
|
||||
|
||||
@@ -424,6 +424,9 @@
|
||||
"kc.pattern_template": "Pattern Template:",
|
||||
"kc.pattern_template.hint": "Select the rectangle pattern to use for color extraction",
|
||||
"kc.pattern_template.none": "-- Select a pattern template --",
|
||||
"kc.brightness_vs": "🔢 Brightness Source:",
|
||||
"kc.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (multiplied with the manual brightness slider)",
|
||||
"kc.brightness_vs.none": "None (manual brightness only)",
|
||||
"kc.created": "Key colors target created successfully",
|
||||
"kc.updated": "Key colors target updated successfully",
|
||||
"kc.deleted": "Key colors target deleted successfully",
|
||||
@@ -763,7 +766,7 @@
|
||||
"audio_source.error.name_required": "Please enter a name",
|
||||
|
||||
"streams.group.value": "Value Sources",
|
||||
"value_source.group.title": "🎚️ Value Sources",
|
||||
"value_source.group.title": "🔢 Value Sources",
|
||||
"value_source.add": "Add Value Source",
|
||||
"value_source.edit": "Edit Value Source",
|
||||
"value_source.name": "Name:",
|
||||
@@ -807,7 +810,7 @@
|
||||
"value_source.deleted": "Value source deleted",
|
||||
"value_source.delete.confirm": "Are you sure you want to delete this value source?",
|
||||
"value_source.error.name_required": "Please enter a name",
|
||||
"targets.brightness_vs": "Brightness Source:",
|
||||
"targets.brightness_vs": "🔢 Brightness Source:",
|
||||
"targets.brightness_vs.hint": "Optional value source that dynamically controls brightness each frame (overrides device brightness)",
|
||||
"targets.brightness_vs.none": "None (device brightness)"
|
||||
}
|
||||
|
||||
@@ -424,6 +424,9 @@
|
||||
"kc.pattern_template": "Шаблон Паттерна:",
|
||||
"kc.pattern_template.hint": "Выберите шаблон прямоугольников для извлечения цветов",
|
||||
"kc.pattern_template.none": "-- Выберите шаблон паттерна --",
|
||||
"kc.brightness_vs": "🔢 Источник Яркости:",
|
||||
"kc.brightness_vs.hint": "Опциональный источник значений, динамически управляющий яркостью каждый кадр (умножается на ручной слайдер яркости)",
|
||||
"kc.brightness_vs.none": "Нет (только ручная яркость)",
|
||||
"kc.created": "Цель ключевых цветов успешно создана",
|
||||
"kc.updated": "Цель ключевых цветов успешно обновлена",
|
||||
"kc.deleted": "Цель ключевых цветов успешно удалена",
|
||||
@@ -763,7 +766,7 @@
|
||||
"audio_source.error.name_required": "Введите название",
|
||||
|
||||
"streams.group.value": "Источники значений",
|
||||
"value_source.group.title": "🎚️ Источники значений",
|
||||
"value_source.group.title": "🔢 Источники значений",
|
||||
"value_source.add": "Добавить источник значений",
|
||||
"value_source.edit": "Редактировать источник значений",
|
||||
"value_source.name": "Название:",
|
||||
@@ -807,7 +810,7 @@
|
||||
"value_source.deleted": "Источник значений удалён",
|
||||
"value_source.delete.confirm": "Удалить этот источник значений?",
|
||||
"value_source.error.name_required": "Введите название",
|
||||
"targets.brightness_vs": "Источник яркости:",
|
||||
"targets.brightness_vs": "🔢 Источник яркости:",
|
||||
"targets.brightness_vs.hint": "Необязательный источник значений для динамического управления яркостью каждый кадр (переопределяет яркость устройства)",
|
||||
"targets.brightness_vs.none": "Нет (яркость устройства)"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user