From 844d86c105a10833d473017ecd2de77fc60bcdd5 Mon Sep 17 00:00:00 2001 From: Claus Lohmar Date: Thu, 23 Jul 2026 09:09:29 +0000 Subject: [PATCH] =?UTF-8?q?style:=20Proxmox=20VE-inspired=20dark=20theme?= =?UTF-8?q?=20=E2=80=94=20pve-*=20class=20naming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrote proxmox.css with consistent pve- prefix matching the Proxmox VE design language: panels with orange-accent headers, clean tables, orange progress bars, green/red/orange badges, subtle shadows. Updated all templates (base, index, _analysis, polling, scp) to use pve-btn, pve-input, pve-select, pve-panel, pve-progress, pve-badge, pve-alert, pve-spinner, pve-hidden, pve-dim, etc. --- frontend/static/proxmox.css | 358 ++++++++++++++++++++++-------- frontend/templates/_analysis.html | 64 +++--- frontend/templates/base.html | 10 +- frontend/templates/index.html | 99 +++++---- frontend/templates/polling.html | 82 ++++--- frontend/templates/scp.html | 83 +++---- 6 files changed, 433 insertions(+), 263 deletions(-) diff --git a/frontend/static/proxmox.css b/frontend/static/proxmox.css index 5a313b8..e35de7e 100644 --- a/frontend/static/proxmox.css +++ b/frontend/static/proxmox.css @@ -1,117 +1,281 @@ -/* Proxmox VE-inspired dark theme for VM Bench */ +/* ═════════════════════════════════════════════════════════ + Proxmox VE-inspired dark theme for VM Bench + ═════════════════════════════════════════════════════════ */ + :root { - --bg: #161616; - --panel: #1e1e1e; - --border: #3a3a3a; - --text: #e0e0e0; - --muted: #999; - --accent: #f48024; /* Proxmox orange */ - --accent-alt: #3892d5; /* blue accent */ - --green: #54b948; - --red: #e8524a; - --yellow: #e5a72e; - --radius: 4px; - --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + --pve-bg: #161616; + --pve-panel-bg: #1e1e1e; + --pve-border: #3a3a3a; + --pve-text: #e0e0e0; + --pve-muted: #888; + --pve-accent: #f48024; /* Proxmox orange */ + --pve-blue: #3892d5; + --pve-green: #54b948; + --pve-red: #e8524a; + --pve-yellow: #e5a72e; + --pve-radius: 4px; + --pve-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; } + * { box-sizing: border-box; margin: 0; padding: 0; } + body { - background: var(--bg); color: var(--text); font-family: var(--font); - font-size: 13px; line-height: 1.5; min-height: 100vh; - display: flex; flex-direction: column; + background: var(--pve-bg); + color: var(--pve-text); + font-family: var(--pve-font); + font-size: 13px; + line-height: 1.5; + min-height: 100vh; + display: flex; + flex-direction: column; } -header { - background: var(--panel); border-bottom: 2px solid var(--accent); - padding: 0.75rem 1.5rem; display: flex; align-items: baseline; gap: 1rem; -} -header .logo { font-size: 1.2rem; font-weight: 700; color: var(--accent); } -header .sub { font-size: 0.8rem; color: var(--muted); } -footer { - margin-top: auto; padding: 0.5rem 1.5rem; font-size: 0.75rem; - color: var(--muted); display: flex; justify-content: space-between; - border-top: 1px solid var(--border); background: var(--panel); -} -.container { max-width: 760px; margin: 0 auto; padding: 2rem 1rem; width: 100%; } -/* Panels */ -.panel { - background: var(--panel); border: 1px solid var(--border); - border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; +/* ── Header ──────────────────────────────────────────────────── */ +.pve-header { + background: var(--pve-panel-bg); + border-bottom: 2px solid var(--pve-accent); + padding: 0.6rem 1.5rem; + display: flex; + align-items: center; + gap: 0.75rem; } -.panel h2 { - font-size: 1rem; color: var(--accent); margin-bottom: 1rem; - padding-bottom: 0.5rem; border-bottom: 1px solid var(--border); +.pve-header .pve-logo { + font-size: 1.1rem; + font-weight: 700; + color: var(--pve-accent); +} +.pve-header .pve-sub { + font-size: 0.75rem; + color: var(--pve-muted); + margin-left: auto; } -.poll-panel { text-align: center; } -/* Forms */ -.form-group { margin-bottom: 1rem; } -label { display: block; margin-bottom: 0.25rem; font-size: 0.8rem; color: var(--muted); } -input, select, button, textarea { - width: 100%; padding: 0.5rem 0.75rem; background: var(--bg); - border: 1px solid var(--border); border-radius: var(--radius); - color: var(--text); font-family: inherit; font-size: 0.85rem; +/* ── Footer ──────────────────────────────────────────────────── */ +.pve-footer { + margin-top: auto; + padding: 0.4rem 1.5rem; + font-size: 0.7rem; + color: var(--pve-muted); + display: flex; + justify-content: space-between; + border-top: 1px solid var(--pve-border); + background: var(--pve-panel-bg); +} + +/* ── Container ───────────────────────────────────────────────── */ +.pve-container { + max-width: 780px; + margin: 0 auto; + padding: 1.5rem 1rem; + width: 100%; +} + +/* ── Panels ──────────────────────────────────────────────────── */ +.pve-panel { + background: var(--pve-panel-bg); + border: 1px solid var(--pve-border); + border-radius: var(--pve-radius); + margin-bottom: 1.25rem; + overflow: hidden; +} +.pve-panel-header { + background: #252525; + padding: 0.65rem 1.25rem; + border-bottom: 1px solid var(--pve-border); + display: flex; + align-items: center; + justify-content: space-between; +} +.pve-panel-title { + font-size: 0.9rem; + font-weight: 600; + color: var(--pve-text); +} +.pve-panel-title::before { + content: ""; + display: inline-block; + width: 4px; + height: 14px; + background: var(--pve-accent); + margin-right: 8px; + vertical-align: middle; + border-radius: 2px; +} +.pve-panel-body { + padding: 1.25rem; +} + +/* ── Buttons ─────────────────────────────────────────────────── */ +.pve-btn { + display: inline-flex; + align-items: center; + gap: 0.3rem; + padding: 0.45rem 1rem; + font-size: 0.8rem; + font-weight: 600; + border: 1px solid var(--pve-border); + border-radius: var(--pve-radius); + background: #2a2a2a; + color: var(--pve-text); + cursor: pointer; + text-decoration: none; + transition: background 0.15s, border-color 0.15s; + white-space: nowrap; +} +.pve-btn:hover { background: #333; border-color: #555; } +.pve-btn:disabled { opacity: 0.5; cursor: not-allowed; } + +.pve-btn-primary { background: var(--pve-accent); color: #fff; border-color: var(--pve-accent); } +.pve-btn-primary:hover { background: #e07a1e; } + +.pve-btn-success { background: var(--pve-green); color: #fff; border-color: var(--pve-green); } +.pve-btn-success:hover { background: #4aa540; } + +.pve-btn-danger { background: var(--pve-red); color: #fff; border-color: var(--pve-red); } +.pve-btn-danger:hover { background: #d9443f; } + +.pve-btn-small { padding: 0.25rem 0.6rem; font-size: 0.72rem; } + +.pve-btn-row { + display: flex; + gap: 0.6rem; + margin-top: 0.75rem; + flex-wrap: wrap; +} + +/* ── Forms ───────────────────────────────────────────────────── */ +.pve-form-group { margin-bottom: 0.85rem; } +.pve-form-group label { + display: block; + margin-bottom: 0.2rem; + font-size: 0.75rem; + color: var(--pve-muted); + font-weight: 600; +} +.pve-input, .pve-select { + width: 100%; + padding: 0.45rem 0.65rem; + background: var(--pve-bg); + border: 1px solid var(--pve-border); + border-radius: var(--pve-radius); + color: var(--pve-text); + font-family: inherit; + font-size: 0.82rem; transition: border-color 0.15s; } -input:focus, select:focus { border-color: var(--accent); outline: none; } -.hint { display: block; font-size: 0.7rem; color: var(--muted); margin-top: 0.25rem; } -.hidden { display: none !important; } -.row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; } -@media (max-width: 520px) { .row { grid-template-columns: 1fr; } } - -/* Buttons */ -button, .btn { - display: inline-block; padding: 0.5rem 1.25rem; font-weight: 600; - font-size: 0.85rem; cursor: pointer; text-decoration: none; - border-radius: var(--radius); transition: opacity 0.15s; +.pve-input:focus, .pve-select:focus { + border-color: var(--pve-accent); + outline: none; + box-shadow: 0 0 0 2px rgba(244,128,36,0.15); } -button, .btn { background: var(--accent); color: #fff; border: none; } -button:hover, .btn:hover { opacity: 0.85; } -.btn-secondary, button.btn-secondary { background: var(--border); color: var(--text); } -.btn-row { display: flex; gap: 0.75rem; margin-top: 1rem; } - -/* Tables */ -table { width: 100%; border-collapse: collapse; margin: 0.75rem 0; } -td { padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--border); font-size: 0.85rem; } -td:first-child { color: var(--muted); width: 35%; } -td:last-child { font-weight: 500; } - -/* Progress bar */ -.progress-bar { - height: 1.25rem; background: var(--bg); border-radius: var(--radius); - overflow: hidden; margin: 1rem 0; +.pve-hint { + display: block; + font-size: 0.68rem; + color: var(--pve-muted); + margin-top: 0.2rem; } -.progress-fill { - height: 100%; background: var(--accent); transition: width 0.4s ease; - display: flex; align-items: center; justify-content: center; - font-size: 0.7rem; font-weight: 700; color: #fff; min-width: 2.5rem; +.pve-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.85rem; +} +@media (max-width: 520px) { .pve-row { grid-template-columns: 1fr; } } + +.pve-hidden { display: none !important; } + +/* ── Tables ──────────────────────────────────────────────────── */ +.pve-table { + width: 100%; + border-collapse: collapse; + margin: 0.5rem 0; +} +.pve-table td { + padding: 0.35rem 0.6rem; + border-bottom: 1px solid var(--pve-border); + font-size: 0.82rem; +} +.pve-table td:first-child { + color: var(--pve-muted); + width: 35%; + font-weight: 600; +} +.pve-table td:last-child { font-weight: 500; } + +/* ── Progress ────────────────────────────────────────────────── */ +.pve-progress { + height: 1.15rem; + background: var(--pve-bg); + border-radius: var(--pve-radius); + overflow: hidden; + margin: 0.6rem 0; +} +.pve-progress-bar { + height: 100%; + background: var(--pve-accent); + transition: width 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.68rem; + font-weight: 700; + color: #fff; + min-width: 2.5rem; } -/* Badges */ -.badge { - display: inline-block; padding: 0.2rem 0.6rem; border-radius: 3px; - font-size: 0.75rem; font-weight: 600; margin-bottom: 0.75rem; +/* ── Badges ──────────────────────────────────────────────────── */ +.pve-badge { + display: inline-block; + padding: 0.2rem 0.55rem; + border-radius: 3px; + font-size: 0.72rem; + font-weight: 600; + margin-bottom: 0.5rem; } -.badge-queued { background: #3b3410; color: var(--yellow); } -.badge-running { background: #1e3a5f; color: var(--accent-alt); } -.badge-completed { background: #1a3a1a; color: var(--green); } -.badge-failed { background: #3a1a1a; color: var(--red); } +.pve-badge-queued { background: #3b3410; color: var(--pve-yellow); } +.pve-badge-running { background: #1e3a5f; color: var(--pve-blue); } +.pve-badge-completed { background: #1a3a1a; color: var(--pve-green); } +.pve-badge-failed { background: #3a1a1a; color: var(--pve-red); } -/* Spinner */ -.spinner { - display: inline-block; width: 0.85rem; height: 0.85rem; - border: 2px solid var(--border); border-top-color: currentColor; - border-radius: 50%; animation: spin 0.6s linear infinite; vertical-align: middle; margin-right: 0.25rem; +/* ── Spinner ─────────────────────────────────────────────────── */ +.pve-spinner { + display: inline-block; + width: 0.8rem; + height: 0.8rem; + border: 2px solid var(--pve-border); + border-top-color: currentColor; + border-radius: 50%; + animation: pve-spin 0.6s linear infinite; + vertical-align: middle; + margin-right: 0.3rem; } -@keyframes spin { to { transform: rotate(360deg); } } +@keyframes pve-spin { to { transform: rotate(360deg); } } -/* Alerts */ -.error { background: #3a1a1a; border: 1px solid var(--red); color: var(--red); - padding: 0.6rem 0.75rem; border-radius: var(--radius); font-size: 0.85rem; } -.success { background: #1a3a1a; border: 1px solid var(--green); color: var(--green); - padding: 0.6rem 0.75rem; border-radius: var(--radius); } -.error-panel h2 { color: var(--red); } +/* ── Alerts ──────────────────────────────────────────────────── */ +.pve-alert { + padding: 0.55rem 0.75rem; + border-radius: var(--pve-radius); + font-size: 0.82rem; + margin-top: 0.5rem; + line-height: 1.5; +} +.pve-alert-error { + background: #3a1a1a; + border: 1px solid var(--pve-red); + color: var(--pve-red); +} +.pve-alert-success { + background: #1a3a1a; + border: 1px solid var(--pve-green); + color: var(--pve-green); +} +.pve-alert-info { + background: #1a2a3a; + border: 1px solid var(--pve-blue); + color: var(--pve-blue); +} -/* Misc */ -.dim { color: var(--muted); } -.confirm-text { color: var(--muted); font-size: 0.85rem; margin: 0.75rem 0; } -code { background: var(--bg); padding: 0.1rem 0.4rem; border-radius: 2px; font-size: 0.8rem; } +/* ── Misc ────────────────────────────────────────────────────── */ +.pve-dim { color: var(--pve-muted); } +.pve-divider { border: none; border-top: 1px solid var(--pve-border); margin: 1rem 0; } +.pve-code { background: var(--pve-bg); padding: 0.1rem 0.4rem; border-radius: 2px; font-size: 0.78rem; } +.pve-center { text-align: center; } diff --git a/frontend/templates/_analysis.html b/frontend/templates/_analysis.html index 93964e4..10012e1 100644 --- a/frontend/templates/_analysis.html +++ b/frontend/templates/_analysis.html @@ -1,16 +1,23 @@ {# Fragment — no