diff --git a/static/css/dashboard.css b/static/css/dashboard.css index c1cefb00..78f77fd7 100644 --- a/static/css/dashboard.css +++ b/static/css/dashboard.css @@ -87,7 +87,7 @@ body { /* Utils */ .text-center { text-align: center; } .whitespace-nowrap { white-space: nowrap; } -.code-sm { font-family: monospace; font-size: 0.8rem; background: var(--bg-secondary); color: var(--aqua-light); padding: 2px 4px; border-radius: 4px; } +.code-sm { font-family: monospace; font-size: 0.8rem; background: var(--bg-primary); color: var(--aqua-light); padding: 2px 4px; border-radius: 4px; } /* Dashboard Layout */ .dashboard-container { @@ -152,6 +152,10 @@ body { display: none; } +.sidebar.collapsed .sidebar-toggle { + opacity: 1; +} + .logo { display: flex; align-items: center; @@ -238,12 +242,27 @@ body { /* Sidebar Tooltips */ .sidebar.collapsed .menu-item::after { + content: attr(data-tooltip); + position: absolute; + left: 100%; + margin-left: 10px; background: var(--bg0); color: var(--fg1); + 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; border: 1px solid var(--bg2); } -/* Sidebar Footer */ +.sidebar.collapsed .menu-item:hover::after { + opacity: 1; +} + .sidebar-footer { padding: var(--spacing-lg); border-top: 1px solid var(--bg2); @@ -259,13 +278,57 @@ body { padding: var(--spacing-lg) 0; } +.sidebar.collapsed .user-details, +.sidebar.collapsed .logout-btn { + display: none; +} + +.user-info { + display: flex; + align-items: center; + gap: 0.75rem; + overflow: hidden; +} + .user-avatar { + width: 32px; + height: 32px; + border-radius: 50%; background: var(--bg2); color: var(--fg1); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.user-details { + display: flex; + flex-direction: column; + overflow: hidden; +} + +.user-name { + font-size: 0.875rem; + font-weight: 600; + white-space: nowrap; + text-overflow: ellipsis; + color: var(--fg1); } -.logout-btn { +.user-role { + font-size: 0.75rem; color: var(--fg4); + opacity: 0.7; +} + +.logout-btn { + background: none; + border: none; + color: var(--fg4); + cursor: pointer; + font-size: 1.125rem; + transition: color 0.2s; } .logout-btn:hover { @@ -275,6 +338,11 @@ body { /* Main Content Area */ .main-content { margin-left: 260px; + flex: 1; + min-height: 100vh; + transition: all 0.3s; + display: flex; + flex-direction: column; background-color: var(--bg-primary); } @@ -283,30 +351,101 @@ body { } .top-nav { + height: 70px; background: var(--bg0); border-bottom: 1px solid var(--bg2); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 var(--spacing-xl); + position: sticky; + top: 0; + z-index: 100; } .nav-left .page-title { + font-size: 1.25rem; + font-weight: 700; color: var(--fg0); } +.nav-right { + display: flex; + align-items: center; + gap: var(--spacing-lg); +} + .nav-item { + display: flex; + align-items: center; + gap: var(--spacing-sm); color: var(--fg3); + font-size: 0.875rem; + cursor: pointer; + transition: color 0.2s; } .nav-item:hover { color: var(--orange-light); } -/* Cards */ -.card, .stat-card, .chart-container { +/* Page Content */ +.page-content { + padding: var(--spacing-xl); + flex: 1; + animation: fadeIn 0.3s ease-out; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(5px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Grids */ +.grid-2, .grid-3 { + display: grid; + gap: 1.5rem; + margin-bottom: 1.5rem; +} + +.grid-2 { grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); } +.grid-3 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } + +/* Stat Cards */ +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 1.5rem; + margin-bottom: 1.5rem; +} + +.stat-card { background: var(--bg1); + padding: var(--spacing-lg); + border-radius: var(--border-radius); border: 1px solid var(--bg2); + box-shadow: var(--shadow-sm); + display: flex; + gap: 1.25rem; + align-items: center; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); } .stat-card:hover { border-color: var(--orange); + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +.stat-icon { + width: 48px; + height: 48px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; + flex-shrink: 0; } .stat-icon.primary { background: rgba(214, 93, 14, 0.1); color: var(--orange); } @@ -314,26 +453,130 @@ body { .stat-icon.warning { background: rgba(215, 153, 33, 0.1); color: var(--yellow-light); } .stat-icon.danger { background: rgba(204, 36, 29, 0.1); color: var(--red-light); } -.stat-value { color: var(--fg0); } -.stat-label { color: var(--fg3); } +.stat-content { + flex: 1; + display: flex; + flex-direction: column; +} + +.stat-value { + font-size: 1.5rem; + font-weight: 800; + letter-spacing: -0.025em; + line-height: 1.2; + color: var(--fg0); +} + +.stat-label { + color: var(--fg3); + font-size: 0.875rem; + font-weight: 500; + margin-bottom: 2px; +} + +.stat-change { + font-size: 0.75rem; + font-weight: 600; + margin-top: 4px; +} + +.stat-change.positive { color: var(--green-light); } +.stat-change.negative { color: var(--red-light); } + +/* Generic Cards */ +.card { + background: var(--bg1); + border-radius: var(--border-radius); + border: 1px solid var(--bg2); + box-shadow: var(--shadow-sm); + margin-bottom: 1.5rem; + display: flex; + flex-direction: column; +} + +.card-header { + padding: 1.25rem var(--spacing-lg); + border-bottom: 1px solid var(--bg2); + display: flex; + justify-content: space-between; + align-items: center; +} + +.card-title { + font-size: 1rem; + font-weight: 700; + color: var(--fg1); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.card-body { + padding: var(--spacing-lg); +} + +.card-action-btn { + background: none; + border: none; + color: var(--fg4); + cursor: pointer; + font-size: 1rem; + transition: color 0.2s; +} + +.card-action-btn:hover { + color: var(--orange); +} /* Tables */ +.table-container { + overflow-x: auto; +} + +.table { + width: 100%; + border-collapse: collapse; +} + .table th { background: var(--bg2); + text-align: left; + padding: 0.75rem 1rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; color: var(--fg2); border-bottom: 1px solid var(--bg3); } .table td { - color: var(--fg1); + padding: 1rem; border-bottom: 1px solid var(--bg2); + font-size: 0.875rem; + color: var(--fg1); } .table tr:hover td { background-color: var(--bg2); } +.table tr:last-child td { + border-bottom: none; +} + /* Badges */ +.status-badge { + padding: 0.25rem 0.75rem; + border-radius: 9999px; + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + display: inline-flex; + align-items: center; + gap: 0.375rem; +} + .status-badge.online, .status-badge.success { background: rgba(184, 187, 38, 0.2); color: var(--green-light); } .status-badge.offline, .status-badge.danger { background: rgba(251, 73, 52, 0.2); color: var(--red-light); } .status-badge.warning { background: rgba(250, 189, 47, 0.2); color: var(--yellow-light); } @@ -341,55 +584,276 @@ body { .badge-client { background: var(--bg2); color: var(--blue-light); + padding: 2px 8px; + border-radius: 6px; + font-family: monospace; + font-size: 0.85rem; border: 1px solid var(--bg3); } -/* Forms */ -.form-control label { color: var(--fg2); } -.form-control input, .form-control textarea, .form-control select { - background: var(--bg0); - border-color: var(--bg3); - color: var(--fg1); +/* Charts */ +.chart-container { + background: var(--bg1); + border: 1px solid var(--bg2); + border-radius: var(--border-radius); + padding: 1.5rem; } -.form-control input:focus { +/* Forms */ +.form-control { + margin-bottom: 1.25rem; +} + +.form-control label { + display: block; + font-weight: 600; + margin-bottom: 0.5rem; + font-size: 0.875rem; + color: var(--fg2); +} + +.form-control input, .form-control textarea, .form-control select { + width: 100%; + background: var(--bg0); + border: 1px solid var(--bg3); + border-radius: 8px; + padding: 0.75rem; + font-family: inherit; + font-size: 0.875rem; + color: var(--fg1); + transition: all 0.2s; +} + +.form-control input:focus, .form-control textarea:focus, .form-control select:focus { + outline: none; border-color: var(--orange); box-shadow: 0 0 0 2px rgba(214, 93, 14, 0.2); } +.btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 1.25rem; + border-radius: 8px; + font-weight: 600; + font-size: 0.875rem; + cursor: pointer; + transition: all 0.2s; + border: 1px solid transparent; +} + .btn-primary { background: var(--orange); color: var(--bg0); } .btn-primary:hover { background: var(--orange-light); } .btn-secondary { background: var(--bg2); border-color: var(--bg3); color: var(--fg1); } .btn-secondary:hover { background: var(--bg3); color: var(--fg0); } +.btn-danger { background: var(--red); color: var(--fg0); } +.btn-danger:hover { background: var(--red-light); } + /* Modals */ +.modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.8); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; + opacity: 0; + visibility: hidden; + transition: all 0.2s; +} + +.modal.active { + opacity: 1; + visibility: visible; +} + .modal-content { background: var(--bg1); + border-radius: 16px; + width: 90%; + max-width: 500px; + box-shadow: var(--shadow-lg); border: 1px solid var(--bg3); + transform: translateY(20px); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.modal.active .modal-content { + transform: translateY(0); +} + +.modal-header { + padding: 1.25rem 1.5rem; + border-bottom: 1px solid var(--bg2); + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-title { + font-size: 1.125rem; + font-weight: 700; + color: var(--fg0); +} + +.modal-close { + background: none; + border: none; + color: var(--fg4); + cursor: pointer; + font-size: 1.25rem; +} + +.modal-body { + padding: 1.5rem; color: var(--fg1); } -.modal-header { border-bottom-color: var(--bg2); } -.modal-footer { border-top-color: var(--bg2); } +.modal-footer { + padding: 1.25rem 1.5rem; + border-top: 1px solid var(--bg2); + display: flex; + justify-content: flex-end; + gap: 0.75rem; +} + +/* WebSocket Dot Pulse */ +@keyframes ws-pulse { + 0% { box-shadow: 0 0 0 0 rgba(184, 187, 38, 0.4); } + 70% { box-shadow: 0 0 0 10px rgba(184, 187, 38, 0); } + 100% { box-shadow: 0 0 0 0 rgba(184, 187, 38, 0); } +} + +.ws-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--fg4); +} -/* WebSocket Dot */ .ws-dot.connected { background: var(--green-light); - box-shadow: 0 0 8px var(--green-light); + animation: ws-pulse 2s infinite; +} + +.ws-dot.disconnected { background: var(--red); } +.ws-dot.error { background: var(--yellow); } + +/* 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(254, 128, 25, 0.1); + border-radius: 50%; + border-top-color: var(--orange); + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Provider Grid Details */ +.provider-card-header .provider-info { + display: flex; + flex-direction: column; +} + +.provider-id { + font-size: 0.75rem; + color: var(--fg4); + font-weight: 600; +} + +.provider-meta { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-bottom: 1rem; +} + +.meta-item { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.875rem; + color: var(--fg3); +} + +.provider-card-footer { + padding: 1rem 1.25rem; + background: var(--bg0); + border-top: 1px solid var(--bg2); + display: flex; + gap: 0.75rem; +} + +.btn-sm { + padding: 0.4rem 0.75rem; + font-size: 0.75rem; +} + +/* Toast Container */ +.toast-container { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + z-index: 3000; + display: flex; + flex-direction: column; + gap: 0.75rem; } -/* Toasts */ .toast { background: var(--bg2); + border-radius: 12px; + padding: 1rem; + box-shadow: var(--shadow-lg); + display: flex; + align-items: center; + gap: 1rem; + min-width: 300px; + border-left: 4px solid var(--orange); color: var(--fg1); - border-left-color: var(--orange); + animation: slideIn 0.3s ease-out forwards; } -.toast.success { border-left-color: var(--green); } -.toast.error { border-left-color: var(--red); } +@keyframes slideIn { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} -/* Scrollbars for Gruvbox */ +.toast.success { border-left-color: var(--green-light); } +.toast.error { border-left-color: var(--red-light); } +.toast.warning { border-left-color: var(--yellow-light); } + +.toast-content { flex: 1; } +.toast-title { font-weight: 700; font-size: 0.875rem; color: var(--fg0); } +.toast-message { font-size: 0.8rem; color: var(--fg3); } +.toast-close { background: none; border: none; color: var(--fg4); cursor: pointer; } + +/* Scrollbars */ ::-webkit-scrollbar { width: 8px; height: 8px;