Frontend improvements: CSS foundations, accessibility, UX enhancements

CSS: Add design token variables (spacing, timing, weights, z-index layers),
migrate all hardcoded z-index to named vars, fix light theme contrast for
WCAG AA, add skeleton loading cards, mask-composite fallback, card padding.

Accessibility: aria-live on toast, aria-label on health dots, sr-only class,
graph container keyboard focusable, MQTT password wrapped in form element.

UX: Modal auto-focus on open, inline field validation with blur, undo toast
with countdown, bulk action progress indicator, API error toast on failure.

i18n: Add common.undo, validation.required, bulk.processing, api.error.*
keys in EN/RU/ZH.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 01:51:22 +03:00
parent 43fbc1eff5
commit 47c696bae3
21 changed files with 397 additions and 38 deletions

View File

@@ -2,6 +2,59 @@ section {
margin-bottom: 40px;
}
/* ── Skeleton loading placeholders ── */
@keyframes skeletonPulse {
0%, 100% { opacity: 0.06; }
50% { opacity: 0.12; }
}
.skeleton-card {
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 16px 20px 20px;
display: flex;
flex-direction: column;
gap: 12px;
min-height: 140px;
}
.skeleton-line {
height: 14px;
border-radius: 4px;
background: var(--text-color);
animation: skeletonPulse 1.5s ease-in-out infinite;
}
.skeleton-line-title {
width: 60%;
height: 18px;
}
.skeleton-line-short {
width: 40%;
}
.skeleton-line-medium {
width: 75%;
}
.skeleton-actions {
display: flex;
gap: 8px;
margin-top: auto;
padding-top: 12px;
border-top: 1px solid var(--border-color);
}
.skeleton-btn {
height: 32px;
flex: 1;
border-radius: var(--radius-sm);
background: var(--text-color);
animation: skeletonPulse 1.5s ease-in-out infinite;
}
.displays-grid,
.devices-grid {
display: grid;
@@ -54,7 +107,7 @@ section {
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 12px 20px 20px;
padding: 16px 20px 20px;
position: relative;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
display: flex;
@@ -152,6 +205,17 @@ section {
animation: rotateBorder 4s linear infinite;
}
/* Fallback for browsers without mask-composite support (older Firefox) */
@supports not (mask-composite: exclude) {
.card-running::before {
-webkit-mask: none;
mask: none;
background: none;
border: 2px solid var(--primary-color);
opacity: 0.7;
}
}
@keyframes rotateBorder {
to { --border-angle: 360deg; }
}
@@ -1192,7 +1256,7 @@ ul.section-tip li {
display: flex;
align-items: center;
gap: 12px;
z-index: 1000;
z-index: var(--z-bulk-toolbar);
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.3);
transition: transform 0.25s ease;
white-space: nowrap;