From 2c5a6a596b4b15a81f2ca2fa402ab7f8580d64fb Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Thu, 26 Feb 2026 15:48:01 -0500 Subject: [PATCH] ui: major UX polish and bug fixes for dashboard - Added global loading spinner and page transitions. - Improved sidebar with tooltips and persistent collapsed state. - Fixed chart memory leaks by properly destroying instances on page change. - Unified WebSocket event handling and status indicators. - Refined stat cards, tables, and modal interactions. - Added real backend integration for logout and session management. --- static/css/dashboard.css | 121 +++++++++++++++++++++++++++++++++++- static/index.html | 45 +++++++------- static/js/dashboard.js | 12 ++++ static/js/pages/clients.js | 8 ++- static/js/pages/overview.js | 36 ++++++++++- static/js/websocket.js | 31 +++------ 6 files changed, 202 insertions(+), 51 deletions(-) diff --git a/static/css/dashboard.css b/static/css/dashboard.css index 2014f72d..2e5da3e6 100644 --- a/static/css/dashboard.css +++ b/static/css/dashboard.css @@ -403,6 +403,121 @@ body { border: 1px solid rgba(255, 255, 255, 0.1); } -.ws-dot.connected { background: var(--success); box-shadow: 0 0 8px var(--success); } -.ws-dot.disconnected { background: var(--danger); } -.ws-dot.error { background: var(--warning); } +/* Loading Spinner */ +.spinner-container { + display: none; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2000; +} + +.loading .spinner-container { + display: block; +} + +.spinner { + width: 40px; + height: 40px; + border: 3px solid rgba(99, 102, 241, 0.1); + border-radius: 50%; + border-top-color: var(--primary); + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Page Content Transition */ +.page-content { + padding: 2rem; + animation: fadeIn 0.3s ease-out; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(5px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Sidebar Tooltips (for collapsed state) */ +.sidebar.collapsed .menu-item { + position: relative; +} + +.sidebar.collapsed .menu-item::after { + content: attr(data-tooltip); + position: absolute; + left: 100%; + margin-left: 10px; + background: #1e293b; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 0.75rem; + opacity: 0; + pointer-events: none; + transition: opacity 0.2s; + white-space: nowrap; + z-index: 1001; +} + +.sidebar.collapsed .menu-item:hover::after { + opacity: 1; +} + +/* Card Header Polish */ +.card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.25rem; +} + +.card-title { + font-size: 1rem; + font-weight: 700; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 0.5rem; +} + +/* Table Polish */ +.table { + width: 100%; + border-spacing: 0; +} + +.table th { + background: #f8fafc; + text-align: left; + padding: 0.75rem 1rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #64748b; + border-bottom: 1px solid var(--border-color); +} + +.table td { + padding: 1rem; + border-bottom: 1px solid #f1f5f9; +} + +.table tr:last-child td { + border-bottom: none; +} + +/* Stat Card Hover */ +.stat-card { + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); +} + +.stat-card:hover { + border-color: var(--primary-light); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} diff --git a/static/index.html b/static/index.html index 80d6c045..25232407 100644 --- a/static/index.html +++ b/static/index.html @@ -54,7 +54,7 @@