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:
2026-02-27 16:14:18 +03:00
parent efb6cf7ce6
commit c262ec0775
39 changed files with 634 additions and 311 deletions

View File

@@ -4,7 +4,7 @@
<div class="modal-header">
<h2 id="add-device-modal-title" data-i18n="devices.add">Add New Device</h2>
<div class="modal-header-actions">
<button type="button" class="modal-header-btn" id="scan-network-btn" onclick="scanForDevices()" data-i18n-title="device.scan" title="Auto Discovery">&#x1F50D;</button>
<button type="button" class="modal-header-btn" id="scan-network-btn" onclick="scanForDevices()" data-i18n-title="device.scan" title="Auto Discovery"><svg class="icon" viewBox="0 0 24 24"><path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/></svg></button>
<button class="modal-close-btn" onclick="closeAddDeviceModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<div id="api-key-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="api-key-modal-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="api-key-modal-title" data-i18n="auth.title">🔑 Login to LED Grab</h2>
<h2 id="api-key-modal-title"><svg class="icon" viewBox="0 0 24 24"><path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/></svg> <span data-i18n="auth.title">Login to LED Grab</span></h2>
<button class="modal-close-btn" id="modal-close-x-btn" onclick="closeApiKeyModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<form id="api-key-form" onsubmit="submitApiKey(event)">
@@ -25,7 +25,7 @@
autocomplete="off"
>
<button type="button" class="password-toggle" onclick="togglePasswordVisibility()">
👁️
<svg class="icon" viewBox="0 0 24 24"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/></svg>
</button>
</div>
</div>

View File

@@ -2,7 +2,7 @@
<div id="calibration-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="calibration-modal-title">
<div class="modal-content" style="max-width: 700px;">
<div class="modal-header">
<h2 id="calibration-modal-title" data-i18n="calibration.title">📐 LED Calibration</h2>
<h2 id="calibration-modal-title"><svg class="icon" viewBox="0 0 24 24"><path d="M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Z"/><path d="m14.5 12.5 2-2"/><path d="m11.5 9.5 2-2"/><path d="m8.5 6.5 2-2"/><path d="m17.5 15.5 2-2"/></svg> <span data-i18n="calibration.title">LED Calibration</span></h2>
<button id="calibration-tutorial-btn" class="tutorial-trigger-btn" onclick="startCalibrationTutorial()" data-i18n-title="calibration.tutorial.start" title="Start tutorial">?</button>
<button class="modal-close-btn" onclick="closeCalibrationModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
@@ -34,7 +34,7 @@
<!-- Screen with direction toggle, total LEDs, and offset -->
<div class="preview-screen">
<button type="button" class="direction-toggle" onclick="toggleDirection()" title="Toggle direction">
<span id="direction-icon"></span> <span id="direction-label">CW</span>
<span id="direction-icon"><svg class="icon" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/></svg></span> <span id="direction-label">CW</span>
</button>
<div class="preview-screen-total" onclick="toggleEdgeInputs()" title="Toggle edge LED inputs"><span id="cal-total-leds-inline">0</span> / <span id="cal-device-led-count-inline">0</span></div>
<div class="preview-screen-border-width">
@@ -42,7 +42,7 @@
<input type="number" id="cal-border-width" min="1" max="100" value="10">
</div>
<button id="calibration-overlay-btn" class="calibration-overlay-toggle" onclick="toggleCalibrationOverlay()" data-i18n-title="overlay.button.show" title="Show overlay visualization" style="display:none">
&#x1F4A1; <span data-i18n="calibration.overlay_toggle">Overlay</span>
<svg class="icon" viewBox="0 0 24 24"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg> <span data-i18n="calibration.overlay_toggle">Overlay</span>
</button>
</div>

View File

@@ -2,7 +2,7 @@
<div id="css-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="css-editor-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="css-editor-title" data-i18n="color_strip.add">🎞️ Add Color Strip Source</h2>
<h2 id="css-editor-title"><svg class="icon" viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 3v18"/><path d="M3 7.5h4"/><path d="M3 12h18"/><path d="M3 16.5h4"/><path d="M17 3v18"/><path d="M17 7.5h4"/><path d="M17 16.5h4"/></svg> <span data-i18n="color_strip.add">Add Color Strip Source</span></h2>
<button class="modal-close-btn" onclick="closeCSSEditorModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">

View File

@@ -2,7 +2,7 @@
<div id="device-settings-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="device-settings-modal-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="device-settings-modal-title" data-i18n="settings.general.title">⚙️ General Settings</h2>
<h2 id="device-settings-modal-title"><svg class="icon" viewBox="0 0 24 24"><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/></svg> <span data-i18n="settings.general.title">General Settings</span></h2>
<button class="modal-close-btn" onclick="closeDeviceSettingsModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">

View File

@@ -2,7 +2,7 @@
<div id="kc-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="kc-editor-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="kc-editor-title" data-i18n="kc.add">🎨 Add Key Colors Target</h2>
<h2 id="kc-editor-title"><svg class="icon" viewBox="0 0 24 24"><path d="M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z"/><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/></svg> <span data-i18n="kc.add">Add Key Colors Target</span></h2>
<button class="modal-close-btn" onclick="closeKCEditorModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">

View File

@@ -2,7 +2,7 @@
<div id="pattern-template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="pattern-template-modal-title">
<div class="modal-content modal-content-wide">
<div class="modal-header">
<h2 id="pattern-template-modal-title" data-i18n="pattern.add">📄 Add Pattern Template</h2>
<h2 id="pattern-template-modal-title"><svg class="icon" viewBox="0 0 24 24"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg> <span data-i18n="pattern.add">Add Pattern Template</span></h2>
<button class="modal-close-btn" onclick="closePatternTemplateModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">
@@ -36,7 +36,7 @@
<small class="input-hint" style="display:none" data-i18n="pattern.visual_editor.hint">Click + buttons to add rectangles. Drag edges to resize, drag inside to move.</small>
<div class="pattern-bg-row">
<select id="pattern-bg-source"></select>
<button type="button" class="btn btn-icon btn-secondary pattern-capture-btn" onclick="capturePatternBackground()" title="Capture Background" data-i18n-title="pattern.capture_bg">📷</button>
<button type="button" class="btn btn-icon btn-secondary pattern-capture-btn" onclick="capturePatternBackground()" title="Capture Background" data-i18n-title="pattern.capture_bg"><svg class="icon" viewBox="0 0 24 24"><path d="M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z"/><circle cx="12" cy="13" r="3"/></svg></button>
</div>
<div class="pattern-canvas-container">
<canvas id="pattern-canvas"></canvas>

View File

@@ -2,7 +2,7 @@
<div id="profile-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="profile-editor-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="profile-editor-title" data-i18n="profiles.add">📋 Add Profile</h2>
<h2 id="profile-editor-title"><svg class="icon" viewBox="0 0 24 24"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M12 11h4"/><path d="M12 16h4"/><path d="M8 11h.01"/><path d="M8 16h.01"/></svg> <span data-i18n="profiles.add">Add Profile</span></h2>
<button class="modal-close-btn" onclick="closeProfileEditorModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">

View File

@@ -2,7 +2,7 @@
<div id="target-editor-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="target-editor-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="target-editor-title" data-i18n="targets.add">🎯 Add Target</h2>
<h2 id="target-editor-title"><svg class="icon" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg> <span data-i18n="targets.add">Add Target</span></h2>
<button class="modal-close-btn" onclick="closeTargetEditorModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">

View File

@@ -16,7 +16,7 @@
</div>
<button type="button" id="test-audio-template-start-btn" class="btn btn-primary" onclick="startAudioTemplateTest()" style="margin-top: 8px;">
<span data-i18n="audio_template.test.run">🧪 Run</span>
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/><path d="M6.453 15h11.094"/><path d="M8.5 2h7"/></svg> <span data-i18n="audio_template.test.run">Run</span>
</button>
<canvas id="audio-template-test-canvas" class="audio-test-canvas" style="display:none; margin-top: 12px;"></canvas>

View File

@@ -19,7 +19,7 @@
</div>
<button type="button" class="btn btn-primary" onclick="runPPTemplateTest()" style="margin-top: 16px;">
<span data-i18n="streams.test.run">🧪 Run</span>
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/><path d="M6.453 15h11.094"/><path d="M8.5 2h7"/></svg> <span data-i18n="streams.test.run">Run</span>
</button>
</div>

View File

@@ -15,7 +15,7 @@
</div>
<button type="button" class="btn btn-primary" onclick="runStreamTest()" style="margin-top: 16px;">
<span data-i18n="streams.test.run">🧪 Run</span>
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/><path d="M6.453 15h11.094"/><path d="M8.5 2h7"/></svg> <span data-i18n="streams.test.run">Run</span>
</button>
</div>

View File

@@ -23,7 +23,7 @@
</div>
<button type="button" class="btn btn-primary" onclick="runTemplateTest()" style="margin-top: 16px;">
<span data-i18n="templates.test.run">🧪 Run</span>
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/><path d="M6.453 15h11.094"/><path d="M8.5 2h7"/></svg> <span data-i18n="templates.test.run">Run</span>
</button>
</div>