feat: add light/dark theme, RU/EN i18n, instructions page, green/red monitoring

- Light and dark theme toggle with localStorage persistence
- Russian and English language support (full i18n)
- Instructions & cheat sheet modal with install/SSH/API/commands
- Green pulsing dot for online, red for offline servers
- Color-coded metrics: green (ok), yellow (warn >70%), red (crit >90%)
- Top bar on server cards: green=online, red=offline

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Андрей Бобырев
2026-05-20 05:55:16 +03:00
parent 468d0bd028
commit 4846742c60
6 changed files with 563 additions and 91 deletions

View File

@@ -1,4 +1,5 @@
:root {
/* Dark Theme (default) */
:root, [data-theme="dark"] {
--bg-primary: #0f0f23;
--bg-secondary: #1a1a3e;
--bg-card: #1e1e4a;
@@ -6,12 +7,36 @@
--text-secondary: #a0a0cc;
--accent: #6366f1;
--accent-hover: #818cf8;
--success: #4ade80;
--danger: #f87171;
--warning: #fbbf24;
--success: #22c55e;
--success-bg: rgba(34, 197, 94, 0.12);
--danger: #ef4444;
--danger-bg: rgba(239, 68, 68, 0.12);
--warning: #f59e0b;
--warning-bg: rgba(245, 158, 11, 0.12);
--border: rgba(255, 255, 255, 0.08);
--radius: 12px;
--shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
--input-bg: #0f0f23;
}
/* Light Theme */
[data-theme="light"] {
--bg-primary: #f8fafc;
--bg-secondary: #ffffff;
--bg-card: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
--accent: #4f46e5;
--accent-hover: #6366f1;
--success: #16a34a;
--success-bg: rgba(22, 163, 74, 0.1);
--danger: #dc2626;
--danger-bg: rgba(220, 38, 38, 0.1);
--warning: #d97706;
--warning-bg: rgba(217, 119, 6, 0.1);
--border: rgba(0, 0, 0, 0.08);
--shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
--input-bg: #f1f5f9;
}
* {
@@ -25,6 +50,7 @@ body {
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
transition: background 0.3s, color 0.3s;
}
/* Login Page */
@@ -33,7 +59,6 @@ body {
align-items: center;
justify-content: center;
min-height: 100vh;
background: linear-gradient(135deg, #0f0f23 0%, #1a1a3e 100%);
}
.login-container {
@@ -81,7 +106,7 @@ body {
.form-group input, .form-group select, .form-group textarea {
width: 100%;
padding: 10px 14px;
background: var(--bg-primary);
background: var(--input-bg);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
@@ -114,8 +139,8 @@ body {
.error-msg {
margin-top: 12px;
padding: 10px;
background: rgba(248, 113, 113, 0.1);
border: 1px solid rgba(248, 113, 113, 0.3);
background: var(--danger-bg);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 8px;
color: var(--danger);
font-size: 13px;
@@ -142,6 +167,7 @@ header {
.header-right {
display: flex;
gap: 8px;
align-items: center;
}
.btn-icon {
@@ -156,10 +182,29 @@ header {
cursor: pointer;
font-size: 16px;
transition: background 0.2s;
color: var(--text-primary);
}
.btn-icon:hover {
background: var(--accent);
color: white;
}
.lang-btn {
padding: 4px 10px;
font-size: 12px;
font-weight: 600;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--bg-card);
color: var(--text-primary);
cursor: pointer;
transition: background 0.2s;
}
.lang-btn:hover {
background: var(--accent);
color: white;
}
/* Main Content */
@@ -183,6 +228,11 @@ main {
border-radius: var(--radius);
padding: 16px;
text-align: center;
transition: transform 0.2s;
}
.stat-item:hover {
transform: translateY(-2px);
}
.stat-item .stat-label {
@@ -204,6 +254,9 @@ main {
/* Toolbar */
.toolbar {
margin-bottom: 20px;
display: flex;
gap: 12px;
align-items: center;
}
.toolbar .btn-primary {
@@ -211,6 +264,22 @@ main {
padding: 10px 20px;
}
.toolbar .btn-secondary {
padding: 10px 20px;
background: var(--bg-card);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: background 0.2s;
}
.toolbar .btn-secondary:hover {
background: var(--accent);
color: white;
}
/* Server Grid */
.servers-grid {
display: grid;
@@ -225,6 +294,25 @@ main {
padding: 20px;
transition: transform 0.2s, box-shadow 0.2s;
cursor: pointer;
position: relative;
overflow: hidden;
}
.server-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
}
.server-card.online::before {
background: var(--success);
}
.server-card.offline::before {
background: var(--danger);
}
.server-card:hover {
@@ -255,18 +343,50 @@ main {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
display: flex;
align-items: center;
gap: 6px;
}
.status-badge.online {
background: rgba(74, 222, 128, 0.15);
background: var(--success-bg);
color: var(--success);
}
.status-badge.offline {
background: rgba(248, 113, 113, 0.15);
background: var(--danger-bg);
color: var(--danger);
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
display: inline-block;
}
.status-dot.online {
background: var(--success);
box-shadow: 0 0 8px var(--success);
animation: pulse-green 2s infinite;
}
.status-dot.offline {
background: var(--danger);
box-shadow: 0 0 8px var(--danger);
animation: pulse-red 2s infinite;
}
@keyframes pulse-green {
0%, 100% { box-shadow: 0 0 4px var(--success); }
50% { box-shadow: 0 0 12px var(--success); }
}
@keyframes pulse-red {
0%, 100% { box-shadow: 0 0 4px var(--danger); }
50% { box-shadow: 0 0 12px var(--danger); }
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
@@ -288,6 +408,7 @@ main {
.metric-item .value {
font-size: 18px;
font-weight: 700;
color: var(--success);
}
.metric-item .value.warn { color: var(--warning); }
@@ -335,6 +456,7 @@ main {
.server-card-actions button:hover {
background: var(--accent);
border-color: var(--accent);
color: white;
}
.server-card-actions button.danger:hover {
@@ -374,6 +496,10 @@ main {
height: 80vh;
}
.modal-content.modal-wide {
max-width: 700px;
}
.modal-header {
display: flex;
align-items: center;
@@ -401,6 +527,7 @@ main {
.btn-close:hover {
background: var(--danger);
color: white;
}
.modal-content h3 {
@@ -411,6 +538,59 @@ main {
letter-spacing: 0.5px;
}
/* Instructions */
.instructions-section {
margin-bottom: 20px;
}
.instr-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px;
margin-bottom: 12px;
}
.instr-card h4 {
font-size: 14px;
margin-bottom: 8px;
color: var(--accent);
}
.instr-card p {
font-size: 13px;
color: var(--text-secondary);
line-height: 1.5;
}
.instr-card code {
display: block;
margin-top: 8px;
padding: 8px 12px;
background: var(--bg-primary);
border-radius: 6px;
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: 12px;
color: var(--success);
overflow-x: auto;
white-space: nowrap;
}
.instr-card .cmd-list {
list-style: none;
margin-top: 8px;
}
.instr-card .cmd-list li {
padding: 6px 12px;
background: var(--bg-primary);
border-radius: 4px;
margin-bottom: 4px;
font-family: monospace;
font-size: 12px;
color: var(--text-primary);
}
/* Terminal */
#terminal-container {
width: 100%;
@@ -426,4 +606,5 @@ main {
.servers-grid { grid-template-columns: 1fr; }
.stats-bar { flex-direction: column; gap: 8px; }
header { padding: 12px 16px; }
.header-right { gap: 4px; }
}