Frontend: structured error handling, state fixes, accessibility, i18n
- Enhance fetchWithAuth with auto-401, retry w/ exponential backoff, timeout - Remove ~40 manual 401 checks across 10 feature files - Fix state: brightness cache setter, manual edit flag resets, static import - Add ARIA: role=dialog/tablist, aria-modal, aria-labelledby, aria-selected - Add focus trapping in Modal base class, aria-expanded on hint toggles - Fix WCAG AA color contrast with --primary-text-color variable - Add i18n pluralization (CLDR rules for en/ru), getCurrentLocale export - Replace hardcoded strings in dashboard.js and profiles.js - Add data-i18n-aria-label support, 20 new keys in en.json and ru.json Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,32 +45,32 @@
|
||||
</header>
|
||||
|
||||
<div class="tabs">
|
||||
<div class="tab-bar">
|
||||
<button class="tab-btn" data-tab="dashboard" onclick="switchTab('dashboard')"><span data-i18n="dashboard.title">📊 Dashboard</span></button>
|
||||
<button class="tab-btn" data-tab="profiles" onclick="switchTab('profiles')"><span data-i18n="profiles.title">📋 Profiles</span></button>
|
||||
<button class="tab-btn" data-tab="targets" onclick="switchTab('targets')"><span data-i18n="targets.title">⚡ Targets</span></button>
|
||||
<button class="tab-btn" data-tab="streams" onclick="switchTab('streams')"><span data-i18n="streams.title">📺 Sources</span></button>
|
||||
<div class="tab-bar" role="tablist">
|
||||
<button class="tab-btn" data-tab="dashboard" onclick="switchTab('dashboard')" role="tab" aria-selected="true" aria-controls="tab-dashboard" id="tab-btn-dashboard"><span data-i18n="dashboard.title">📊 Dashboard</span></button>
|
||||
<button class="tab-btn" data-tab="profiles" onclick="switchTab('profiles')" role="tab" aria-selected="false" aria-controls="tab-profiles" id="tab-btn-profiles"><span data-i18n="profiles.title">📋 Profiles</span></button>
|
||||
<button class="tab-btn" data-tab="targets" onclick="switchTab('targets')" role="tab" aria-selected="false" aria-controls="tab-targets" id="tab-btn-targets"><span data-i18n="targets.title">⚡ Targets</span></button>
|
||||
<button class="tab-btn" data-tab="streams" onclick="switchTab('streams')" role="tab" aria-selected="false" aria-controls="tab-streams" id="tab-btn-streams"><span data-i18n="streams.title">📺 Sources</span></button>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-dashboard">
|
||||
<div class="tab-panel" id="tab-dashboard" role="tabpanel" aria-labelledby="tab-btn-dashboard">
|
||||
<div id="dashboard-content">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-profiles">
|
||||
<div class="tab-panel" id="tab-profiles" role="tabpanel" aria-labelledby="tab-btn-profiles">
|
||||
<div id="profiles-content">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-targets">
|
||||
<div class="tab-panel" id="tab-targets" role="tabpanel" aria-labelledby="tab-btn-targets">
|
||||
<div id="targets-panel-content">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel" id="tab-streams">
|
||||
<div class="tab-panel" id="tab-streams" role="tabpanel" aria-labelledby="tab-btn-streams">
|
||||
<div id="streams-list">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<!-- Add Device Modal -->
|
||||
<div id="add-device-modal" class="modal">
|
||||
<div id="add-device-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="add-device-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 data-i18n="devices.add">Add New Device</h2>
|
||||
<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">🔍</button>
|
||||
<button class="modal-close-btn" onclick="closeAddDeviceModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeAddDeviceModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@@ -82,8 +82,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeAddDeviceModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="document.getElementById('add-device-form').requestSubmit()" title="Add Device">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeAddDeviceModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="document.getElementById('add-device-form').requestSubmit()" title="Add Device" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Login Modal -->
|
||||
<div id="api-key-modal" class="modal">
|
||||
<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 data-i18n="auth.title">🔑 Login to LED Grab</h2>
|
||||
<button class="modal-close-btn" id="modal-close-x-btn" onclick="closeApiKeyModal()" title="Close">✕</button>
|
||||
<h2 id="api-key-modal-title" data-i18n="auth.title">🔑 Login to LED Grab</h2>
|
||||
<button class="modal-close-btn" id="modal-close-x-btn" onclick="closeApiKeyModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<form id="api-key-form" onsubmit="submitApiKey(event)">
|
||||
<div class="modal-body">
|
||||
@@ -32,8 +32,8 @@
|
||||
<div id="api-key-error" class="error-message" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-icon btn-secondary" onclick="closeApiKeyModal()" id="modal-cancel-btn" title="Cancel">✕</button>
|
||||
<button type="submit" class="btn btn-icon btn-primary" title="Login">✓</button>
|
||||
<button type="button" class="btn btn-icon btn-secondary" onclick="closeApiKeyModal()" id="modal-cancel-btn" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button type="submit" class="btn btn-icon btn-primary" title="Login" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<!-- Calibration Modal -->
|
||||
<div id="calibration-modal" class="modal">
|
||||
<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 data-i18n="calibration.title">📐 LED Calibration</h2>
|
||||
<h2 id="calibration-modal-title" data-i18n="calibration.title">📐 LED Calibration</h2>
|
||||
<button 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">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeCalibrationModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="calibration-device-id">
|
||||
@@ -137,8 +137,8 @@
|
||||
<div id="calibration-error" class="error-message" style="display: none;"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeCalibrationModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveCalibration()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeCalibrationModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveCalibration()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Template Modal -->
|
||||
<div id="template-modal" class="modal">
|
||||
<div id="template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="template-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="template-modal-title" data-i18n="templates.add">Add Capture Template</h2>
|
||||
<button class="modal-close-btn" onclick="closeTemplateModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeTemplateModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="template-id">
|
||||
@@ -38,8 +38,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeTemplateModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveTemplate()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeTemplateModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveTemplate()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Confirmation Modal -->
|
||||
<div id="confirm-modal" class="modal">
|
||||
<div id="confirm-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="confirm-modal-title">
|
||||
<div class="modal-content" style="max-width: 450px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="confirm-title">Confirm Action</h2>
|
||||
<button class="modal-close-btn" onclick="closeConfirmModal(false)" title="Close">✕</button>
|
||||
<h2 id="confirm-modal-title">Confirm Action</h2>
|
||||
<button class="modal-close-btn" onclick="closeConfirmModal(false)" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id="confirm-message" class="modal-description"></p>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- General Settings Modal -->
|
||||
<div id="device-settings-modal" class="modal">
|
||||
<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 data-i18n="settings.general.title">⚙️ General Settings</h2>
|
||||
<button class="modal-close-btn" onclick="closeDeviceSettingsModal()" title="Close">✕</button>
|
||||
<h2 id="device-settings-modal-title" data-i18n="settings.general.title">⚙️ General Settings</h2>
|
||||
<button class="modal-close-btn" onclick="closeDeviceSettingsModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="device-settings-form">
|
||||
@@ -83,8 +83,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeDeviceSettingsModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveDeviceSettings()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeDeviceSettingsModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveDeviceSettings()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Key Colors Editor Modal -->
|
||||
<div id="kc-editor-modal" class="modal">
|
||||
<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>
|
||||
<button class="modal-close-btn" onclick="closeKCEditorModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeKCEditorModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="kc-editor-form">
|
||||
@@ -73,8 +73,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeKCEditorModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveKCEditor()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeKCEditorModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveKCEditor()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Pattern Template Editor Modal -->
|
||||
<div id="pattern-template-modal" class="modal">
|
||||
<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-title" data-i18n="pattern.add">📄 Add Pattern Template</h2>
|
||||
<button class="modal-close-btn" onclick="closePatternTemplateModal()" title="Close">✕</button>
|
||||
<h2 id="pattern-template-modal-title" data-i18n="pattern.add">📄 Add Pattern Template</h2>
|
||||
<button class="modal-close-btn" onclick="closePatternTemplateModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="pattern-template-form">
|
||||
@@ -60,8 +60,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closePatternTemplateModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="savePatternTemplate()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closePatternTemplateModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="savePatternTemplate()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Processing Template Modal -->
|
||||
<div id="pp-template-modal" class="modal">
|
||||
<div id="pp-template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="pp-template-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="pp-template-modal-title" data-i18n="postprocessing.add">Add Processing Template</h2>
|
||||
<button class="modal-close-btn" onclick="closePPTemplateModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closePPTemplateModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="pp-template-id">
|
||||
@@ -33,8 +33,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closePPTemplateModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="savePPTemplate()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closePPTemplateModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="savePPTemplate()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Profile Editor Modal -->
|
||||
<div id="profile-editor-modal" class="modal">
|
||||
<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>
|
||||
<button class="modal-close-btn" onclick="closeProfileEditorModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeProfileEditorModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="profile-editor-form">
|
||||
@@ -67,8 +67,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeProfileEditorModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveProfileEditor()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeProfileEditorModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveProfileEditor()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Source Modal -->
|
||||
<div id="stream-modal" class="modal">
|
||||
<div id="stream-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="stream-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 id="stream-modal-title" data-i18n="streams.add">Add Source</h2>
|
||||
<button class="modal-close-btn" onclick="closeStreamModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeStreamModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="stream-id">
|
||||
@@ -95,8 +95,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeStreamModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveStream()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeStreamModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveStream()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Target Editor Modal (name, device, source, settings) -->
|
||||
<div id="target-editor-modal" class="modal">
|
||||
<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>
|
||||
<button class="modal-close-btn" onclick="closeTargetEditorModal()" title="Close">✕</button>
|
||||
<button class="modal-close-btn" onclick="closeTargetEditorModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="target-editor-form">
|
||||
@@ -85,8 +85,8 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeTargetEditorModal()" title="Cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveTargetEditor()" title="Save">✓</button>
|
||||
<button class="btn btn-icon btn-secondary" onclick="closeTargetEditorModal()" title="Cancel" data-i18n-aria-label="aria.cancel">✕</button>
|
||||
<button class="btn btn-icon btn-primary" onclick="saveTargetEditor()" title="Save" data-i18n-aria-label="aria.save">✓</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Test PP Template Modal -->
|
||||
<div id="test-pp-template-modal" class="modal">
|
||||
<div id="test-pp-template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="test-pp-template-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 data-i18n="postprocessing.test.title">Test Processing Template</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestPPTemplateModal()" title="Close">✕</button>
|
||||
<h2 id="test-pp-template-modal-title" data-i18n="postprocessing.test.title">Test Processing Template</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestPPTemplateModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Test Source Modal -->
|
||||
<div id="test-stream-modal" class="modal">
|
||||
<div id="test-stream-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="test-stream-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 data-i18n="streams.test.title">Test Source</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestStreamModal()" title="Close">✕</button>
|
||||
<h2 id="test-stream-modal-title" data-i18n="streams.test.title">Test Source</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestStreamModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- Test Template Modal -->
|
||||
<div id="test-template-modal" class="modal">
|
||||
<div id="test-template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="test-template-modal-title">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 data-i18n="templates.test.title">Test Capture Template</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestTemplateModal()" title="Close">✕</button>
|
||||
<h2 id="test-template-modal-title" data-i18n="templates.test.title">Test Capture Template</h2>
|
||||
<button class="modal-close-btn" onclick="closeTestTemplateModal()" title="Close" data-i18n-aria-label="aria.close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<!-- Device Tutorial Overlay (viewport-level) -->
|
||||
<div id="device-tutorial-overlay" class="tutorial-overlay tutorial-overlay-fixed">
|
||||
<div id="device-tutorial-overlay" class="tutorial-overlay tutorial-overlay-fixed" role="dialog" aria-modal="true">
|
||||
<div class="tutorial-backdrop"></div>
|
||||
<div class="tutorial-ring"></div>
|
||||
<div class="tutorial-tooltip">
|
||||
<div class="tutorial-tooltip-header">
|
||||
<span class="tutorial-step-counter"></span>
|
||||
<button class="tutorial-close-btn" onclick="closeTutorial()">×</button>
|
||||
<button class="tutorial-close-btn" onclick="closeTutorial()" data-i18n-aria-label="aria.close">×</button>
|
||||
</div>
|
||||
<p class="tutorial-tooltip-text"></p>
|
||||
<div class="tutorial-tooltip-nav">
|
||||
<button class="tutorial-prev-btn" onclick="tutorialPrev()">←</button>
|
||||
<button class="tutorial-next-btn" onclick="tutorialNext()">→</button>
|
||||
<button class="tutorial-prev-btn" onclick="tutorialPrev()" data-i18n-aria-label="aria.previous">←</button>
|
||||
<button class="tutorial-next-btn" onclick="tutorialNext()" data-i18n-aria-label="aria.next">→</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user