Frontend polish: loading states, CSS variables, focus indicators, scroll lock

- Add tab refresh loading bar animation for all 4 tab loaders
- Add profiles loading guard to prevent concurrent fetches
- Centralize theme colors into CSS variables (--text-secondary, --text-muted,
  --bg-secondary, --success-color, --shadow-color) for both dark/light themes
- Replace hardcoded gray values across 10 CSS files with variables
- Fix duplicate .btn-sm definition in modal.css
- Fix z-index: toast 2001→2500 to safely clear modals at 2000
- Add :focus-visible keyboard navigation indicators for all interactive elements
- Add responsive breakpoints for tab bar and header on narrow screens
- Prevent background page scroll when command palette is open

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 21:09:42 +03:00
parent 82e12ffaac
commit 7f80faf8be
17 changed files with 162 additions and 49 deletions

View File

@@ -5,7 +5,7 @@
import { apiKey, _dashboardLoading, set_dashboardLoading, dashboardPollInterval, setDashboardPollInterval } from '../core/state.js';
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml } from '../core/api.js';
import { t } from '../core/i18n.js';
import { showToast, formatUptime } from '../core/ui.js';
import { showToast, formatUptime, setTabRefreshing } from '../core/ui.js';
import { renderPerfSection, initPerfCharts, startPerfPolling, stopPerfPolling } from './perf-charts.js';
import { startAutoRefresh, updateTabBadge } from './tabs.js';
import {
@@ -302,6 +302,7 @@ export async function loadDashboard(forceFullRender = false) {
set_dashboardLoading(true);
const container = document.getElementById('dashboard-content');
if (!container) { set_dashboardLoading(false); return; }
setTabRefreshing('dashboard-content', true);
try {
const [targetsResp, profilesResp, devicesResp, cssResp] = await Promise.all([
@@ -481,6 +482,7 @@ export async function loadDashboard(forceFullRender = false) {
container.innerHTML = `<div class="dashboard-no-targets">${t('dashboard.failed')}</div>`;
} finally {
set_dashboardLoading(false);
setTabRefreshing('dashboard-content', false);
}
}