From f6b09ca99e1e57bd5b5d161c9f8a5d67312de1c5 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Wed, 25 Feb 2026 21:32:44 +0100 Subject: [PATCH] ui: brand-consistent button and card styling Replace traffic light colors (green/yellow/red) with brand palette: - Primary actions: blue gradient - Secondary actions: ghost/outline - Destructive actions: ghost with red hover (modals keep filled red) - Running cards: blue glow instead of green border - Bottom-aligned buttons via flexbox column layout Co-Authored-By: Claude Opus 4.6 --- CHANGELOG.md | 9 +++ controller/internal/web/templates/style.css | 82 ++++++++++++++------- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8427520..3506d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## Changelog +### v0.31.6 — UI: Brand-consistent button & card styling (2026-02-25) + +#### Changed +- **Buttons**: Replaced traffic light colors (green/yellow/red) with brand-consistent palette — primary actions use blue gradient, secondary actions use ghost/outline, destructive actions show red tint on hover only (modal confirmations keep filled red) +- **Card borders**: Running apps now show a subtle blue glow instead of green top border; all other states have neutral borders +- **Status badges**: Running state badge uses brand blue instead of green +- **Button alignment**: Cards use flexbox column layout with `margin-top: auto` on actions — buttons always align to the bottom regardless of card content height +- **Dashboard cards**: Left border indicator changed from green to blue for running apps + ### v0.31.5 — Fix Nextcloud-OnlyOffice callback URL + trusted_domains (2026-02-25) #### Fixed diff --git a/controller/internal/web/templates/style.css b/controller/internal/web/templates/style.css index cfe87d5..0de8efc 100644 --- a/controller/internal/web/templates/style.css +++ b/controller/internal/web/templates/style.css @@ -280,20 +280,19 @@ h3 { border-radius: var(--radius); padding: 1rem 1.25rem; border: 1px solid var(--border-color); - border-left: 4px solid var(--gray); + border-left: 4px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; - transition: border-color 0.3s ease, transform 0.2s ease; + transition: border-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease; } .stack-card:hover { border-color: var(--accent-blue); } -.stack-state-green { border-left-color: var(--green); } -.stack-state-red { border-left-color: var(--red); } -.stack-state-yellow { border-left-color: var(--yellow); } -.stack-state-orange { border-left-color: var(--orange); } -.stack-state-gray { border-left-color: var(--gray); } +.stack-card.stack-state-green { + border-left-color: var(--accent-blue); + box-shadow: 0 0 12px rgba(0, 136, 204, 0.1); +} .stack-info { display: flex; align-items: center; @@ -339,17 +338,22 @@ h3 { border-radius: var(--radius); padding: 1.25rem; border: 1px solid var(--border-color); - border-top: 4px solid var(--gray); - transition: border-color 0.3s ease, transform 0.3s ease; + transition: border-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease; + display: flex; + flex-direction: column; } .stack-detail-card:hover { border-color: var(--accent-blue); transform: translateY(-2px); } -.stack-detail-card.stack-state-green { border-top-color: var(--green); } -.stack-detail-card.stack-state-red { border-top-color: var(--red); } -.stack-detail-card.stack-state-orange { border-top-color: var(--orange); } -.stack-detail-card.stack-state-yellow { border-top-color: var(--yellow); } +.stack-detail-card.stack-state-green { + border-color: rgba(0, 136, 204, 0.25); + box-shadow: 0 0 16px rgba(0, 136, 204, 0.12), 0 0 4px rgba(0, 136, 204, 0.08); +} +.stack-detail-card.stack-state-green:hover { + border-color: var(--accent-blue); + box-shadow: 0 0 20px rgba(0, 136, 204, 0.2), 0 0 6px rgba(0, 136, 204, 0.12); +} .stack-detail-header { display: flex; justify-content: space-between; @@ -375,12 +379,12 @@ h3 { font-weight: 600; white-space: nowrap; } -.state-green { background: var(--green-bg); color: var(--green); } +.state-green { background: rgba(0, 136, 204, 0.12); color: var(--accent-light); } .state-red { background: var(--red-bg); color: var(--red); } .state-yellow { background: var(--yellow-bg); color: var(--yellow); } .state-orange { background: var(--orange-bg); color: var(--orange); } .state-gray { background: var(--gray-bg); color: var(--gray); } -.state-text-green { color: var(--green); } +.state-text-green { color: var(--accent-light); } .state-text-red { color: var(--red); } .state-text-orange { color: var(--orange); } .state-text-yellow { color: var(--yellow); } @@ -421,7 +425,8 @@ h3 { .stack-detail-actions { display: flex; gap: .5rem; - margin-top: 1rem; + margin-top: auto; + padding-top: 1rem; flex-wrap: wrap; } @@ -454,11 +459,31 @@ h3 { box-shadow: 0 4px 12px var(--accent-glow); } .btn-primary:hover { box-shadow: 0 6px 20px var(--accent-glow); } -.btn-success { background: var(--green); } -.btn-success:hover { box-shadow: 0 4px 12px rgba(35, 134, 54, 0.3); } -.btn-warning { background: var(--yellow); color: #0d1117; } -.btn-danger { background: var(--red); } -.btn-danger:hover { box-shadow: 0 4px 12px rgba(218, 54, 51, 0.3); } +.btn-success { + background: linear-gradient(135deg, var(--accent-blue), var(--accent-light)); + box-shadow: 0 4px 12px var(--accent-glow); +} +.btn-success:hover { box-shadow: 0 6px 20px var(--accent-glow); } +.btn-warning { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-secondary); +} +.btn-warning:hover { + border-color: var(--accent-blue); + color: var(--accent-light); + background: rgba(0, 136, 204, 0.08); +} +.btn-danger { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-secondary); +} +.btn-danger:hover { + border-color: var(--red); + color: var(--red); + background: var(--red-bg); +} .btn-outline { background: transparent; border: 1px solid var(--border-color); @@ -2483,14 +2508,16 @@ a.stat-card:hover { margin-bottom: 0; } -.btn-danger { +/* Red-filled danger buttons inside modal confirmation dialogs */ +.modal-actions .btn-danger { background: var(--red); color: white; border-color: var(--red); } - -.btn-danger:hover { +.modal-actions .btn-danger:hover { opacity: 0.85; + background: var(--red); + color: white; } /* Cross-drive backup card on deploy page */ @@ -2985,7 +3012,8 @@ a.stat-card:hover { box-shadow: 0 0 0 2px rgba(218, 54, 51, 0.2); } -.btn-danger { +/* Debug page: red-filled danger buttons for destructive debug actions */ +.debug-section .btn-danger { background: var(--red); color: #fff; border: none; @@ -2996,8 +3024,8 @@ a.stat-card:hover { font-weight: 600; transition: background .15s, opacity .15s; } -.btn-danger:hover { background: #e5534b; } -.btn-danger:disabled { opacity: 0.5; cursor: not-allowed; } +.debug-section .btn-danger:hover { background: #e5534b; } +.debug-section .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; } .debug-spinner { display: inline-block;