From 00f8d707d84801a62282b290f2523d9916e53c1e Mon Sep 17 00:00:00 2001 From: Andrew Simonson Date: Thu, 12 Feb 2026 13:35:24 -0600 Subject: [PATCH] improve css practices --- src/static/css/App.css | 156 +++++++++++++--------------- src/static/js/responsive.js | 3 +- src/static/js/status.js | 46 ++++---- src/templates/partials/project.html | 2 +- src/templates/status.html | 50 ++++----- 5 files changed, 123 insertions(+), 134 deletions(-) diff --git a/src/static/css/App.css b/src/static/css/App.css index e565980..b67e3f5 100755 --- a/src/static/css/App.css +++ b/src/static/css/App.css @@ -453,11 +453,6 @@ tr { margin-bottom: 5px; } -.relative { - position: relative; -} - - .bgi { background-size: contain; background-repeat: no-repeat; @@ -1299,10 +1294,29 @@ tr { display: none; height: 0px; } + + .card-grid { + grid-template-columns: 1fr; + } + + .legend-items { + flex-direction: column; + gap: 0.5em; + } + + .summary-content { + flex-direction: column; + text-align: center; + } + + .summary-indicator { + flex-direction: column; + text-align: center; + } } -/* Status Page Styles */ -.status-subtitle { +/* Reusable Card & State Components */ +.page-subtitle { text-align: center; color: #a8a8a8; margin-top: -10px; @@ -1310,14 +1324,13 @@ tr { font-size: 1rem; } -/* Overall Status Bar */ -/* Overall Status Card - extends status-card */ -.overall-status-card { +/* Summary Card */ +.summary-card { padding: 2em; margin-bottom: 2em; } -.overall-status-content { +.summary-content { display: flex; justify-content: space-between; align-items: center; @@ -1325,29 +1338,29 @@ tr { gap: 2em; } -.overall-status-indicator { +.summary-indicator { display: flex; align-items: center; gap: 1.5em; } -.overall-status-icon { +.summary-icon { font-size: 3rem; line-height: 1; animation: spin 2s linear infinite; } -.overall-status-icon.operational { +.summary-icon.operational { color: #4caf50; animation: pulse-icon 1.5s ease-in-out infinite; } -.overall-status-icon.partial { +.summary-icon.partial { color: #ffc107; animation: pulse-icon 1.5s ease-in-out infinite; } -.overall-status-icon.major { +.summary-icon.major { color: #f44336; animation: pulse-icon 1.5s ease-in-out infinite; } @@ -1362,7 +1375,7 @@ tr { 50% { opacity: 0.5; } } -.overall-status-title { +.summary-title { margin: 0; font-size: 1.5rem; color: #ecebeb; @@ -1386,8 +1399,12 @@ tr { } .metric-label { - font-size: 0.85rem; color: #a8a8a8; + font-size: 0.9rem; +} + +.metric-box .metric-label { + font-size: 0.85rem; margin-top: 0.3em; text-transform: uppercase; letter-spacing: 0.5px; @@ -1413,14 +1430,16 @@ tr { cursor: not-allowed; } -.status-container { +/* Card Grid */ +.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5em; margin-bottom: 2em; } -.status-card { +/* Info Card */ +.info-card { background: rgba(24, 24, 24, 0.85); border-radius: 0.5em; padding: 1.5em; @@ -1428,19 +1447,19 @@ tr { transition: 0.3s; } -.status-card.online { +.info-card.online { border-top-color: rgba(76, 175, 80, 0.8); } -.status-card.degraded { +.info-card.degraded { border-top-color: rgba(255, 193, 7, 0.8); } -.status-card.offline { +.info-card.offline { border-top-color: rgba(244, 67, 54, 0.8); } -.status-header { +.card-header { display: flex; justify-content: space-between; align-items: center; @@ -1449,46 +1468,47 @@ tr { border-bottom: 1px solid rgba(168, 168, 168, 0.2); } -.status-header h3 { +.card-header h3 { margin: 0; font-size: 1.1rem; color: #ecebeb; } -.status-indicator { +/* State Indicators */ +.state-indicator { display: flex; align-items: center; gap: 0.5em; } -.status-text { +.state-text { font-size: 0.85rem; color: #a8a8a8; } -.status-dot { +.state-dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; } -.status-dot.online, .status-dot.complete { +.state-dot.online, .state-dot.complete { background: #4caf50; box-shadow: 0 0 10px #4caf50; } -.status-dot.degraded, .status-dot.WIP { +.state-dot.degraded, .state-dot.WIP { background: #ffc107; box-shadow: 0 0 10px #ffc107; } -.status-dot.offline, .status-dot.incomplete { +.state-dot.offline, .state-dot.incomplete { background: #f44336; box-shadow: 0 0 10px #f44336; } -.status-dot.loading { +.state-dot.loading { background: #a8a8a8; animation: pulse 1.5s ease-in-out infinite; } @@ -1502,30 +1522,25 @@ tr { } } -.status-details { +.card-body { display: flex; flex-direction: column; gap: 0.5em; } -.status-metric { +.metric-row { display: flex; justify-content: space-between; padding: 0.3em 0; } -.metric-label { - color: #a8a8a8; - font-size: 0.9rem; -} - .metric-value { color: #ecebeb; font-size: 0.9rem; font-weight: bold; } -.status-legend { +.info-box { background: rgba(24, 24, 24, 0.85); border-radius: 0.5em; padding: 1.5em; @@ -1533,7 +1548,7 @@ tr { margin-bottom: 2em; } -.status-legend h4 { +.info-box h4 { margin-top: 0; color: #ecebeb; } @@ -1552,80 +1567,53 @@ tr { font-size: 0.9rem; } -.status-note { +.note-text { text-align: center; font-size: 0.85rem; color: #a8a8a8; font-style: italic; } -.status-uptime { +.card-footer { margin-top: 1em; padding-top: 0.8em; border-top: 1px solid rgba(168, 168, 168, 0.2); } -.uptime-label { +.detail-label { color: #a8a8a8; font-size: 0.85rem; margin-bottom: 0.3em; font-weight: bold; } -.uptime-values { +.detail-values { color: #ecebeb; font-size: 0.85rem; line-height: 1.5; } -.uptime-values strong { +.detail-values strong { font-weight: 600; } -/* Uptime color coding based on percentage */ -.uptime-excellent { - color: #4caf50 !important; /* 99%+ - Green */ +/* State color utilities */ +.text-excellent { + color: #4caf50 !important; } -.uptime-good { - color: #8bc34a !important; /* 95-99% - Light green */ +.text-good { + color: #8bc34a !important; } -.uptime-fair { - color: #ffc107 !important; /* 90-95% - Yellow */ +.text-fair { + color: #ffc107 !important; } -.uptime-poor { - color: #f44336 !important; /* <90% - Red */ +.text-poor { + color: #f44336 !important; } -.uptime-none { - color: #888 !important; /* No data - Gray */ -} - -@media screen and (max-width: 1400px) { - .status-container { - grid-template-columns: 1fr; - } - - .status-info { - flex-direction: column; - gap: 1em; - } - - .legend-items { - flex-direction: column; - gap: 0.5em; - } - - .overall-status-content { - flex-direction: column; - text-align: center; - } - - .overall-status-indicator { - flex-direction: column; - text-align: center; - } - +.text-muted { + color: #888 !important; } \ No newline at end of file diff --git a/src/static/js/responsive.js b/src/static/js/responsive.js index fbea260..98cae17 100755 --- a/src/static/js/responsive.js +++ b/src/static/js/responsive.js @@ -2,7 +2,8 @@ function toggleMenu(collapse=false) { if (window.innerWidth < 1400) { const e = document.querySelector(".navControl"); const bar = document.querySelector(".header"); - if (e.style.maxHeight === "0px" && !collapse) { + const isCollapsed = !e.style.maxHeight || e.style.maxHeight === "0px"; + if (isCollapsed && !collapse) { e.style.maxHeight = `${e.scrollHeight + 10}px`; bar.style.borderBottomWidth = "0px"; } else { diff --git a/src/static/js/status.js b/src/static/js/status.js index 8f20c09..b79f239 100644 --- a/src/static/js/status.js +++ b/src/static/js/status.js @@ -61,8 +61,8 @@ function updateServiceCard(service) { const card = document.getElementById(`status-${service.id}`); if (!card) return; - const statusDot = card.querySelector('.status-dot'); - const statusText = card.querySelector('.status-text'); + const stateDot = card.querySelector('.state-dot'); + const stateText = card.querySelector('.state-text'); const timeDisplay = document.getElementById(`time-${service.id}`); const codeDisplay = document.getElementById(`code-${service.id}`); const uptimeDisplay = document.getElementById(`uptime-${service.id}`); @@ -87,24 +87,24 @@ function updateServiceCard(service) { switch (service.status) { case 'online': - statusDot.className = 'status-dot online'; - statusText.textContent = 'Operational'; + stateDot.className = 'state-dot online'; + stateText.textContent = 'Operational'; card.classList.add('online'); break; case 'degraded': case 'timeout': - statusDot.className = 'status-dot degraded'; - statusText.textContent = service.status === 'timeout' ? 'Timeout' : 'Degraded'; + stateDot.className = 'state-dot degraded'; + stateText.textContent = service.status === 'timeout' ? 'Timeout' : 'Degraded'; card.classList.add('degraded'); break; case 'offline': - statusDot.className = 'status-dot offline'; - statusText.textContent = 'Offline'; + stateDot.className = 'state-dot offline'; + stateText.textContent = 'Offline'; card.classList.add('offline'); break; default: - statusDot.className = 'status-dot loading'; - statusText.textContent = 'Unknown'; + stateDot.className = 'state-dot loading'; + stateText.textContent = 'Unknown'; card.classList.add('unknown'); } @@ -114,11 +114,11 @@ function updateServiceCard(service) { // Helper function to get color class based on uptime percentage const getUptimeClass = (value) => { - if (value === null) return 'uptime-none'; - if (value >= 99) return 'uptime-excellent'; - if (value >= 95) return 'uptime-good'; - if (value >= 90) return 'uptime-fair'; - return 'uptime-poor'; + if (value === null) return 'text-muted'; + if (value >= 99) return 'text-excellent'; + if (value >= 95) return 'text-good'; + if (value >= 90) return 'text-fair'; + return 'text-poor'; }; // Helper function to format uptime value @@ -148,9 +148,9 @@ function updateServiceCard(service) { */ function updateOverallStatus(services) { const overallBar = document.getElementById('overallStatus'); - const icon = overallBar.querySelector('.overall-status-icon'); - const title = overallBar.querySelector('.overall-status-title'); - const subtitle = document.getElementById('overall-status-subtitle'); + const icon = overallBar.querySelector('.summary-icon'); + const title = overallBar.querySelector('.summary-title'); + const subtitle = document.getElementById('summary-subtitle'); const onlineCount = document.getElementById('onlineCount'); const totalCount = document.getElementById('totalCount'); @@ -164,7 +164,7 @@ function updateOverallStatus(services) { onlineCount.textContent = online; totalCount.textContent = total; - // Remove all status classes (reuse status-card classes) + // Remove all status classes overallBar.classList.remove('online', 'degraded', 'offline'); icon.classList.remove('operational', 'partial', 'major', 'loading'); @@ -173,21 +173,21 @@ function updateOverallStatus(services) { // All systems operational overallBar.classList.add('online'); icon.classList.add('operational'); - icon.textContent = '✓'; + icon.textContent = '\u2713'; title.textContent = 'All Systems Operational'; subtitle.textContent = `All ${total} services are running normally`; } else if (offline >= Math.ceil(total / 2)) { // Major outage (50% or more offline) overallBar.classList.add('offline'); icon.classList.add('major'); - icon.textContent = '✕'; + icon.textContent = '\u2715'; title.textContent = 'Major Outage'; subtitle.textContent = `${offline} service${offline !== 1 ? 's' : ''} offline, ${degraded} degraded`; } else if (offline > 0 || degraded > 0) { // Partial outage overallBar.classList.add('degraded'); icon.classList.add('partial'); - icon.textContent = '⚠'; + icon.textContent = '\u26A0'; title.textContent = 'Partial Outage'; if (offline > 0 && degraded > 0) { subtitle.textContent = `${offline} offline, ${degraded} degraded`; @@ -199,7 +199,7 @@ function updateOverallStatus(services) { } else { // Unknown state icon.classList.add('loading'); - icon.textContent = '◐'; + icon.textContent = '\u25D0'; title.textContent = 'Status Unknown'; subtitle.textContent = 'Waiting for service data'; } diff --git a/src/templates/partials/project.html b/src/templates/partials/project.html index 412ad97..9391f38 100755 --- a/src/templates/partials/project.html +++ b/src/templates/partials/project.html @@ -2,7 +2,7 @@

{{ title }}

-

{{ status }}

+

{{ status }}

diff --git a/src/templates/status.html b/src/templates/status.html index 7eeddc3..7bd3fa0 100644 --- a/src/templates/status.html +++ b/src/templates/status.html @@ -3,7 +3,7 @@

Service Status Monitor

-
+
Last checked: Loading... @@ -12,33 +12,33 @@
-
+

Status Legend

- + Operational (response successful)
- + Degraded (timeout or errors)
- + Offline (unreachable)
-