Add card color system with wrapCard helper and reset support

Introduce localStorage-backed card color assignment for all card types
with a reusable wrapCard() helper that provides consistent card shell
structure (top actions, bottom actions with color picker). Move color
picker from top-right to bottom-right action bar. Add color reset
button to clear card color back to default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 21:55:29 +03:00
parent fa81d6a608
commit 9b2ccde8a7
15 changed files with 329 additions and 125 deletions

View File

@@ -23,6 +23,7 @@ import {
ICON_LED, ICON_FPS, ICON_OVERLAY, ICON_LED_PREVIEW,
ICON_GLOBE, ICON_RADIO, ICON_PLUG, ICON_FILM, ICON_SUN_DIM, ICON_TARGET_ICON, ICON_HELP,
} from '../core/icons.js';
import { wrapCard } from '../core/card-colors.js';
import { CardSection } from '../core/card-sections.js';
import { updateSubTabHash, updateTabBadge } from './tabs.js';
@@ -850,12 +851,13 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
healthTitle = devOnline ? t('device.health.online') : t('device.health.offline');
}
return `
<div class="card" data-target-id="${target.id}">
<div class="card-top-actions">
<button class="card-autostart-btn${target.auto_start ? ' active' : ''}" onclick="toggleTargetAutoStart('${target.id}', ${!target.auto_start})" title="${target.auto_start ? t('autostart.toggle.enabled') : t('autostart.toggle.disabled')}">&#x2605;</button>
<button class="card-remove-btn" onclick="deleteTarget('${target.id}')" title="${t('common.delete')}">&#x2715;</button>
</div>
return wrapCard({
dataAttr: 'data-target-id',
id: target.id,
topButtons: `<button class="card-autostart-btn${target.auto_start ? ' active' : ''}" onclick="toggleTargetAutoStart('${target.id}', ${!target.auto_start})" title="${target.auto_start ? t('autostart.toggle.enabled') : t('autostart.toggle.disabled')}">&#x2605;</button>`,
removeOnclick: `deleteTarget('${target.id}')`,
removeTitle: t('common.delete'),
content: `
<div class="card-header">
<div class="card-title">
<span class="health-dot ${healthClass}" title="${healthTitle}"></span>
@@ -908,8 +910,8 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
<div id="led-preview-panel-${target.id}" class="led-preview-panel" style="display:${ledPreviewWebSockets[target.id] ? '' : 'none'}">
<canvas id="led-preview-canvas-${target.id}" class="led-preview-canvas"></canvas>
<span id="led-preview-brightness-${target.id}" class="led-preview-brightness" style="display:none"${bvsId ? ' data-has-bvs="1"' : ''}></span>
</div>
<div class="card-actions">
</div>`,
actions: `
${isProcessing ? `
<button class="btn btn-icon btn-danger" onclick="stopTargetProcessing('${target.id}')" title="${t('device.button.stop')}">
${ICON_STOP}
@@ -938,10 +940,8 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
<button class="btn btn-icon btn-secondary" onclick="startTargetOverlay('${target.id}')" title="${t('overlay.button.show')}">
${ICON_OVERLAY}
</button>
`) : ''}
</div>
</div>
`;
`) : ''}`,
});
}
async function _targetAction(action) {