diff --git a/static/css/dashboard.css b/static/css/dashboard.css index fdb9a123..15094479 100644 --- a/static/css/dashboard.css +++ b/static/css/dashboard.css @@ -6,7 +6,7 @@ } :root { - /* ... existing colors ... */ + /* Color Palette - Modern SaaS Darkish Theme */ --primary: #6366f1; --primary-dark: #4f46e5; --primary-light: #818cf8; @@ -86,7 +86,7 @@ body { } .sidebar-header { - padding: var(--spacing-lg); + padding: 0 var(--spacing-lg); display: flex; align-items: center; justify-content: space-between; @@ -94,21 +94,38 @@ body { border-bottom: 1px solid rgba(255, 255, 255, 0.05); } -.sidebar.collapsed .sidebar-header { +.sidebar-toggle { + background: rgba(255, 255, 255, 0.05); + border: none; + color: var(--text-white); + width: 32px; + height: 32px; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; justify-content: center; - padding: var(--spacing-sm); + transition: all 0.2s; + opacity: 0.7; + flex-shrink: 0; } -.sidebar.collapsed .logo span { +.sidebar-toggle:hover { + background: rgba(255, 255, 255, 0.1); + opacity: 1; +} + +.sidebar.collapsed .sidebar-header { + justify-content: center; + padding: 0; +} + +.sidebar.collapsed .logo { display: none; } .sidebar.collapsed .sidebar-toggle { - display: none; /* Hide toggle when collapsed to simplify, or center it */ -} - -.sidebar.collapsed .logo { - justify-content: center; + opacity: 1; } .logo { @@ -119,6 +136,7 @@ body { font-weight: 800; letter-spacing: -0.025em; overflow: hidden; + white-space: nowrap; } .logo i { @@ -188,6 +206,101 @@ body { font-size: 1.25rem; } +/* 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; +} + +.sidebar-footer { + padding: var(--spacing-lg); + border-top: 1px solid rgba(255, 255, 255, 0.05); + display: flex; + align-items: center; + justify-content: space-between; + min-height: 70px; +} + +.sidebar.collapsed .sidebar-footer { + justify-content: center; + 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: rgba(255, 255, 255, 0.1); + 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; +} + +.user-role { + font-size: 0.75rem; + color: var(--text-light); + opacity: 0.7; +} + +.logout-btn { + background: none; + border: none; + color: #94a3b8; + cursor: pointer; + font-size: 1.125rem; + transition: color 0.2s; +} + +.logout-btn:hover { + color: var(--danger); +} + /* Main Content Area */ .main-content { margin-left: 260px; @@ -216,6 +329,12 @@ body { z-index: 100; } +.nav-left .page-title { + font-size: 1.25rem; + font-weight: 700; + color: var(--text-primary); +} + .nav-right { display: flex; align-items: center; @@ -228,9 +347,44 @@ body { gap: var(--spacing-sm); color: var(--text-secondary); font-size: 0.875rem; + cursor: pointer; + transition: color 0.2s; } +.nav-item:hover { + color: var(--primary); +} + +/* 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(--bg-card); padding: var(--spacing-lg); @@ -239,7 +393,14 @@ body { box-shadow: var(--shadow-sm); display: flex; gap: 1.25rem; - align-items: center; /* Center horizontally/vertically */ + align-items: center; + 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); } .stat-icon { @@ -253,19 +414,275 @@ body { flex-shrink: 0; } +.stat-icon.primary { background: rgba(99, 102, 241, 0.1); color: var(--primary); } +.stat-icon.success { background: rgba(16, 185, 129, 0.1); color: var(--success); } +.stat-icon.warning { background: rgba(245, 158, 11, 0.1); color: var(--warning); } +.stat-icon.danger { background: rgba(239, 68, 68, 0.1); color: var(--danger); } + .stat-content { flex: 1; + display: flex; + flex-direction: column; } -/* Grids */ -.grid-2, .grid-3 { - display: grid; - gap: 1.5rem; +.stat-value { + font-size: 1.5rem; + font-weight: 800; + letter-spacing: -0.025em; + line-height: 1.2; +} + +.stat-label { + color: var(--text-secondary); + 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(--success); } +.stat-change.negative { color: var(--danger); } + +/* Generic Cards */ +.card { + background: var(--bg-card); + border-radius: var(--border-radius); + border: 1px solid var(--border-color); + box-shadow: var(--shadow-sm); margin-bottom: 1.5rem; + display: flex; + flex-direction: column; } -.grid-2 { grid-template-columns: repeat(auto-fit, minmax(450px, 1fr)); } -.grid-3 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); } +.card-header { + padding: 1.25rem var(--spacing-lg); + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.card-title { + font-size: 1rem; + font-weight: 700; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.card-body { + padding: var(--spacing-lg); +} + +.card-action-btn { + background: none; + border: none; + color: var(--text-secondary); + cursor: pointer; + font-size: 1rem; + transition: color 0.2s; +} + +.card-action-btn:hover { + color: var(--primary); +} + +/* Tables */ +.table-container { + overflow-x: auto; +} + +.table { + width: 100%; + border-collapse: collapse; +} + +.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; + font-size: 0.875rem; +} + +.table tr:hover td { + background-color: var(--bg-hover); +} + +.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: #dcfce7; color: #166534; } +.status-badge.offline, .status-badge.danger { background: #fee2e2; color: #991b1b; } +.status-badge.warning { background: #fef9c3; color: #854d0e; } + +.badge-client { + background: #f1f5f9; + color: #475569; + padding: 2px 8px; + border-radius: 6px; + font-family: monospace; + font-size: 0.85rem; + border: 1px solid #e2e8f0; +} + +/* Charts */ +.chart-container { + background: white; + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + padding: 1.5rem; +} + +/* 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(--text-secondary); +} + +.form-control input, .form-control textarea, .form-control select { + width: 100%; + border: 1px solid #cbd5e1; + border-radius: 8px; + padding: 0.75rem; + font-family: inherit; + font-size: 0.875rem; + transition: all 0.2s; +} + +.form-control input:focus, .form-control textarea:focus, .form-control select:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1); +} + +.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(--primary); color: white; } +.btn-primary:hover { background: var(--primary-dark); } + +.btn-secondary { background: white; border-color: var(--border-color); color: var(--text-secondary); } +.btn-secondary:hover { background: var(--bg-hover); color: var(--text-primary); } + +.btn-danger { background: var(--danger); color: white; } +.btn-danger:hover { background: #dc2626; } + +/* Modals */ +.modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.6); + 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: white; + border-radius: 16px; + width: 90%; + max-width: 500px; + box-shadow: var(--shadow-lg); + 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(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-title { + font-size: 1.125rem; + font-weight: 700; +} + +.modal-close { + background: none; + border: none; + color: var(--text-secondary); + cursor: pointer; + font-size: 1.25rem; +} + +.modal-body { + padding: 1.5rem; +} + +.modal-footer { + padding: 1.25rem 1.5rem; + border-top: 1px solid var(--border-color); + display: flex; + justify-content: flex-end; + gap: 0.75rem; +} /* WebSocket Dot Pulse */ @keyframes ws-pulse { @@ -286,161 +703,8 @@ body { animation: ws-pulse 2s infinite; } -.status-badge.online, .status-badge.success { background: #dcfce7; color: #166534; } -.status-badge.offline, .status-badge.danger { background: #fee2e2; color: #991b1b; } -.status-badge.warning { background: #fef9c3; color: #854d0e; } - -.badge-client { - background: #f1f5f9; - color: #475569; - padding: 2px 8px; - border-radius: 6px; - font-family: monospace; - font-size: 0.85rem; - border: 1px solid #e2e8f0; -} - -/* Provider Grid */ -.provider-cards-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 1.5rem; -} - -.provider-card { - background: var(--bg-card); - border-radius: var(--border-radius); - border: 1px solid var(--border-color); - overflow: hidden; - transition: all 0.2s; -} - -.provider-card:hover { - box-shadow: var(--shadow-md); - transform: translateY(-2px); -} - -.provider-card-header { - padding: 1.25rem; - border-bottom: 1px solid var(--border-color); - display: flex; - justify-content: space-between; - align-items: center; -} - -.provider-name { - font-size: 1.125rem; - font-weight: 700; -} - -.provider-card-body { - padding: 1.25rem; -} - -.model-tags { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - margin-top: 1rem; -} - -.model-tag { - background: #f1f5f9; - padding: 2px 10px; - border-radius: 6px; - font-size: 0.75rem; - font-weight: 600; - color: #64748b; -} - -/* Forms */ -.form-control label { - font-weight: 600; - margin-bottom: 0.5rem; - font-size: 0.875rem; -} - -.form-control input, .form-control textarea { - border: 1px solid #cbd5e1; - border-radius: 8px; - padding: 0.75rem; - transition: all 0.2s; -} - -.form-control input:focus { - border-color: var(--primary); - box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1); -} - -/* Modals */ -.modal { - background: rgba(15, 23, 42, 0.6); - backdrop-filter: blur(4px); -} - -.modal-content { - border-radius: 16px; - border: none; - box-shadow: var(--shadow-lg); -} - -/* Charts Area */ -.chart-container { - background: white; - border: 1px solid var(--border-color); - border-radius: var(--border-radius); - padding: 1.5rem; -} - -/* Logs Style */ -.log-row { - font-family: 'Inter', sans-serif; -} - -.log-meta { - display: flex; - flex-direction: column; - gap: 4px; -} - -.log-provider { - font-size: 0.75rem; - color: var(--text-light); - text-transform: uppercase; - font-weight: 700; -} - -.log-message-container { - display: flex; - flex-wrap: wrap; - gap: 8px; - align-items: center; -} - -.log-tokens, .log-duration { - font-size: 0.75rem; - color: var(--text-secondary); - background: #f8fafc; - padding: 2px 6px; - border-radius: 4px; -} - -.log-error-msg { - width: 100%; - color: var(--danger); - font-size: 0.8rem; - margin-top: 4px; - font-style: italic; -} - -/* WebSocket Status */ -.ws-status { - background: #0f172a; - color: white; - padding: 6px 16px; - border-radius: 999px; - border: 1px solid rgba(255, 255, 255, 0.1); -} +.ws-dot.disconnected { background: var(--danger); } +.ws-dot.error { background: var(--warning); } /* Loading Spinner */ .spinner-container { @@ -469,94 +733,133 @@ body { 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 { +/* Login Screen */ +.login-container { + min-height: 100vh; display: flex; - justify-content: space-between; align-items: center; - margin-bottom: 1.25rem; + justify-content: center; + background: radial-gradient(circle at top left, #1e293b, #0f172a); + padding: 1.5rem; } -.card-title { - font-size: 1rem; - font-weight: 700; - color: var(--text-primary); - display: flex; +.login-card { + background: var(--bg-primary); + border-radius: var(--border-radius); + box-shadow: var(--shadow-lg); + padding: 3rem; + width: 100%; + max-width: 450px; +} + +.login-header { + text-align: center; + margin-bottom: 2rem; +} + +.login-icon { + font-size: 3rem; + color: var(--primary); + margin-bottom: 1rem; +} + +.login-subtitle { + color: var(--text-secondary); + font-size: 0.875rem; +} + +.login-btn { + width: 100%; + padding: 0.75rem; + margin-top: 1rem; +} + +.error-message { + background: #fef2f2; + color: var(--danger); + padding: 0.75rem; + border-radius: 8px; + margin-bottom: 1.5rem; + font-size: 0.875rem; + display: none; align-items: center; gap: 0.5rem; } -/* Table Polish */ -.table { - width: 100%; - border-spacing: 0; +/* Provider Grid Details */ +.provider-card-header .provider-info { + display: flex; + flex-direction: column; } -.table th { - background: #f8fafc; - text-align: left; - padding: 0.75rem 1rem; +.provider-id { font-size: 0.75rem; + color: var(--text-light); font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; - color: #64748b; - border-bottom: 1px solid var(--border-color); } -.table td { +.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(--text-secondary); +} + +.provider-card-footer { + padding: 1rem 1.25rem; + background: #f8fafc; + border-top: 1px solid var(--border-color); + 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; +} + +.toast { + background: white; + border-radius: 12px; padding: 1rem; - border-bottom: 1px solid #f1f5f9; + box-shadow: var(--shadow-lg); + display: flex; + align-items: center; + gap: 1rem; + min-width: 300px; + border-left: 4px solid var(--primary); + animation: slideIn 0.3s ease-out forwards; } -.table tr:last-child td { - border-bottom: none; +@keyframes slideIn { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } } -/* Stat Card Hover */ -.stat-card { - transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); -} +.toast.success { border-left-color: var(--success); } +.toast.error { border-left-color: var(--danger); } +.toast.warning { border-left-color: var(--warning); } -.stat-card:hover { - border-color: var(--primary-light); - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} +.toast-content { flex: 1; } +.toast-title { font-weight: 700; font-size: 0.875rem; } +.toast-message { font-size: 0.8rem; color: var(--text-secondary); } +.toast-close { background: none; border: none; color: var(--text-light); cursor: pointer; }