From a240675f87f0f5ad52c7fdfd65c1320caf60a441 Mon Sep 17 00:00:00 2001 From: host Date: Sat, 25 Jul 2026 04:22:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/styles.css | 421 +++++++++++++++++++++++++--------------- 1 file changed, 266 insertions(+), 155 deletions(-) diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 38a851a..3cbe16b 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1,35 +1,61 @@ /* ============================================================ - Proxmox VPS Panel — UI-стили - Тёмная тема, аккуратные карточки, читаемая типографика. + Proxmox VPS Panel — UI + Linear / Vercel-style: чистые формы, тонкие тени, Inter, + один акцент, без рамок, много воздуха. ============================================================ */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); + :root { - --bg: #0b1120; - --bg-soft: #0f1729; - --surface: #131b2e; - --surface-2: #1a2438; - --surface-3: #232f48; - --border: #26324a; - --border-soft: #1e2942; - --text: #e6edf5; - --text-muted: #8b96a8; - --text-dim: #6b7588; - --accent: #22d3aa; - --accent-dim: #16826a; - --accent-soft: rgba(34, 211, 170, 0.12); - --warn: #f5a623; - --warn-soft: rgba(245, 166, 35, 0.12); + /* Базовые цвета — нейтральная светлая серая шкала (как Linear/Vercel) */ + --bg: #fafafa; + --surface: #ffffff; + --surface-2: #f5f5f5; + --surface-hover: #fafafa; + + /* Текст */ + --text: #0a0a0a; + --text-muted: #6b7280; + --text-dim: #9ca3af; + + /* Границы — почти невидимые, заменены на тени */ + --border: rgba(0, 0, 0, 0.06); + --border-soft: rgba(0, 0, 0, 0.04); + + /* Один акцент — Inter-style синий */ + --accent: #0070f3; + --accent-hover: #005ad1; + --accent-soft: rgba(0, 112, 243, 0.08); + --accent-text: #ffffff; + + /* Семантические цвета */ + --success: #10b981; + --success-soft: rgba(16, 185, 129, 0.08); + --warn: #f59e0b; + --warn-soft: rgba(245, 158, 11, 0.08); --danger: #ef4444; - --danger-soft: rgba(239, 68, 68, 0.12); - --font-mono: "IBM Plex Mono", ui-monospace, monospace; - --font-body: "Inter", system-ui, sans-serif; + --danger-soft: rgba(239, 68, 68, 0.08); + + /* Тени — мягкие, реалистичные */ + --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04); + --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.03); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -1px rgba(0, 0, 0, 0.04); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.06), 0 4px 6px -2px rgba(0, 0, 0, 0.04); + + /* Радиусы */ + --radius-sm: 6px; --radius: 8px; --radius-lg: 12px; - --shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2); - --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.2); + --radius-xl: 16px; + + --font-body: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif; } -* { box-sizing: border-box; } +* { + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} html, body { margin: 0; @@ -37,14 +63,15 @@ html, body { background: var(--bg); color: var(--text); font-family: var(--font-body); - -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.5; + font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11'; } button, input, select, textarea { font-family: inherit; font-size: inherit; + color: inherit; } a { @@ -52,9 +79,12 @@ a { text-decoration: none; transition: color 0.15s ease; } -a:hover { color: #2ee6bb; } +a:hover { color: var(--accent-hover); } + +/* ============================================================ + Layout + ============================================================ */ -/* --- Layout shell --- */ .shell { min-height: 100vh; display: flex; @@ -65,124 +95,163 @@ a:hover { color: #2ee6bb; } display: flex; align-items: center; justify-content: space-between; - padding: 14px 28px; - border-bottom: 1px solid var(--border-soft); + padding: 18px 32px; background: var(--surface); position: sticky; top: 0; z-index: 10; + box-shadow: var(--shadow-xs); } .brand { - font-family: var(--font-mono); font-weight: 600; - letter-spacing: 0.02em; + letter-spacing: -0.01em; font-size: 15px; display: flex; align-items: center; - gap: 8px; + gap: 10px; + color: var(--text); } .brand .prompt { - color: var(--accent); + width: 24px; + height: 24px; + border-radius: 6px; + background: var(--accent); + color: var(--accent-text); + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 12px; font-weight: 700; } .topbar-right { display: flex; align-items: center; - gap: 18px; + gap: 4px; font-size: 14px; color: var(--text-muted); } .topbar-right a { + color: var(--text-muted); + padding: 8px 14px; + border-radius: var(--radius-sm); + font-weight: 500; + transition: all 0.15s ease; +} +.topbar-right a:hover { + background: var(--surface-2); color: var(--text); - padding: 6px 4px; - border-bottom: 2px solid transparent; +} + +.topbar-right .badge { + margin: 0 8px; } -.topbar-right a:hover { color: var(--accent); } .container { max-width: 1200px; margin: 0 auto; - padding: 32px 24px 80px; + padding: 48px 32px 80px; width: 100%; } .page-title { - font-family: var(--font-mono); - font-size: 24px; + font-size: 28px; font-weight: 600; - margin: 0 0 6px; + letter-spacing: -0.02em; + margin: 0 0 8px; color: var(--text); } .page-sub { color: var(--text-muted); - margin: 0 0 28px; - font-size: 14px; + margin: 0 0 36px; + font-size: 15px; } -/* --- Buttons --- */ +/* ============================================================ + Buttons — мягкие тени, без рамок + ============================================================ */ + .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; - padding: 9px 16px; - border-radius: var(--radius); - border: 1px solid var(--border); - background: var(--surface-2); + padding: 10px 16px; + border-radius: var(--radius-sm); + border: none; + background: var(--surface); color: var(--text); cursor: pointer; font-size: 14px; font-weight: 500; - transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease; + box-shadow: var(--shadow-xs); + transition: all 0.15s ease; user-select: none; } -.btn:hover { background: var(--surface-3); border-color: var(--accent-dim); } -.btn:active { transform: translateY(1px); } -.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -.btn:disabled { opacity: 0.5; cursor: not-allowed; } +.btn:hover { + background: var(--surface-hover); + box-shadow: var(--shadow-sm); +} +.btn:active { transform: scale(0.98); } +.btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} .btn-primary { background: var(--accent); - border-color: var(--accent); - color: #06231c; - font-weight: 600; + color: var(--accent-text); + box-shadow: var(--shadow-sm); +} +.btn-primary:hover { + background: var(--accent-hover); + box-shadow: var(--shadow-md); } -.btn-primary:hover { background: #2ee6bb; border-color: #2ee6bb; } .btn-danger { - border-color: rgba(239, 68, 68, 0.4); - color: #ff8a8a; - background: transparent; + background: var(--danger-soft); + color: var(--danger); +} +.btn-danger:hover { + background: var(--danger); + color: white; } -.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); } .btn-sm { - padding: 6px 10px; - font-size: 12px; + padding: 6px 12px; + font-size: 13px; } -/* --- Cards --- */ +/* ============================================================ + Cards — без рамок, только тени + ============================================================ */ + .card { background: var(--surface); - border: 1px solid var(--border-soft); border-radius: var(--radius-lg); - padding: 20px; - box-shadow: var(--shadow); + padding: 24px; + box-shadow: var(--shadow-sm); } .card + .card { margin-top: 16px; } -/* --- Forms --- */ +/* ============================================================ + Forms + ============================================================ */ + .field { display: flex; flex-direction: column; - gap: 6px; - margin-bottom: 16px; + gap: 8px; + margin-bottom: 18px; } .field label { font-size: 13px; @@ -190,76 +259,89 @@ a:hover { color: #2ee6bb; } font-weight: 500; } .field input, .field select, .field textarea { - background: var(--bg-soft); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 10px 12px; + background: var(--surface-2); + border: none; + border-radius: var(--radius-sm); + padding: 11px 14px; color: var(--text); font-size: 14px; - transition: border-color 0.15s ease; + transition: all 0.15s ease; +} +.field input:hover, .field select:hover { + background: var(--surface-hover); } .field input:focus, .field select:focus, .field textarea:focus { outline: none; - border-color: var(--accent); + background: var(--surface); box-shadow: 0 0 0 3px var(--accent-soft); } -.field input::placeholder, .field textarea::placeholder { color: var(--text-dim); } +.field input::placeholder { color: var(--text-dim); } + +/* ============================================================ + Banners + ============================================================ */ -/* --- Banners / Errors --- */ .error-box { background: var(--danger-soft); - border: 1px solid rgba(239, 68, 68, 0.4); - color: #ffb4b4; - padding: 12px 14px; + color: var(--danger); + padding: 12px 16px; border-radius: var(--radius); - font-size: 13px; + font-size: 14px; margin-bottom: 16px; } .success-box { - background: var(--accent-soft); - border: 1px solid rgba(34, 211, 170, 0.4); - color: var(--accent); - padding: 12px 14px; + background: var(--success-soft); + color: var(--success); + padding: 12px 16px; border-radius: var(--radius); - font-size: 13px; + font-size: 14px; margin-bottom: 16px; } -/* --- Auth page --- */ +/* ============================================================ + Auth + ============================================================ */ + .auth-wrap { - max-width: 380px; + max-width: 400px; margin: 100px auto; } -.auth-wrap .card { padding: 32px; } +.auth-wrap .card { padding: 36px; } +.auth-wrap .page-title { text-align: center; } +.auth-wrap .page-sub { text-align: center; margin-bottom: 28px; } +.auth-wrap .btn { width: 100%; padding: 12px; font-size: 15px; } + +/* ============================================================ + Instance grid + ============================================================ */ -/* --- Instance grid --- */ .instance-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); - gap: 16px; + grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); + gap: 20px; } .instance-card { background: var(--surface); - border: 1px solid var(--border-soft); border-radius: var(--radius-lg); - padding: 18px; + padding: 22px; display: flex; flex-direction: column; - gap: 10px; - transition: border-color 0.15s ease, transform 0.1s ease; + gap: 14px; + box-shadow: var(--shadow-sm); + transition: box-shadow 0.2s ease; +} +.instance-card:hover { + box-shadow: var(--shadow-md); } -.instance-card:hover { border-color: var(--border); } .status-row { display: flex; align-items: center; gap: 8px; - font-family: var(--font-mono); - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.06em; + font-size: 12px; + font-weight: 500; color: var(--text-muted); } @@ -267,20 +349,23 @@ a:hover { color: #2ee6bb; } width: 8px; height: 8px; border-radius: 50%; - background: var(--text-muted); + background: var(--text-dim); flex-shrink: 0; } .dot.running { - background: var(--accent); - box-shadow: 0 0 0 3px var(--accent-soft); + background: var(--success); + box-shadow: 0 0 0 3px var(--success-soft); } -.dot.stopped { background: var(--text-muted); } +.dot.stopped { background: var(--text-dim); } .dot.creating { background: var(--warn); animation: pulse 1.4s infinite; box-shadow: 0 0 0 3px var(--warn-soft); } -.dot.error { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); } +.dot.error { + background: var(--danger); + box-shadow: 0 0 0 3px var(--danger-soft); +} @keyframes pulse { 0%, 100% { opacity: 1; } @@ -288,129 +373,155 @@ a:hover { color: #2ee6bb; } } .instance-name { - font-size: 16px; + font-size: 17px; font-weight: 600; color: var(--text); + letter-spacing: -0.01em; } .instance-name a { color: var(--text); + transition: color 0.15s ease; } .instance-name a:hover { color: var(--accent); } .instance-meta { - font-family: var(--font-mono); - font-size: 12px; + font-size: 13px; color: var(--text-muted); - line-height: 1.6; + line-height: 1.7; } .instance-actions { display: flex; gap: 8px; flex-wrap: wrap; - margin-top: 6px; + margin-top: 8px; } -/* --- Empty state --- */ +/* ============================================================ + Empty state + ============================================================ */ + .empty-state { text-align: center; padding: 80px 20px; color: var(--text-muted); background: var(--surface); - border: 1px dashed var(--border); border-radius: var(--radius-lg); + box-shadow: var(--shadow-xs); } -/* --- Tabs --- */ +/* ============================================================ + Tabs + ============================================================ */ + .nav-tabs { display: flex; - gap: 4px; - margin-bottom: 24px; - border-bottom: 1px solid var(--border-soft); + gap: 8px; + margin-bottom: 28px; } .nav-tab { padding: 10px 16px; font-size: 14px; + font-weight: 500; color: var(--text-muted); cursor: pointer; - border-bottom: 2px solid transparent; - transition: color 0.15s ease, border-color 0.15s ease; + border-radius: var(--radius-sm); + transition: all 0.15s ease; +} +.nav-tab:hover { + background: var(--surface); + color: var(--text); } -.nav-tab:hover { color: var(--text); } .nav-tab.active { - color: var(--accent); - border-color: var(--accent); + background: var(--accent); + color: var(--accent-text); } -/* --- Tables --- */ +/* ============================================================ + Tables + ============================================================ */ + table.data-table { width: 100%; - border-collapse: collapse; + border-collapse: separate; + border-spacing: 0; font-size: 14px; + background: var(--surface); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-sm); } table.data-table th, table.data-table td { text-align: left; - padding: 12px 14px; - border-bottom: 1px solid var(--border-soft); + padding: 14px 18px; } -table.data-table tr:last-child td { border-bottom: none; } table.data-table th { color: var(--text-muted); font-weight: 500; - font-size: 11px; + font-size: 12px; text-transform: uppercase; - letter-spacing: 0.06em; - background: var(--bg-soft); + letter-spacing: 0.04em; + background: var(--surface-2); + border-bottom: 1px solid var(--border-soft); } -table.data-table tr:hover td { background: var(--bg-soft); } +table.data-table td { + border-bottom: 1px solid var(--border-soft); +} +table.data-table tr:last-child td { border-bottom: none; } +table.data-table tr:hover td { background: var(--surface-2); } + +/* ============================================================ + Inline stats + ============================================================ */ -/* --- Inline stat bars --- */ .metric { display: inline-flex; align-items: center; - gap: 6px; + gap: 8px; font-size: 13px; color: var(--text); + font-weight: 500; } .metric-bar { - width: 60px; - height: 8px; - background: var(--surface-3); - border-radius: 4px; + width: 70px; + height: 6px; + background: var(--surface-2); + border-radius: 3px; overflow: hidden; } .metric-bar > span { display: block; height: 100%; - border-radius: 4px; + border-radius: 3px; transition: width 0.5s ease; } -.metric-bar > span.good { background: var(--accent); } +.metric-bar > span.good { background: var(--success); } .metric-bar > span.warn { background: var(--warn); } .metric-bar > span.bad { background: var(--danger); } -/* --- Badges --- */ +/* ============================================================ + Badges + ============================================================ */ + .badge { - font-family: var(--font-mono); - font-size: 11px; - padding: 2px 8px; + display: inline-flex; + align-items: center; + font-size: 12px; + font-weight: 500; + padding: 3px 10px; border-radius: 100px; - border: 1px solid var(--border); color: var(--text-muted); - background: var(--bg-soft); + background: var(--surface-2); } -/* --- Divider --- */ -.hr { - border: none; - border-top: 1px solid var(--border-soft); - margin: 16px 0; -} +/* ============================================================ + Mobile + ============================================================ */ -/* --- Mobile --- */ @media (max-width: 640px) { - .topbar { padding: 12px 16px; } - .container { padding: 24px 16px 64px; } + .topbar { padding: 14px 20px; } + .container { padding: 32px 20px 64px; } .instance-grid { grid-template-columns: 1fr; } - .page-title { font-size: 20px; } + .page-title { font-size: 24px; } + .topbar-right a { padding: 6px 10px; font-size: 13px; } }