diff --git a/src/main.js b/src/main.js index 78a8058..202f003 100755 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,15 @@ import './style.css' +import './styles/sidebar.css' +import './styles/login.css' +import './styles/dashboard.css' +import './styles/facturas.css' +import './styles/clients.css' +import './styles/create-invoice.css' +import './styles/settings.css' import { initRouter } from './router.js' import { initSessionManager } from './services/session.js' +import { initTheme } from './services/theme.js' +initTheme() initSessionManager() initRouter() diff --git a/src/pages/DashboardPage.js b/src/pages/DashboardPage.js index 92b642e..1b4f49e 100644 --- a/src/pages/DashboardPage.js +++ b/src/pages/DashboardPage.js @@ -66,14 +66,13 @@ function getStatusBadge(status) { return `${s.label}`; } -function statusDotStyle(status) { +function statusDotClass(status) { const map = { - paid: { bg: '#f0fdf4', color: '#16a34a' }, - unpaid: { bg: '#fffbeb', color: '#b45309' }, - draft: { bg: '#f3f4f6', color: '#6b7280' }, + paid: 'status-paid', + unpaid: 'status-unpaid', + draft: 'status-draft', }; - const s = map[status] || map.draft; - return `background:${s.bg};color:${s.color}`; + return map[status] || 'status-draft'; } function openInvoiceModal(invoiceId) { @@ -317,7 +316,7 @@ export function renderDashboard() { } else { recentList.innerHTML = recent.map(inv => `
-
+
diff --git a/src/pages/SettingsPage.js b/src/pages/SettingsPage.js index e69de29..df5a54b 100644 --- a/src/pages/SettingsPage.js +++ b/src/pages/SettingsPage.js @@ -0,0 +1,121 @@ +import { isDarkTheme, toggleTheme } from '../services/theme.js'; + +function decodeTokenPayload(token) { + try { + const payloadPart = token.split('.')[1]; + if (!payloadPart) return null; + const base64 = payloadPart.replace(/-/g, '+').replace(/_/g, '/'); + return JSON.parse(atob(base64)); + } catch { + return null; + } +} + +function formatSeconds(totalSeconds) { + if (totalSeconds <= 0) return 'Expirada'; + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + const hh = String(hours).padStart(2, '0'); + const mm = String(minutes).padStart(2, '0'); + const ss = String(seconds).padStart(2, '0'); + return `${hh}:${mm}:${ss}`; +} + +function getTokenExpirationInfo() { + const token = localStorage.getItem('token'); + if (!token) { + return { hasToken: false, expiresAtText: 'No hay token', remainingText: 'No autenticado' }; + } + + const payload = decodeTokenPayload(token); + if (!payload || !payload.exp) { + return { hasToken: true, expiresAtText: 'No disponible', remainingText: 'No disponible' }; + } + + const expiresAtMs = payload.exp * 1000; + const nowMs = Date.now(); + const remainingSeconds = Math.max(0, Math.floor((expiresAtMs - nowMs) / 1000)); + + return { + hasToken: true, + expiresAtText: new Date(expiresAtMs).toLocaleString('es-ES'), + remainingText: formatSeconds(remainingSeconds), + remainingSeconds + }; +} + +export function renderSettingsPage() { + const container = document.createElement('div'); + container.className = 'settings-page'; + + container.innerHTML = ` +
+

Configuracion

+

Preferencias visuales y estado de sesion.

+
+ +
+
+

Apariencia

+
+
+

Modo oscuro

+

Cambia entre tema claro y oscuro.

+
+ +
+
+ +
+

Sesion

+
+
+ Caducidad del token + - +
+
+ Tiempo restante + - +
+
+
+
+ `; + + const themeBtn = container.querySelector('#settings-theme-toggle'); + const expireAtEl = container.querySelector('#token-expire-at'); + const remainingEl = container.querySelector('#token-remaining'); + + const renderThemeButton = () => { + const dark = isDarkTheme(); + themeBtn.textContent = dark ? 'Activado' : 'Desactivado'; + themeBtn.setAttribute('aria-pressed', dark ? 'true' : 'false'); + }; + + const renderTokenInfo = () => { + const info = getTokenExpirationInfo(); + expireAtEl.textContent = info.expiresAtText; + remainingEl.textContent = info.remainingText; + + if (info.remainingSeconds === 0 && info.hasToken) { + remainingEl.classList.add('settings-token-expired'); + } else { + remainingEl.classList.remove('settings-token-expired'); + } + }; + + renderThemeButton(); + renderTokenInfo(); + + themeBtn.addEventListener('click', () => { + toggleTheme(); + renderThemeButton(); + }); + + const intervalId = setInterval(renderTokenInfo, 1000); + container.cleanup = () => clearInterval(intervalId); + + return container; +} diff --git a/src/pages/pagesRegistry.js b/src/pages/pagesRegistry.js index ed59fb5..2c6da94 100755 --- a/src/pages/pagesRegistry.js +++ b/src/pages/pagesRegistry.js @@ -2,6 +2,7 @@ import { renderDashboard } from './DashboardPage.js'; import { renderFacturasPage } from './Facturas.js'; import { renderCreateInvoicePage } from './CreateInvoicePage.js'; import { renderClientesPage } from './ClientesPage.js'; +import { renderSettingsPage } from './SettingsPage.js'; // Registry of all pages available in the application export const pagesRegistry = [ @@ -43,11 +44,7 @@ export const pagesRegistry = [ icon: '', requiresAuth: true, showInSidebar: true, - render: () => { - const div = document.createElement('div'); - div.innerHTML = '

Configuración

Página en construcción...

'; - return div; - } + render: renderSettingsPage } ]; diff --git a/src/router.js b/src/router.js index 89ac757..77a0993 100755 --- a/src/router.js +++ b/src/router.js @@ -3,6 +3,7 @@ import { renderLoginPage } from './pages/LoginPage.js'; import { createSidebar } from './components/Sidebar.js'; import { getAvailablePages, getPageByRoute } from './pages/pagesRegistry.js'; import { showConfirmExitModal } from './components/ConfirmExitModal.js'; +import { applyLoginTheme, applySavedTheme } from './services/theme.js'; // 🔧 Modo DEV: cambiar a false para activar login const DEV_MODE = false; @@ -34,6 +35,7 @@ export function initRouter() { const app = document.querySelector('#app'); let isNavigating = false; let pendingHash = null; + let currentPageCleanup = null; async function navigate(forceNavigate = false) { const hash = window.location.hash || (DEV_MODE ? '#dashboard' : '#login'); @@ -71,6 +73,17 @@ export function initRouter() { return; } + if (typeof currentPageCleanup === 'function') { + currentPageCleanup(); + currentPageCleanup = null; + } + + if (hash === '#login') { + applyLoginTheme(); + } else { + applySavedTheme(); + } + app.innerHTML = ''; // For authenticated routes, add sidebar and main content wrapper @@ -105,6 +118,10 @@ export function initRouter() { // Render page content using registry const pageContent = page.render(); + if (pageContent && typeof pageContent.cleanup === 'function') { + currentPageCleanup = pageContent.cleanup; + } + mainContent.appendChild(pageContent); layout.appendChild(sidebar); layout.appendChild(mainContent); diff --git a/src/services/theme.js b/src/services/theme.js new file mode 100644 index 0000000..f8c326b --- /dev/null +++ b/src/services/theme.js @@ -0,0 +1,78 @@ +const THEME_KEY = 'theme-preference'; + +function getStoredUser() { + try { + const raw = localStorage.getItem('user'); + if (!raw) return null; + const parsed = JSON.parse(raw); + return parsed && typeof parsed === 'object' ? parsed : null; + } catch { + return null; + } +} + +function getUserThemeKey() { + const user = getStoredUser(); + if (!user) return null; + + const identity = user.id || user.userId || user.email || user.username || user.identifier; + if (!identity) return null; + + return `${THEME_KEY}:user:${String(identity).toLowerCase()}`; +} + +function setRootTheme(theme) { + const root = document.documentElement; + const finalTheme = theme === 'dark' ? 'dark' : 'light'; + root.setAttribute('data-theme', finalTheme); + root.style.colorScheme = finalTheme; +} + +function getSystemPrefersDark() { + return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; +} + +export function getSavedTheme() { + const userKey = getUserThemeKey(); + const saved = userKey ? localStorage.getItem(userKey) : localStorage.getItem(THEME_KEY); + if (saved === 'dark' || saved === 'light') return saved; + return getSystemPrefersDark() ? 'dark' : 'light'; +} + +export function applyTheme(theme) { + const finalTheme = theme === 'dark' ? 'dark' : 'light'; + setRootTheme(finalTheme); + + const userKey = getUserThemeKey(); + if (userKey) { + localStorage.setItem(userKey, finalTheme); + return; + } + + localStorage.setItem(THEME_KEY, finalTheme); +} + +export function initTheme() { + applyTheme(getSavedTheme()); +} + +export function toggleTheme() { + const current = document.documentElement.getAttribute('data-theme') || getSavedTheme(); + const next = current === 'dark' ? 'light' : 'dark'; + applyTheme(next); + return next; +} + +export function isDarkTheme() { + const current = document.documentElement.getAttribute('data-theme') || getSavedTheme(); + return current === 'dark'; +} + +// Login should remain neutral and should not persist or inherit cross-user preferences. +export function applyLoginTheme() { + setRootTheme('light'); +} + +export function applySavedTheme() { + setRootTheme(getSavedTheme()); +} diff --git a/src/style.css b/src/style.css index 1895eb6..ba5ac09 100755 --- a/src/style.css +++ b/src/style.css @@ -92,6 +92,74 @@ -moz-osx-font-smoothing: grayscale; } +:root[data-theme='dark'] { + --gray-50: #0f172a; + --gray-100: #111827; + --gray-200: #1f2937; + --gray-300: #374151; + --gray-400: #94a3b8; + --gray-500: #cbd5e1; + --gray-600: #e2e8f0; + --gray-700: #f1f5f9; + --gray-800: #f8fafc; + --gray-900: #ffffff; + + --card-bg: #0b1220; + --border-color: #1f2a3d; + --text-primary: #f8fafc; + --text-secondary: #94a3b8; + --bg-page: #070d18; + --bg-subtle: #0f172a; + color-scheme: dark; +} + +:root[data-theme='dark'] .status-badge, +:root[data-theme='dark'] .status-badge-client { + border: 1px solid rgba(148, 163, 184, 0.2); +} + +:root[data-theme='dark'] .status-paid, +:root[data-theme='dark'] .status-badge-client.status-active { + background-color: rgba(34, 197, 94, 0.18); + color: #86efac; + border-color: rgba(34, 197, 94, 0.35); +} + +:root[data-theme='dark'] .status-overdue, +:root[data-theme='dark'] .status-unpaid, +:root[data-theme='dark'] .status-pending, +:root[data-theme='dark'] .status-badge-client.status-inactive { + background-color: rgba(248, 113, 113, 0.18); + color: #fca5a5; + border-color: rgba(248, 113, 113, 0.35); +} + +:root[data-theme='dark'] .status-draft, +:root[data-theme='dark'] .status-canceled, +:root[data-theme='dark'] .status-badge-client.status-unknown { + background-color: rgba(148, 163, 184, 0.14); + color: #cbd5e1; + border-color: rgba(148, 163, 184, 0.24); +} + +:root[data-theme='dark'] .status-validated { + background-color: rgba(96, 165, 250, 0.18); + color: #93c5fd; + border-color: rgba(96, 165, 250, 0.35); +} + +:root[data-theme='dark'] .invoices-table thead, +:root[data-theme='dark'] .clients-table thead, +:root[data-theme='dark'] .db-monitoring-table thead th { + background: rgba(15, 23, 42, 0.85); +} + +:root[data-theme='dark'] .db-recent-item:hover, +:root[data-theme='dark'] .invoices-table tbody tr:hover, +:root[data-theme='dark'] .clients-table tbody tr:hover { + background-color: rgba(30, 41, 59, 0.65); +} + /* ============================================ Reset & Base ============================================ */ @@ -264,395 +332,6 @@ button:disabled { color: var(--danger); } -/* ============================================ - App Layout with Sidebar - ============================================ */ -.app-layout { - display: flex; - min-height: 100vh; - width: 100%; -} - -/* ============================================ - Sidebar - ============================================ */ -.sidebar { - width: 220px; - background-color: var(--card-bg); - border-right: 1px solid var(--border-color); - display: flex; - flex-direction: column; - transition: width var(--transition-base); - position: relative; - z-index: 100; - flex-shrink: 0; -} - -.sidebar-header { - padding: var(--space-4); - border-bottom: 1px solid var(--border-color); - display: flex; - justify-content: space-between; - align-items: center; - height: 52px; -} - -.sidebar-header h2 { - margin: 0; - font-size: 14px; - font-weight: 600; - color: var(--text-primary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - letter-spacing: -0.01em; -} - -.sidebar-toggle { - background: transparent; - border: none; - cursor: pointer; - padding: var(--space-1); - color: var(--text-secondary); - font-size: 14px; - border-radius: var(--radius-sm); - transition: background-color var(--transition-fast); - display: flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; -} - -.sidebar-toggle:hover { - background-color: var(--gray-100); - border-color: transparent; -} - -.sidebar-nav { - flex: 1; - overflow-y: auto; - padding: var(--space-2) 0; -} - -.sidebar-menu { - list-style: none; - margin: 0; - padding: 0; -} - -.sidebar-menu li { - margin: 0; - padding: 0 var(--space-2); -} - -.sidebar-link { - display: flex; - align-items: center; - gap: var(--space-3); - padding: var(--space-2) var(--space-3); - color: var(--text-secondary); - text-decoration: none; - transition: color var(--transition-fast), background-color var(--transition-fast); - cursor: pointer; - border-radius: var(--radius-md); - font-size: 14px; - font-weight: 400; - margin-bottom: 1px; -} - -.sidebar-link:hover { - background-color: var(--gray-100); - color: var(--text-primary); -} - -.sidebar-link.active { - background-color: var(--blue-50); - color: var(--primary); - font-weight: 500; -} - -.sidebar-icon { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - flex-shrink: 0; -} - -.sidebar-icon svg { - width: 16px; - height: 16px; -} - -.sidebar-text { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -/* Collapsed Sidebar */ -.sidebar.collapsed { - width: 56px; -} - -.sidebar.collapsed .sidebar-header h2, -.sidebar.collapsed .sidebar-text { - opacity: 0; - width: 0; - overflow: hidden; -} - -.sidebar.collapsed .sidebar-icon { - margin-right: 0; -} - -.sidebar.collapsed .sidebar-link { - justify-content: center; - padding: var(--space-2); -} - -/* Main Content Area */ -.main-content { - flex: 1; - overflow-y: auto; - background-color: var(--bg-page); - min-width: 0; -} - -.main-content>div { - max-width: 1280px; - margin: 0 auto; - padding: var(--space-6); -} - -/* ============================================ - Login - ============================================ */ -.login-container { - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - width: 100%; - background: var(--bg-page); -} - -.login-card { - background: var(--card-bg); - padding: var(--space-8); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - width: 100%; - max-width: 380px; - border: 1px solid var(--border-color); -} - -.login-title { - color: var(--text-primary); - margin: 0 0 var(--space-6) 0; - font-size: 1.25rem; - text-align: center; - font-weight: 600; -} - -.form-group { - margin-bottom: var(--space-4); -} - -.form-group label { - display: block; - color: var(--text-secondary); - margin-bottom: var(--space-1); - font-weight: 500; - font-size: 13px; -} - -.form-group input { - width: 100%; - padding: var(--space-2) var(--space-3); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - background: var(--card-bg); - color: var(--text-primary); - font-size: 14px; - font-family: inherit; - box-sizing: border-box; - transition: border-color var(--transition-fast); - height: 36px; -} - -.form-group input:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); -} - -/* ============================================ - Session Warning Modal - ============================================ */ -.session-warning-overlay { - position: fixed; - inset: 0; - background: rgba(17, 24, 39, 0.45); - display: flex; - align-items: center; - justify-content: center; - z-index: 3000; - padding: var(--space-4); -} - -.session-warning-modal { - width: 100%; - max-width: 430px; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: 12px; - box-shadow: var(--shadow-lg); - padding: var(--space-6); -} - -.session-warning-modal h3 { - margin: 0 0 var(--space-3) 0; - font-size: 1.15rem; -} - -.session-warning-modal p { - margin: 0; - color: var(--text-secondary); -} - -.session-warning-actions { - margin-top: var(--space-5); - display: flex; - justify-content: flex-end; - gap: var(--space-2); -} - -/* ============================================ - Connection Lost Modal - ============================================ */ -.connection-lost-overlay { - position: fixed; - inset: 0; - background: rgba(17, 24, 39, 0.55); - display: flex; - align-items: center; - justify-content: center; - z-index: 4000; - padding: var(--space-4); -} - -.connection-lost-modal { - width: 100%; - max-width: 460px; - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: 12px; - box-shadow: var(--shadow-lg); - padding: var(--space-6); -} - -.connection-lost-modal h3 { - margin: 0 0 var(--space-2) 0; - color: var(--danger); -} - -.connection-lost-modal p { - margin: 0; - color: var(--text-secondary); -} - -.connection-lost-sub { - margin-top: var(--space-3) !important; - font-size: 0.92rem; -} - -.connection-lost-login-btn { - margin-top: var(--space-5); - width: 100%; -} - -.session-warning-logout { - background: transparent; - border: 1px solid var(--border-color); - color: var(--text-secondary); -} - -.session-warning-logout:hover { - background: var(--gray-100); -} - -.session-warning-continue { - background: var(--primary); -} - -@media (max-width: 640px) { - .session-warning-actions { - flex-direction: column; - } - - .session-warning-actions button { - width: 100%; - } -} - -.login-button { - width: 100%; - padding: var(--space-2) var(--space-4); - background-color: var(--primary); - color: white; - border: none; - border-radius: var(--radius-md); - font-size: 14px; - font-weight: 500; - cursor: pointer; - transition: background-color var(--transition-fast); - height: 36px; - margin-top: var(--space-2); -} - -.login-button:hover { - background-color: var(--primary-hover); - border-color: transparent; -} - -.login-error { - color: var(--danger); - text-align: center; - margin-top: var(--space-3); - font-size: 13px; -} - -/* ============================================ - Dashboard - ============================================ */ -.dashboard { - max-width: 1280px; - margin: 0 auto; - padding: var(--space-6); -} - -.dashboard-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-6); -} - -.dashboard-header h1 { - font-size: 1.25rem; - font-weight: 600; -} - -.dashboard-content { - background: var(--card-bg); - padding: var(--space-5); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - box-shadow: var(--shadow-xs); -} .logout-button { background-color: transparent; @@ -671,1717 +350,3 @@ button:disabled { border-color: var(--danger); background-color: var(--red-50); } - -/* ============================================ - Facturas Page - ============================================ */ -.facturas-page { - padding: var(--space-6); - max-width: 1400px; - margin: 0 auto; -} - -.facturas-header { - margin-bottom: var(--space-5); -} - -.facturas-header h1 { - font-size: 1.25rem; - font-weight: 600; -} - -.btn-new-invoice { - background-color: var(--primary); - color: white; - padding: var(--space-2) var(--space-4); - border: none; - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 14px; - transition: background-color var(--transition-fast); - height: 36px; -} - -.btn-new-invoice:hover { - background-color: var(--primary-hover); -} - -.facturas-filters { - display: flex; - gap: var(--space-3); - margin-bottom: var(--space-4); - align-items: center; -} - -.search-input, -.filter-status { - padding: var(--space-2) var(--space-3); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - font-size: 14px; - font-family: inherit; - background: var(--card-bg); - color: var(--text-primary); - height: 36px; - transition: border-color var(--transition-fast); -} - -.search-input:focus, -.filter-status:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); -} - -.search-input { - flex: 1; - max-width: 320px; -} - -.filter-status { - min-width: 180px; - cursor: pointer; -} - -/* ============================================ - Tables (Invoices & Clients) - ============================================ */ -.invoices-table-container, -.clients-table-container { - background: var(--card-bg); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - overflow: hidden; - box-shadow: var(--shadow-xs); -} - -.invoices-table, -.clients-table { - width: 100%; - border-collapse: collapse; -} - -.invoices-table thead, -.clients-table thead { - background: var(--gray-50); - border-bottom: 1px solid var(--border-color); -} - -.invoices-table th, -.clients-table th { - font-weight: 500; - color: var(--text-secondary); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 0.04em; - padding: var(--space-3) var(--space-4); - text-align: left; -} - -.invoices-table tbody tr, -.clients-table tbody tr { - border-bottom: 1px solid var(--border-color); - transition: background-color var(--transition-fast); -} - -.invoices-table tbody tr:hover, -.clients-table tbody tr:hover { - background-color: var(--gray-50); -} - -.invoices-table tbody tr:last-child, -.clients-table tbody tr:last-child { - border-bottom: none; -} - -.invoices-table td, -.clients-table td { - padding: var(--space-3) var(--space-4); - font-size: 14px; -} - -.invoice-number { - font-weight: 500; - color: var(--text-primary); -} - -.invoice-client { - display: flex; - align-items: center; - gap: var(--space-2); - color: var(--text-secondary); -} - -.client-icon { - display: flex; - align-items: center; - color: var(--gray-400); -} - -.invoice-date { - color: var(--text-primary); -} - -.invoice-total, -.invoice-remain { - font-weight: 500; - font-variant-numeric: tabular-nums; - color: var(--text-primary); -} - -/* Notes column */ -.invoice-notes { - max-width: 200px; -} - -.notes-preview { - display: flex; - flex-direction: column; - gap: 4px; -} - -.note-badge { - display: inline-flex; - align-items: center; - gap: 4px; - font-size: 0.75rem; - padding: 2px 8px; - border-radius: 12px; - line-height: 1.4; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - cursor: default; -} - -.note-public { - background: rgba(37, 99, 235, 0.08); - color: var(--primary); - border: 1px solid rgba(37, 99, 235, 0.15); -} - -.note-public svg { - flex-shrink: 0; -} - -.note-private { - background: rgba(245, 158, 11, 0.08); - color: #b45309; - border: 1px solid rgba(245, 158, 11, 0.15); -} - -.note-private svg { - flex-shrink: 0; -} - -.no-notes { - color: var(--text-secondary); - font-size: 0.875rem; -} - -.invoice-actions { - display: flex; - gap: var(--space-1); - justify-content: center; -} - -.btn-view, -.btn-action { - background: transparent; - border: none; - padding: var(--space-1); - border-radius: var(--radius-sm); - cursor: pointer; - color: var(--gray-400); - transition: color var(--transition-fast), background-color var(--transition-fast); - display: inline-flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; -} - -.btn-view:hover { - color: var(--primary); - background-color: var(--blue-50); -} - -.btn-action:hover { - background-color: var(--gray-100); - color: var(--text-primary); -} - -.btn-delete:hover { - background-color: var(--red-50); - color: var(--danger); -} - -.loading, -.error, -.no-invoices, -.no-clients { - padding: var(--space-10); - text-align: center; - color: var(--text-secondary); - font-size: 14px; -} - -.error { - color: var(--danger); -} - -/* ============================================ - Pagination - ============================================ */ -.pagination { - display: flex; - justify-content: center; - align-items: center; - gap: var(--space-4); - margin-top: var(--space-4); - padding: var(--space-3) var(--space-4); - background: var(--card-bg); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); -} - -.pagination-info { - font-weight: 500; - color: var(--text-secondary); - font-size: 13px; - display: flex; - gap: var(--space-1); - align-items: center; - font-variant-numeric: tabular-nums; -} - -.pagination-info .current-page, -.pagination-info .total-pages { - font-weight: 600; - color: var(--text-primary); - min-width: 20px; - text-align: center; -} - -.btn-pagination { - padding: var(--space-2) var(--space-3); - background-color: var(--card-bg); - color: var(--text-primary); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 13px; - transition: background-color var(--transition-fast), border-color var(--transition-fast); - display: flex; - align-items: center; - gap: var(--space-1); -} - -.btn-pagination:hover:not(:disabled) { - background-color: var(--gray-50); - border-color: var(--gray-300); -} - -.btn-pagination:disabled { - background-color: var(--gray-50); - color: var(--gray-300); - cursor: not-allowed; - border-color: var(--gray-200); -} - -/* ============================================ - Create Invoice Page - ============================================ */ -.create-invoice-page { - padding: var(--space-6); - max-width: 960px; - margin: 0 auto; - min-height: 100vh; -} - -.invoice-header-compact { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-5); -} - -.invoice-header-compact h1 { - font-size: 1.25rem; - font-weight: 600; -} - -.btn-back { - background: transparent; - color: var(--text-secondary); - border: 1px solid var(--border-color); - padding: var(--space-2) var(--space-3); - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 13px; - transition: border-color var(--transition-fast), color var(--transition-fast); - height: 32px; -} - -.btn-back:hover { - color: var(--text-primary); - border-color: var(--gray-300); - background: transparent; -} - -.invoice-form-compact { - background: var(--card-bg); - border-radius: var(--radius-lg); - border: 1px solid var(--border-color); - padding: var(--space-5); - box-shadow: var(--shadow-xs); -} - -.form-grid-compact { - display: grid; - grid-template-columns: 2fr 1fr 1fr; - gap: var(--space-3); - margin-bottom: var(--space-5); -} - -.notes-grid-compact { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--space-3); - margin-bottom: var(--space-5); -} - -.form-field-compact { - display: flex; - flex-direction: column; -} - -.form-field-compact.full-width { - grid-column: 1 / -1; -} - -.form-field-compact label { - font-weight: 500; - margin-bottom: var(--space-1); - color: var(--text-secondary); - font-size: 13px; -} - -.form-field-compact input, -.form-field-compact select, -.form-field-compact textarea { - padding: var(--space-2) var(--space-3); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - font-size: 14px; - color: var(--text-primary); - background: var(--card-bg); - resize: vertical; - font-family: inherit; - transition: border-color var(--transition-fast); - height: 36px; -} - -.form-field-compact textarea { - height: auto; - min-height: 64px; -} - -.form-field-compact input:focus, -.form-field-compact select:focus, -.form-field-compact textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); -} - -/* Date input wrapper */ -.date-input-wrapper { - position: relative; - display: flex; - align-items: stretch; -} - -.date-input-wrapper input[type="date"] { - flex: 1; - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: none; -} - -.date-input-wrapper input[type="date"]:focus { - z-index: 1; -} - -.date-picker-btn { - display: flex; - align-items: center; - justify-content: center; - padding: 0 0.75rem; - background: var(--primary); - color: white; - border: 1px solid var(--primary); - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; - cursor: pointer; - transition: background 0.2s; -} - -.date-picker-btn:hover { - background: var(--primary-hover, #1d4ed8); -} - -.date-picker-btn:active { - transform: scale(0.96); -} - -.lines-section-compact { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - margin-bottom: var(--space-5); -} - -.lines-header-compact { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--space-3); -} - -.lines-header-compact h3 { - margin: 0; - font-size: 14px; - font-weight: 600; -} - -.btn-add-compact { - background: var(--card-bg); - color: var(--text-primary); - border: 1px solid var(--border-color); - padding: var(--space-1) var(--space-3); - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 13px; - transition: border-color var(--transition-fast); - height: 32px; -} - -.btn-add-compact:hover { - border-color: var(--gray-300); -} - -.lines-table-compact { - flex: 1; - overflow-y: auto; - display: flex; - flex-direction: column; - gap: var(--space-2); -} - -.line-row-compact { - display: grid; - grid-template-columns: 4fr 0.8fr 1.2fr 0.8fr 1.2fr auto; - gap: var(--space-2); - align-items: center; - background: var(--gray-50); - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - padding: var(--space-2) var(--space-3); -} - -.line-desc-compact, -.line-qty-compact, -.line-price-compact, -.line-tax-compact { - padding: var(--space-1) var(--space-2); - border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - font-size: 13px; - background: white; - color: var(--text-primary); - font-family: inherit; - transition: border-color var(--transition-fast); - height: 32px; -} - -.line-desc-compact { - width: 100%; -} - -.line-desc-compact:focus, -.line-qty-compact:focus, -.line-price-compact:focus, -.line-tax-compact:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); -} - -.line-total-compact { - font-weight: 500; - color: var(--text-primary); - font-size: 13px; - text-align: right; - padding-right: var(--space-2); - font-variant-numeric: tabular-nums; -} - -.btn-delete-compact { - background: transparent; - color: var(--gray-400); - border: none; - width: 28px; - height: 28px; - border-radius: var(--radius-sm); - cursor: pointer; - font-size: 16px; - font-weight: 400; - line-height: 1; - display: flex; - align-items: center; - justify-content: center; - transition: color var(--transition-fast), background-color var(--transition-fast); - flex-shrink: 0; - padding: 0; -} - -.btn-delete-compact:hover { - color: var(--danger); - background: var(--red-50); - border-color: transparent; -} - -.form-actions-compact { - display: flex; - justify-content: flex-end; - gap: var(--space-2); - padding-top: var(--space-4); - border-top: 1px solid var(--border-color); -} - -.btn-cancel-compact { - background: transparent; - color: var(--text-secondary); - border: 1px solid var(--border-color); - padding: var(--space-2) var(--space-4); - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 14px; - transition: border-color var(--transition-fast), color var(--transition-fast); - height: 36px; -} - -.btn-cancel-compact:hover { - color: var(--text-primary); - border-color: var(--gray-300); - background: transparent; -} - -.btn-submit-compact { - background: var(--primary); - color: white; - border: none; - padding: var(--space-2) var(--space-5); - border-radius: var(--radius-md); - cursor: pointer; - font-weight: 500; - font-size: 14px; - transition: background-color var(--transition-fast); - height: 36px; -} - -.btn-submit-compact:hover { - background: var(--primary-hover); -} - -.btn-submit-compact:disabled { - background: var(--gray-200); - color: var(--gray-400); - cursor: not-allowed; -} - -/* ============================================ - Clientes Page - ============================================ */ -.clientes-page { - padding: var(--space-6); - max-width: 1400px; - margin: 0 auto; -} - -.clientes-header { - margin-bottom: var(--space-5); -} - -.clientes-header h1 { - font-size: 1.25rem; - font-weight: 600; -} - -.clientes-filters { - display: flex; - gap: var(--space-3); - margin-bottom: var(--space-4); - align-items: center; -} - -.clientes-filters .search-input { - flex: 1; - max-width: 400px; -} - -/* Client table cells */ -.client-avatar-col { - width: 48px; -} - -.client-avatar-cell { - width: 48px; -} - -.client-avatar { - width: 32px; - height: 32px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - color: white; - font-weight: 500; - font-size: 12px; -} - -.client-name-wrapper { - display: flex; - flex-direction: column; - gap: 1px; -} - -.client-company-name { - font-weight: 500; - color: var(--text-primary); -} - -.client-code { - font-size: 11px; - color: var(--text-secondary); - font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace; -} - -.contact-info { - display: flex; - flex-direction: column; - gap: 1px; -} - -.contact-name { - color: var(--text-primary); -} - -.contacts-count { - font-size: 11px; - color: var(--primary); - background: var(--blue-50); - padding: 1px var(--space-2); - border-radius: var(--radius-sm); - display: inline-block; - width: fit-content; - font-weight: 500; -} - -.client-email .email-text { - color: var(--text-secondary); - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - display: inline-block; - font-size: 13px; -} - -.client-phone { - color: var(--text-primary); - font-variant-numeric: tabular-nums; - font-size: 13px; -} - -.client-actions { - text-align: center; -} - -.clients-table .client-actions-col { - width: 60px; - text-align: center; -} - -.clients-table td.client-actions { - text-align: center; - vertical-align: middle; -} - -.clients-table td.client-actions .btn-view { - margin: 0 auto; -} - -/* Client status badge */ -.status-badge-client { - display: inline-flex; - align-items: center; - padding: 2px var(--space-2); - border-radius: var(--radius-sm); - font-size: 12px; - font-weight: 500; - white-space: nowrap; -} - -.status-badge-client.status-active { - background: var(--green-50); - color: var(--green-600); -} - -.status-badge-client.status-inactive { - background: var(--red-50); - color: var(--red-600); -} - -.status-badge-client.status-unknown { - background: var(--gray-100); - color: var(--gray-500); -} - -/* Contacts button */ -.btn-contacts { - position: relative; - background: var(--blue-50); - border: 1px solid rgba(59, 130, 246, 0.15); - color: var(--primary); - border-radius: var(--radius-sm); - padding: 2px var(--space-2); - cursor: pointer; - transition: background-color var(--transition-fast); - display: flex; - align-items: center; - gap: 2px; - font-size: 12px; -} - -.btn-contacts:hover { - background: var(--blue-100); -} - -.btn-contacts.active { - background: var(--primary); - color: white; - border-color: var(--primary); -} - -.contacts-badge { - font-size: 11px; - font-weight: 600; - min-width: 14px; - text-align: center; -} - -/* Expandable contacts row */ -.contacts-expand-row td { - padding: 0 !important; - background: var(--gray-50); -} - -.contacts-expand-content { - padding: var(--space-3) var(--space-4); - border-top: 1px solid var(--border-color); - border-bottom: 2px solid var(--primary); -} - -.contacts-expand-header h4 { - margin: 0 0 var(--space-3) 0; - font-size: 12px; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.04em; - font-weight: 500; -} - -.contacts-expand-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); - gap: var(--space-2); -} - -.contact-expand-card { - background: white; - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - padding: var(--space-3); -} - -.contact-expand-name { - display: flex; - align-items: center; - gap: var(--space-2); - font-weight: 500; - color: var(--text-primary); - margin-bottom: var(--space-2); - font-size: 14px; -} - -.contact-expand-name svg { - color: var(--primary); - flex-shrink: 0; -} - -.contact-expand-details { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2px var(--space-3); - font-size: 12px; - color: var(--text-secondary); -} - -.contact-expand-details span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -/* Client Modal */ -.client-modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.4); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - padding: var(--space-4); -} - -.client-modal { - background: var(--card-bg); - border-radius: var(--radius-lg); - width: 100%; - max-width: 560px; - max-height: 80vh; - overflow: hidden; - display: flex; - flex-direction: column; - box-shadow: var(--shadow-lg); -} - -.client-modal-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: var(--space-4) var(--space-5); - border-bottom: 1px solid var(--border-color); -} - -.client-modal-header h2 { - margin: 0; - font-size: 1.125rem; - font-weight: 600; -} - -.btn-close-modal { - background: transparent; - border: none; - font-size: 18px; - cursor: pointer; - color: var(--text-secondary); - padding: var(--space-1); - border-radius: var(--radius-sm); - transition: color var(--transition-fast), background-color var(--transition-fast); - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; -} - -.btn-close-modal:hover { - background: var(--gray-100); - color: var(--text-primary); -} - -.client-modal-body { - padding: var(--space-5); - overflow-y: auto; -} - -.client-info-section, -.contacts-section { - margin-bottom: var(--space-5); -} - -.client-info-section:last-child, -.contacts-section:last-child { - margin-bottom: 0; -} - -.client-info-section h3, -.contacts-section h3 { - margin: 0 0 var(--space-3) 0; - font-size: 12px; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.04em; - font-weight: 500; -} - -.info-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: var(--space-3); -} - -.info-item { - display: flex; - flex-direction: column; - gap: 1px; -} - -.info-label { - font-size: 11px; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.04em; - font-weight: 500; -} - -.info-value { - font-weight: 500; - color: var(--text-primary); - font-size: 14px; -} - -.contacts-list { - display: flex; - flex-direction: column; - gap: var(--space-3); -} - -.contact-card { - background: var(--card-bg); - border-radius: var(--radius-md); - padding: var(--space-4); - border: 1px solid var(--border-color); -} - -.contact-header { - display: flex; - align-items: center; - gap: var(--space-2); - margin-bottom: var(--space-3); - padding-bottom: var(--space-3); - border-bottom: 1px solid var(--border-color); -} - -.contact-avatar { - width: 28px; - height: 28px; - border-radius: 50%; - background: var(--gray-100); - display: flex; - align-items: center; - justify-content: center; - color: var(--text-secondary); - flex-shrink: 0; -} - -.contact-full-name { - font-weight: 600; - color: var(--text-primary); - font-size: 13px; -} - -.contact-details { - display: flex; - flex-direction: column; - gap: var(--space-2); -} - -.contact-row { - display: flex; - align-items: center; - gap: var(--space-2); - font-size: 13px; - color: var(--text-secondary); -} - -.contact-icon { - display: flex; - align-items: center; - justify-content: center; - color: var(--gray-400); - flex-shrink: 0; - width: 16px; -} - -.no-contacts { - color: var(--text-secondary); - text-align: center; - padding: var(--space-5); - background: var(--gray-50); - border-radius: var(--radius-md); - font-size: 13px; -} - -/* ============================================ - Responsive Design - ============================================ */ -@media (max-width: 768px) { - .sidebar { - position: fixed; - left: 0; - top: 0; - bottom: 0; - z-index: 1000; - transform: translateX(0); - } - - .sidebar.collapsed { - transform: translateX(-100%); - width: 220px; - } - - .main-content { - margin-left: 0; - } - - .facturas-filters, - .clientes-filters { - flex-direction: column; - } - - .search-input { - max-width: 100% !important; - } - - .pagination { - flex-wrap: wrap; - gap: var(--space-3); - } - - .btn-pagination { - flex: 1; - min-width: 100px; - justify-content: center; - } - - .pagination-info { - order: 3; - width: 100%; - justify-content: center; - } - - .create-invoice-page { - padding: var(--space-3); - } - - .form-grid-compact { - grid-template-columns: 1fr; - } - - .form-field-compact.full-width { - grid-column: 1; - } - - .notes-grid-compact { - grid-template-columns: 1fr; - } - - .line-row-compact { - grid-template-columns: 1fr auto; - gap: var(--space-2); - padding: var(--space-3); - } - - .clients-table thead { - display: none; - } - - .clients-table tbody tr.client-item { - display: flex; - flex-wrap: wrap; - padding: var(--space-3); - gap: var(--space-2); - position: relative; - } - - .clients-table tbody tr.contacts-expand-row { - display: block; - } - - .clients-table td { - padding: 0; - } - - .client-avatar-cell { - width: auto; - margin-right: var(--space-3); - } - - .client-name { - flex: 1; - } - - .client-type-col, - .client-type { - display: none; - } - - .client-actions { - position: absolute; - right: var(--space-3); - top: 50%; - transform: translateY(-50%); - } - - .contacts-expand-grid { - grid-template-columns: 1fr; - } - - .info-grid { - grid-template-columns: 1fr; - } -} - -@media (max-width: 1024px) { - - .clientes-page, - .facturas-page { - padding: var(--space-4); - } - - .clients-table th, - .clients-table td { - padding: var(--space-2) var(--space-3); - } - - .client-email-col, - .client-email, - .client-type-col, - .client-type { - display: none; - } -} - -/* ============================================ - Dashboard — New Analytics Layout - ============================================ */ - -/* Header */ -.db-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: var(--space-6); - gap: var(--space-4); -} - -.db-greeting { - font-size: 1.5rem; - font-weight: 700; - color: var(--text-primary); - margin: 0 0 var(--space-1) 0; - letter-spacing: -0.02em; -} - -.db-subtitle { - font-size: 13px; - color: var(--text-secondary); - margin: 0; -} - -/* KPI row */ -.db-kpi-row { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: var(--space-4); - margin-bottom: var(--space-5); -} - -.db-kpi-card { - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - padding: var(--space-5); - box-shadow: var(--shadow-xs); - display: flex; - flex-direction: column; - gap: var(--space-2); - transition: box-shadow var(--transition-fast); -} - -.db-kpi-card:hover { - box-shadow: var(--shadow-sm); -} - -/* KPI card top row */ -.db-kpi-top { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: var(--space-2); -} - -.db-kpi-icon { - width: 28px; - height: 28px; - border-radius: var(--radius-md); - background: var(--gray-100); - display: flex; - align-items: center; - justify-content: center; - color: var(--text-secondary); - flex-shrink: 0; -} - -.db-kpi-label { - font-size: 11px; - font-weight: 500; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.db-kpi-value { - font-size: 1.65rem; - font-weight: 700; - color: var(--text-primary); - letter-spacing: -0.03em; - line-height: 1.1; - min-height: 2rem; -} - -.db-kpi-sub { - font-size: 12px; - color: var(--text-secondary); - min-height: 1rem; -} - -.db-sub-green { - color: var(--green-600); - font-weight: 500; -} - -.db-sub-amber { - color: var(--amber-600); - font-weight: 500; -} - -.db-sub-red { - color: var(--red-600); - font-weight: 500; -} - -.db-sub-muted { - color: var(--text-secondary); -} - -/* Skeleton loaders */ -.db-kpi-skeleton { - display: inline-block; - background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); - background-size: 200% 100%; - animation: db-shimmer 1.4s infinite; - border-radius: var(--radius-sm); - width: 80px; - height: 1.6rem; -} - -.db-kpi-skeleton-sm { - width: 120px; - height: 0.8rem; -} - -@keyframes db-shimmer { - 0% { - background-position: 200% 0; - } - - 100% { - background-position: -200% 0; - } -} - -/* Middle row: chart + recent */ -.db-mid-row { - display: grid; - grid-template-columns: 1fr 340px; - gap: var(--space-4); - margin-bottom: var(--space-5); -} - -/* Shared card styles */ -.db-chart-card, -.db-recent-card, -.db-table-card { - background: var(--card-bg); - border: 1px solid var(--border-color); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-xs); - overflow: hidden; -} - -.db-card-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: var(--space-4) var(--space-5); - border-bottom: 1px solid var(--border-color); -} - -.db-card-title { - font-size: 13px; - font-weight: 600; - color: var(--text-primary); -} - -.db-card-badge, -.db-card-year { - font-size: 12px; - font-weight: 500; - color: var(--text-secondary); - background: var(--gray-100); - padding: 2px 8px; - border-radius: 99px; -} - -.db-see-all { - font-size: 12px; - color: var(--blue-600); - text-decoration: none; - font-weight: 500; -} - -.db-see-all:hover { - text-decoration: underline; -} - -/* Chart body */ -.db-chart-body { - padding: var(--space-5); - height: 260px; - position: relative; -} - -.db-chart-body canvas { - width: 100% !important; - height: 100% !important; -} - -/* Recent list */ -.db-recent-list { - overflow-y: auto; - max-height: 320px; -} - -.db-recent-item { - display: flex; - align-items: center; - gap: var(--space-3); - padding: var(--space-3) var(--space-4); - border-bottom: 1px solid var(--border-color); - cursor: pointer; - transition: background var(--transition-fast); -} - -.db-recent-item:last-child { - border-bottom: none; -} - -.db-recent-item:hover { - background: var(--gray-50); -} - -.db-recent-dot { - width: 30px; - height: 30px; - border-radius: var(--radius-md); - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; -} - -.db-recent-arrow { - color: var(--gray-300); - flex-shrink: 0; - display: flex; - align-items: center; - transition: color var(--transition-fast); -} - -.db-recent-item:hover .db-recent-arrow { - color: var(--gray-500); -} - -.db-recent-info { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - gap: 2px; -} - -.db-recent-num { - font-size: 13px; - font-weight: 600; - color: var(--text-primary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.db-recent-client { - font-size: 12px; - color: var(--text-secondary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.db-recent-right { - display: flex; - flex-direction: column; - align-items: flex-end; - gap: 2px; - flex-shrink: 0; -} - -.db-recent-amount { - font-size: 13px; - font-weight: 600; - color: var(--text-primary); -} - -.db-recent-date { - font-size: 11px; - color: var(--text-secondary); -} - -/* Monitoring table */ -.db-table-card { - margin-bottom: var(--space-4); -} - -.db-table-wrap { - overflow-x: auto; -} - -.db-monitoring-table { - width: 100%; - border-collapse: collapse; - font-size: 13px; -} - -.db-monitoring-table thead th { - padding: var(--space-3) var(--space-4); - text-align: left; - font-size: 11px; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.05em; - background: var(--gray-50); - border-bottom: 1px solid var(--border-color); - white-space: nowrap; -} - -.db-th-right { - text-align: right !important; -} - -.db-monitoring-table thead th:first-child { - padding-left: var(--space-5); -} - -.db-monitoring-table thead th:last-child { - padding-right: var(--space-5); -} - -.db-table-row { - cursor: pointer; -} - -.db-table-row td { - padding: var(--space-3) var(--space-4); - border-bottom: 1px solid var(--border-color); - color: var(--text-primary); - vertical-align: middle; - transition: background var(--transition-fast); -} - -.db-table-row:last-child td { - border-bottom: none; -} - -.db-table-row:hover td { - background: var(--gray-50); -} - -.db-table-row td:first-child { - padding-left: var(--space-5); -} - -.db-table-row td:last-child { - padding-right: var(--space-5); -} - -.db-cell-num { - font-variant-numeric: tabular-nums; - font-weight: 500; - white-space: nowrap; -} - -.db-cell-client { - max-width: 180px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.db-cell-right { - text-align: right; -} - -.db-remain-due { - color: var(--red-600); - font-weight: 600; -} - -.db-remain-ok { - color: var(--green-600); -} - -.db-table-loading { - text-align: center; - padding: var(--space-8) !important; - color: var(--text-secondary); - font-size: 13px; -} - -/* Misc states */ -.db-loading-inner, -.db-no-data, -.db-error { - text-align: center; - padding: var(--space-6); - color: var(--text-secondary); - font-size: 13px; - margin: 0; -} - -.db-error { - color: var(--red-600); -} - -.db-td-center { - text-align: center; -} - -/* Recent skeleton */ -.db-recent-skeleton { - pointer-events: none; -} - -.db-skel-icon { - width: 30px; - height: 30px; - border-radius: var(--radius-md); - background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); - background-size: 200% 100%; - animation: db-shimmer 1.4s infinite; - flex-shrink: 0; -} - -.db-skel-lines { - flex: 1; - display: flex; - flex-direction: column; - gap: 5px; -} - -.db-skel-lines span { - display: block; - height: 10px; - border-radius: var(--radius-sm); - background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); - background-size: 200% 100%; - animation: db-shimmer 1.4s infinite; -} - -.db-skel-lines span:first-child { - width: 70%; -} - -.db-skel-lines span:last-child { - width: 50%; -} - -.db-skel-right { - display: flex; - flex-direction: column; - align-items: flex-end; - gap: 5px; -} - -.db-skel-right span { - display: block; - height: 10px; - border-radius: var(--radius-sm); - background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); - background-size: 200% 100%; - animation: db-shimmer 1.4s infinite; -} - -.db-skel-right span:first-child { - width: 60px; -} - -.db-skel-right span:last-child { - width: 44px; -} - -/* Responsive */ -@media (max-width: 1100px) { - .db-kpi-row { - grid-template-columns: repeat(2, 1fr); - } -} - -@media (max-width: 900px) { - .db-mid-row { - grid-template-columns: 1fr; - } -} - -@media (max-width: 580px) { - .db-kpi-row { - grid-template-columns: 1fr; - } - - .db-greeting { - font-size: 1.1rem; - } -} - -/* Keep legacy dashboard-subtitle for possible other uses */ -.dashboard-subtitle { - color: var(--text-secondary); - font-size: 13px; - margin: var(--space-1) 0 0 0; -} \ No newline at end of file diff --git a/src/styles/clients.css b/src/styles/clients.css index e69de29..5b2b8d6 100644 --- a/src/styles/clients.css +++ b/src/styles/clients.css @@ -0,0 +1,509 @@ +/* ============================================ + Clientes Page + ============================================ */ + +.clientes-page { + padding: var(--space-6); + max-width: 1400px; + margin: 0 auto; +} + +.clientes-header { + margin-bottom: var(--space-5); +} + +.clientes-header h1 { + font-size: 1.25rem; + font-weight: 600; +} + +.clientes-filters { + display: flex; + gap: var(--space-3); + margin-bottom: var(--space-4); + align-items: center; +} + +.clientes-filters .search-input { + flex: 1; + max-width: 400px; +} + +.client-avatar-col { + width: 48px; +} + +.client-avatar-cell { + width: 48px; +} + +.client-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 500; + font-size: 12px; +} + +.client-name-wrapper { + display: flex; + flex-direction: column; + gap: 1px; +} + +.client-company-name { + font-weight: 500; + color: var(--text-primary); +} + +.client-code { + font-size: 11px; + color: var(--text-secondary); + font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace; +} + +.contact-info { + display: flex; + flex-direction: column; + gap: 1px; +} + +.contact-name { + color: var(--text-primary); +} + +.contacts-count { + font-size: 11px; + color: var(--primary); + background: var(--blue-50); + padding: 1px var(--space-2); + border-radius: var(--radius-sm); + display: inline-block; + width: fit-content; + font-weight: 500; +} + +.client-email .email-text { + color: var(--text-secondary); + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: inline-block; + font-size: 13px; +} + +.client-phone { + color: var(--text-primary); + font-variant-numeric: tabular-nums; + font-size: 13px; +} + +.client-actions { + text-align: center; +} + +.clients-table .client-actions-col { + width: 60px; + text-align: center; +} + +.clients-table td.client-actions { + text-align: center; + vertical-align: middle; +} + +.clients-table td.client-actions .btn-view { + margin: 0 auto; +} + +.status-badge-client { + display: inline-flex; + align-items: center; + padding: 2px var(--space-2); + border-radius: var(--radius-sm); + font-size: 12px; + font-weight: 500; + white-space: nowrap; +} + +.status-badge-client.status-active { + background: var(--green-50); + color: var(--green-600); +} + +.status-badge-client.status-inactive { + background: var(--red-50); + color: var(--red-600); +} + +.status-badge-client.status-unknown { + background: var(--gray-100); + color: var(--gray-500); +} + +.btn-contacts { + position: relative; + background: var(--blue-50); + border: 1px solid rgba(59, 130, 246, 0.15); + color: var(--primary); + border-radius: var(--radius-sm); + padding: 2px var(--space-2); + cursor: pointer; + transition: background-color var(--transition-fast); + display: flex; + align-items: center; + gap: 2px; + font-size: 12px; +} + +.btn-contacts:hover { + background: var(--blue-100); +} + +.btn-contacts.active { + background: var(--primary); + color: white; + border-color: var(--primary); +} + +.contacts-badge { + font-size: 11px; + font-weight: 600; + min-width: 14px; + text-align: center; +} + +.contacts-expand-row td { + padding: 0 !important; + background: var(--gray-50); +} + +.contacts-expand-content { + padding: var(--space-3) var(--space-4); + border-top: 1px solid var(--border-color); + border-bottom: 2px solid var(--primary); +} + +.contacts-expand-header h4 { + margin: 0 0 var(--space-3) 0; + font-size: 12px; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.04em; + font-weight: 500; +} + +.contacts-expand-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: var(--space-2); +} + +.contact-expand-card { + background: white; + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + padding: var(--space-3); +} + +.contact-expand-name { + display: flex; + align-items: center; + gap: var(--space-2); + font-weight: 500; + color: var(--text-primary); + margin-bottom: var(--space-2); + font-size: 14px; +} + +.contact-expand-name svg { + color: var(--primary); + flex-shrink: 0; +} + +.contact-expand-details { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2px var(--space-3); + font-size: 12px; + color: var(--text-secondary); +} + +.contact-expand-details span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Client Modal */ +.client-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.4); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + padding: var(--space-4); +} + +.client-modal { + background: var(--card-bg); + border-radius: var(--radius-lg); + width: 100%; + max-width: 560px; + max-height: 80vh; + overflow: hidden; + display: flex; + flex-direction: column; + box-shadow: var(--shadow-lg); +} + +.client-modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--space-4) var(--space-5); + border-bottom: 1px solid var(--border-color); +} + +.client-modal-header h2 { + margin: 0; + font-size: 1.125rem; + font-weight: 600; +} + +.btn-close-modal { + background: transparent; + border: none; + font-size: 18px; + cursor: pointer; + color: var(--text-secondary); + padding: var(--space-1); + border-radius: var(--radius-sm); + transition: color var(--transition-fast), background-color var(--transition-fast); + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +.btn-close-modal:hover { + background: var(--gray-100); + color: var(--text-primary); +} + +.client-modal-body { + padding: var(--space-5); + overflow-y: auto; +} + +.client-info-section, +.contacts-section { + margin-bottom: var(--space-5); +} + +.client-info-section:last-child, +.contacts-section:last-child { + margin-bottom: 0; +} + +.client-info-section h3, +.contacts-section h3 { + margin: 0 0 var(--space-3) 0; + font-size: 12px; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.04em; + font-weight: 500; +} + +.info-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: var(--space-3); +} + +.info-item { + display: flex; + flex-direction: column; + gap: 1px; +} + +.info-label { + font-size: 11px; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.04em; + font-weight: 500; +} + +.info-value { + font-weight: 500; + color: var(--text-primary); + font-size: 14px; +} + +.contacts-list { + display: flex; + flex-direction: column; + gap: var(--space-3); +} + +.contact-card { + background: var(--card-bg); + border-radius: var(--radius-md); + padding: var(--space-4); + border: 1px solid var(--border-color); +} + +.contact-header { + display: flex; + align-items: center; + gap: var(--space-2); + margin-bottom: var(--space-3); + padding-bottom: var(--space-3); + border-bottom: 1px solid var(--border-color); +} + +.contact-avatar { + width: 28px; + height: 28px; + border-radius: 50%; + background: var(--gray-100); + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + flex-shrink: 0; +} + +.contact-full-name { + font-weight: 600; + color: var(--text-primary); + font-size: 13px; +} + +.contact-details { + display: flex; + flex-direction: column; + gap: var(--space-2); +} + +.contact-row { + display: flex; + align-items: center; + gap: var(--space-2); + font-size: 13px; + color: var(--text-secondary); +} + +.contact-icon { + display: flex; + align-items: center; + justify-content: center; + color: var(--gray-400); + flex-shrink: 0; + width: 16px; +} + +.no-contacts { + color: var(--text-secondary); + text-align: center; + padding: var(--space-5); + background: var(--gray-50); + border-radius: var(--radius-md); + font-size: 13px; +} + +@media (max-width: 768px) { + .clientes-filters { + flex-direction: column; + } + + .clients-table thead { + display: none; + } + + .clients-table tbody tr.client-item { + display: flex; + flex-wrap: wrap; + padding: var(--space-3); + gap: var(--space-2); + position: relative; + } + + .clients-table tbody tr.contacts-expand-row { + display: block; + } + + .clients-table td { + padding: 0; + } + + .client-avatar-cell { + width: auto; + margin-right: var(--space-3); + } + + .client-name { + flex: 1; + } + + .client-type-col, + .client-type { + display: none; + } + + .client-actions { + position: absolute; + right: var(--space-3); + top: 50%; + transform: translateY(-50%); + } + + .contacts-expand-grid { + grid-template-columns: 1fr; + } + + .info-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 1024px) { + .clientes-page { + padding: var(--space-4); + } + + .clients-table th, + .clients-table td { + padding: var(--space-2) var(--space-3); + } + + .client-email-col, + .client-email, + .client-type-col, + .client-type { + display: none; + } +} + +:root[data-theme='dark'] .contact-expand-card { + background: #0f172a; + border-color: #1e2f4d; +} + +:root[data-theme='dark'] .contacts-expand-row td, +:root[data-theme='dark'] .no-contacts { + background: rgba(15, 23, 42, 0.9); +} diff --git a/src/styles/create-invoice.css b/src/styles/create-invoice.css index d9bb289..6373a63 100644 --- a/src/styles/create-invoice.css +++ b/src/styles/create-invoice.css @@ -1,6 +1,9 @@ -/* ===================== CREATE INVOICE PAGE ===================== */ +/* ============================================ + Create Invoice Page + ============================================ */ + .create-invoice-page { - padding: 2rem; + padding: var(--space-6); max-width: 960px; margin: 0 auto; min-height: 100vh; @@ -10,57 +13,53 @@ display: flex; justify-content: space-between; align-items: center; - margin-bottom: 1.5rem; - flex-shrink: 0; + margin-bottom: var(--space-5); } .invoice-header-compact h1 { - margin: 0; - font-size: 1.375rem; - color: var(--text-primary); + font-size: 1.25rem; font-weight: 600; - letter-spacing: -0.02em; } .btn-back { background: transparent; color: var(--text-secondary); border: 1px solid var(--border-color); - padding: 0.45rem 0.875rem; - border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-3); + border-radius: var(--radius-md); cursor: pointer; font-weight: 500; - font-size: 0.8125rem; - transition: all 0.15s ease; + font-size: 13px; + transition: border-color var(--transition-fast), color var(--transition-fast); + height: 32px; } .btn-back:hover { - background: #f8fafc; color: var(--text-primary); - border-color: #cbd5e1; + border-color: var(--gray-300); + background: transparent; } .invoice-form-compact { background: var(--card-bg); - border-radius: var(--radius-md); + border-radius: var(--radius-lg); border: 1px solid var(--border-color); - padding: 1.75rem; + padding: var(--space-5); box-shadow: var(--shadow-xs); } .form-grid-compact { display: grid; grid-template-columns: 2fr 1fr 1fr; - gap: 1rem; - margin-bottom: 1.5rem; - flex-shrink: 0; + gap: var(--space-3); + margin-bottom: var(--space-5); } .notes-grid-compact { display: grid; grid-template-columns: 1fr 1fr; - gap: 1rem; - margin-bottom: 1.5rem; + gap: var(--space-3); + margin-bottom: var(--space-5); } .form-field-compact { @@ -74,24 +73,29 @@ .form-field-compact label { font-weight: 500; - margin-bottom: 0.375rem; + margin-bottom: var(--space-1); color: var(--text-secondary); - font-size: 0.8125rem; + font-size: 13px; } .form-field-compact input, .form-field-compact select, .form-field-compact textarea { - padding: 0.5rem 0.75rem; + padding: var(--space-2) var(--space-3); border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - font-size: 0.875rem; + border-radius: var(--radius-md); + font-size: 14px; color: var(--text-primary); - background: #ffffff; + background: var(--card-bg); resize: vertical; - min-height: 36px; font-family: inherit; - transition: border-color 0.15s ease, box-shadow 0.15s ease; + transition: border-color var(--transition-fast); + height: 36px; +} + +.form-field-compact textarea { + height: auto; + min-height: 64px; } .form-field-compact input:focus, @@ -99,10 +103,9 @@ .form-field-compact textarea:focus { outline: none; border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); } -/* Date input wrapper */ .date-input-wrapper { position: relative; display: flex; @@ -124,61 +127,60 @@ display: flex; align-items: center; justify-content: center; - padding: 0 0.625rem; + padding: 0 0.75rem; background: var(--primary); color: white; border: 1px solid var(--primary); - border-top-right-radius: var(--radius-sm); - border-bottom-right-radius: var(--radius-sm); + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; cursor: pointer; - transition: background 0.15s; + transition: background 0.2s; } .date-picker-btn:hover { - background: var(--primary-hover); + background: var(--primary-hover, #1d4ed8); +} + +.date-picker-btn:active { + transform: scale(0.96); } -/* Lines section */ .lines-section-compact { flex: 1; display: flex; flex-direction: column; overflow: hidden; - margin-bottom: 1.5rem; + margin-bottom: var(--space-5); } .lines-header-compact { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 0.75rem; - flex-shrink: 0; + margin-bottom: var(--space-3); } .lines-header-compact h3 { margin: 0; - font-size: 0.875rem; - color: var(--text-primary); + font-size: 14px; font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.03em; } .btn-add-compact { - background: #f8fafc; + background: var(--card-bg); color: var(--text-primary); border: 1px solid var(--border-color); - padding: 0.4rem 0.875rem; - border-radius: var(--radius-sm); + padding: var(--space-1) var(--space-3); + border-radius: var(--radius-md); cursor: pointer; font-weight: 500; - font-size: 0.8125rem; - transition: all 0.15s; + font-size: 13px; + transition: border-color var(--transition-fast); + height: 32px; } .btn-add-compact:hover { - background: #f1f5f9; - border-color: #cbd5e1; + border-color: var(--gray-300); } .lines-table-compact { @@ -186,57 +188,38 @@ overflow-y: auto; display: flex; flex-direction: column; - gap: 0.375rem; -} - -/* Column headers */ -.lines-columns-header { - display: grid; - grid-template-columns: 4fr 0.8fr 1.2fr 0.8fr 1.2fr 40px; - gap: 0.75rem; - padding: 0.5rem 0.75rem; - font-size: 0.7rem; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.04em; - border-bottom: 1px solid var(--border-color); - margin-bottom: 0.25rem; + gap: var(--space-2); } .line-row-compact { display: grid; - grid-template-columns: 4fr 0.8fr 1.2fr 0.8fr 1.2fr 40px; - gap: 0.75rem; + grid-template-columns: 4fr 0.8fr 1.2fr 0.8fr 1.2fr auto; + gap: var(--space-2); align-items: center; - background: #f8fafc; + background: var(--gray-50); border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - padding: 0.625rem 0.75rem; - transition: border-color 0.15s ease; + border-radius: var(--radius-md); + padding: var(--space-2) var(--space-3); } -.line-row-compact:hover { - border-color: #cbd5e1; -} - -.line-label-mobile { display: none; } -.line-field { display: flex; flex-direction: column; } - .line-desc-compact, .line-qty-compact, .line-price-compact, .line-tax-compact { - padding: 0.4rem 0.5rem; + padding: var(--space-1) var(--space-2); border: 1px solid var(--border-color); - border-radius: 4px; - font-size: 0.8125rem; + border-radius: var(--radius-sm); + font-size: 13px; background: white; color: var(--text-primary); - transition: border-color 0.15s ease; + font-family: inherit; + transition: border-color var(--transition-fast); + height: 32px; } -.line-desc-compact { width: 100%; } +.line-desc-compact { + width: 100%; +} .line-desc-compact:focus, .line-qty-compact:focus, @@ -244,114 +227,81 @@ .line-tax-compact:focus { outline: none; border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); } .line-total-compact { - font-weight: 600; - color: var(--primary); - font-size: 0.875rem; + font-weight: 500; + color: var(--text-primary); + font-size: 13px; text-align: right; - padding: 0.4rem 0.25rem; + padding-right: var(--space-2); + font-variant-numeric: tabular-nums; } .btn-delete-compact { background: transparent; - color: var(--text-tertiary); - border: 1px solid transparent; - width: 32px; - height: 32px; + color: var(--gray-400); + border: none; + width: 28px; + height: 28px; border-radius: var(--radius-sm); cursor: pointer; + font-size: 16px; + font-weight: 400; + line-height: 1; display: flex; align-items: center; justify-content: center; - transition: all 0.15s; + transition: color var(--transition-fast), background-color var(--transition-fast); flex-shrink: 0; + padding: 0; } .btn-delete-compact:hover { - color: #ef4444; - background: #fee2e2; + color: var(--danger); + background: var(--red-50); + border-color: transparent; } -/* Grand total */ -.invoice-grand-total { - display: flex; - flex-direction: column; - gap: 0.4rem; - margin-top: 0.75rem; - padding: 0.875rem 1rem; - background: #f8fafc; - border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - max-width: 280px; - margin-left: auto; -} - -.grand-total-row { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.8125rem; - color: var(--text-secondary); -} - -.grand-total-row strong { - color: var(--text-primary); - font-weight: 600; -} - -.grand-total-final { - padding-top: 0.4rem; - border-top: 1px solid var(--border-color); - font-size: 0.9375rem; -} - -.grand-total-final strong { - color: var(--primary); - font-size: 1rem; - font-weight: 700; -} - -/* Form actions */ .form-actions-compact { display: flex; justify-content: flex-end; - gap: 0.625rem; - margin-top: 0; - padding-top: 1.25rem; + gap: var(--space-2); + padding-top: var(--space-4); border-top: 1px solid var(--border-color); - flex-shrink: 0; } .btn-cancel-compact { background: transparent; color: var(--text-secondary); border: 1px solid var(--border-color); - padding: 0.5rem 1rem; - border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-4); + border-radius: var(--radius-md); cursor: pointer; font-weight: 500; - font-size: 0.8125rem; - transition: all 0.15s; + font-size: 14px; + transition: border-color var(--transition-fast), color var(--transition-fast); + height: 36px; } .btn-cancel-compact:hover { - background: #f8fafc; color: var(--text-primary); + border-color: var(--gray-300); + background: transparent; } .btn-submit-compact { background: var(--primary); color: white; border: none; - padding: 0.5rem 1.25rem; - border-radius: var(--radius-sm); + padding: var(--space-2) var(--space-5); + border-radius: var(--radius-md); cursor: pointer; font-weight: 500; - font-size: 0.8125rem; - transition: background 0.15s; + font-size: 14px; + transition: background-color var(--transition-fast); + height: 36px; } .btn-submit-compact:hover { @@ -359,43 +309,31 @@ } .btn-submit-compact:disabled { - background: #e2e8f0; - color: #94a3b8; + background: var(--gray-200); + color: var(--gray-400); cursor: not-allowed; } -/* Responsive */ @media (max-width: 768px) { .create-invoice-page { - padding: 0.5rem; - height: calc(100vh - 1rem); + padding: var(--space-3); } .form-grid-compact { grid-template-columns: 1fr; - gap: 0.5rem; } - .form-field-compact.full-width { grid-column: 1; } - .lines-columns-header { display: none; } + .form-field-compact.full-width { + grid-column: 1; + } + + .notes-grid-compact { + grid-template-columns: 1fr; + } .line-row-compact { - grid-template-columns: 1fr 1fr; - gap: 0.5rem; - padding: 0.625rem; + grid-template-columns: 1fr auto; + gap: var(--space-2); + padding: var(--space-3); } - - .line-label-mobile { - display: block; - font-size: 0.65rem; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.04em; - margin-bottom: 0.15rem; - } - - .line-field-desc { grid-column: 1 / -1; } - .line-field-actions { grid-column: 2; justify-self: end; } - .invoice-grand-total { max-width: 100%; } } diff --git a/src/styles/dashboard.css b/src/styles/dashboard.css index 8a89196..ac341e6 100644 --- a/src/styles/dashboard.css +++ b/src/styles/dashboard.css @@ -1,58 +1,201 @@ -/* ===================== DASHBOARD STYLES ===================== */ -.dashboard { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; -} +/* ============================================ + Dashboard — Analytics Layout + ============================================ */ -.dashboard-header { +.db-header { display: flex; justify-content: space-between; align-items: flex-start; - margin-bottom: 1.75rem; + margin-bottom: var(--space-6); + gap: var(--space-4); } -.dashboard-header h1 { +.db-greeting { font-size: 1.5rem; - margin: 0; + font-weight: 700; color: var(--text-primary); - font-weight: 600; + margin: 0 0 var(--space-1) 0; letter-spacing: -0.02em; } -.dashboard-subtitle { - margin: 0.2rem 0 0; +.db-subtitle { + font-size: 13px; color: var(--text-secondary); - font-size: 0.875rem; + margin: 0; } -/* Stats */ -.dashboard-stats { +.db-kpi-row { display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; - margin-bottom: 1.75rem; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-4); + margin-bottom: var(--space-5); } -.stat-card { +.db-kpi-card { background: var(--card-bg); - border-radius: var(--radius-md); - padding: 1.25rem; - display: flex; - align-items: center; - gap: 0.875rem; border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + padding: var(--space-5); box-shadow: var(--shadow-xs); - transition: box-shadow 0.15s ease; + display: flex; + flex-direction: column; + gap: var(--space-2); + transition: box-shadow var(--transition-fast); } -.stat-card:hover { +.db-kpi-card:hover { box-shadow: var(--shadow-sm); } -.stat-icon { - width: 42px; - height: 42px; +.db-kpi-top { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: var(--space-2); +} + +.db-kpi-icon { + width: 28px; + height: 28px; + border-radius: var(--radius-md); + background: var(--gray-100); + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + flex-shrink: 0; +} + +.db-kpi-label { + font-size: 11px; + font-weight: 500; + color: var(--text-secondary); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.db-kpi-value { + font-size: 1.65rem; + font-weight: 700; + color: var(--text-primary); + letter-spacing: -0.03em; + line-height: 1.1; + min-height: 2rem; +} + +.db-kpi-sub { + font-size: 12px; + color: var(--text-secondary); + min-height: 1rem; +} + +.db-sub-green { color: var(--green-600); font-weight: 500; } +.db-sub-amber { color: var(--amber-600); font-weight: 500; } +.db-sub-red { color: var(--red-600); font-weight: 500; } +.db-sub-muted { color: var(--text-secondary); } + +.db-kpi-skeleton { + display: inline-block; + background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); + background-size: 200% 100%; + animation: db-shimmer 1.4s infinite; + border-radius: var(--radius-sm); + width: 80px; + height: 1.6rem; +} + +.db-kpi-skeleton-sm { + width: 120px; + height: 0.8rem; +} + +@keyframes db-shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +.db-mid-row { + display: grid; + grid-template-columns: 1fr 340px; + gap: var(--space-4); + margin-bottom: var(--space-5); +} + +.db-chart-card, +.db-recent-card, +.db-table-card { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-xs); + overflow: hidden; +} + +.db-card-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4) var(--space-5); + border-bottom: 1px solid var(--border-color); +} + +.db-card-title { + font-size: 13px; + font-weight: 600; + color: var(--text-primary); +} + +.db-card-badge, +.db-card-year { + font-size: 12px; + font-weight: 500; + color: var(--text-secondary); + background: var(--gray-100); + padding: 2px 8px; + border-radius: 99px; +} + +.db-see-all { + font-size: 12px; + color: var(--blue-600); + text-decoration: none; + font-weight: 500; +} + +.db-see-all:hover { text-decoration: underline; } + +.db-chart-body { + padding: var(--space-5); + height: 260px; + position: relative; +} + +.db-chart-body canvas { + width: 100% !important; + height: 100% !important; +} + +.db-recent-list { + overflow-y: auto; + max-height: 320px; +} + +.db-recent-item { + display: flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-3) var(--space-4); + border-bottom: 1px solid var(--border-color); + cursor: pointer; + transition: background var(--transition-fast); +} + +.db-recent-item:last-child { border-bottom: none; } +.db-recent-item:hover { background: var(--gray-50); } + +.db-recent-dot { + width: 30px; + height: 30px; border-radius: var(--radius-md); display: flex; align-items: center; @@ -60,136 +203,258 @@ flex-shrink: 0; } -.stat-icon-invoices { - background: rgba(37, 99, 235, 0.08); - color: #2563eb; -} - -.stat-icon-paid { - background: rgba(22, 163, 74, 0.08); +.db-recent-dot.status-paid { + background: #f0fdf4; color: #16a34a; } -.stat-icon-unpaid { - background: rgba(202, 138, 4, 0.08); - color: #ca8a04; +.db-recent-dot.status-unpaid { + background: #fffbeb; + color: #b45309; } -.stat-icon-clients { - background: rgba(99, 102, 241, 0.08); - color: #6366f1; +.db-recent-dot.status-draft { + background: #f3f4f6; + color: #6b7280; } -.stat-info { +.db-recent-arrow { + color: var(--gray-300); + flex-shrink: 0; + display: flex; + align-items: center; + transition: color var(--transition-fast); +} + +.db-recent-item:hover .db-recent-arrow { color: var(--gray-500); } + +.db-recent-info { + flex: 1; + min-width: 0; display: flex; flex-direction: column; + gap: 2px; } -.stat-value { - font-size: 1.375rem; - font-weight: 700; - color: var(--text-primary); - line-height: 1.2; - letter-spacing: -0.02em; -} - -.stat-label { - font-size: 0.78rem; - color: var(--text-secondary); - margin-top: 0.1rem; -} - -/* Dashboard grid */ -.dashboard-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); - gap: 1rem; -} - -.dashboard-card { - background: var(--card-bg); - border-radius: var(--radius-md); - padding: 1.25rem; - border: 1px solid var(--border-color); - box-shadow: var(--shadow-xs); -} - -.dashboard-card h3 { - margin: 0 0 1rem; - font-size: 0.875rem; +.db-recent-num { + font-size: 13px; font-weight: 600; color: var(--text-primary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.db-recent-client { + font-size: 12px; + color: var(--text-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.db-recent-right { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 2px; + flex-shrink: 0; +} + +.db-recent-amount { + font-size: 13px; + font-weight: 600; + color: var(--text-primary); +} + +.db-recent-date { + font-size: 11px; + color: var(--text-secondary); +} + +.db-table-card { margin-bottom: var(--space-4); } +.db-table-wrap { overflow-x: auto; } + +.db-monitoring-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.db-monitoring-table thead th { + padding: var(--space-3) var(--space-4); + text-align: left; + font-size: 11px; + font-weight: 600; + color: var(--text-secondary); text-transform: uppercase; - letter-spacing: 0.03em; + letter-spacing: 0.05em; + background: var(--gray-50); + border-bottom: 1px solid var(--border-color); + white-space: nowrap; } -/* Quick actions */ -.quick-actions { - display: flex; - flex-direction: column; - gap: 0.5rem; -} +.db-th-right { text-align: right !important; } +.db-monitoring-table thead th:first-child { padding-left: var(--space-5); } +.db-monitoring-table thead th:last-child { padding-right: var(--space-5); } -.quick-action-btn { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.625rem 1rem; - border-radius: var(--radius-sm); - font-size: 0.8125rem; - font-weight: 500; - text-decoration: none; - transition: background-color 0.15s ease; - cursor: pointer; - background: var(--primary); - color: #fff; -} +.db-table-row { cursor: pointer; } -.quick-action-btn:hover { - background: var(--primary-hover); - color: #fff; -} - -.quick-action-btn.secondary { - background: var(--primary-subtle); - color: var(--primary); -} - -.quick-action-btn.secondary:hover { - background: rgba(37, 99, 235, 0.12); - color: var(--primary); -} - -/* Dashboard info */ -.dashboard-info-list { - display: flex; - flex-direction: column; -} - -.dashboard-info-row { - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.55rem 0; - border-bottom: 1px solid var(--border-subtle); - font-size: 0.8125rem; -} - -.dashboard-info-row:last-child { - border-bottom: none; -} - -.dashboard-info-row span:first-child { - color: var(--text-secondary); -} - -.dashboard-info-value { +.db-table-row td { + padding: var(--space-3) var(--space-4); + border-bottom: 1px solid var(--border-color); color: var(--text-primary); - font-weight: 600; + vertical-align: middle; + transition: background var(--transition-fast); } -/* Stat skeleton */ -.stat-card .skeleton-value { - width: 50px; - height: 24px; +.db-table-row:last-child td { border-bottom: none; } +.db-table-row:hover td { background: var(--gray-50); } + +.db-table-row td:first-child { padding-left: var(--space-5); } +.db-table-row td:last-child { padding-right: var(--space-5); } + +.db-cell-num { + font-variant-numeric: tabular-nums; + font-weight: 500; + white-space: nowrap; +} + +.db-cell-client { + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.db-cell-right { text-align: right; } +.db-remain-due { color: var(--red-600); font-weight: 600; } +.db-remain-ok { color: var(--green-600); } + +.db-table-loading { + text-align: center; + padding: var(--space-8) !important; + color: var(--text-secondary); + font-size: 13px; +} + +.db-loading-inner, +.db-no-data, +.db-error { + text-align: center; + padding: var(--space-6); + color: var(--text-secondary); + font-size: 13px; + margin: 0; +} + +.db-error { color: var(--red-600); } +.db-td-center { text-align: center; } + +.db-recent-skeleton { pointer-events: none; } + +.db-skel-icon, +.db-skel-lines span, +.db-skel-right span { + background: linear-gradient(90deg, var(--gray-100) 25%, var(--gray-200) 50%, var(--gray-100) 75%); + background-size: 200% 100%; + animation: db-shimmer 1.4s infinite; +} + +.db-skel-icon { + width: 30px; + height: 30px; + border-radius: var(--radius-md); + flex-shrink: 0; +} + +.db-skel-lines { + flex: 1; + display: flex; + flex-direction: column; + gap: 5px; +} + +.db-skel-lines span { + display: block; + height: 10px; + border-radius: var(--radius-sm); +} + +.db-skel-lines span:first-child { width: 70%; } +.db-skel-lines span:last-child { width: 50%; } + +.db-skel-right { + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 5px; +} + +.db-skel-right span { + display: block; + height: 10px; + border-radius: var(--radius-sm); +} + +.db-skel-right span:first-child { width: 60px; } +.db-skel-right span:last-child { width: 44px; } + +@media (max-width: 1100px) { + .db-kpi-row { grid-template-columns: repeat(2, 1fr); } +} + +@media (max-width: 900px) { + .db-mid-row { grid-template-columns: 1fr; } +} + +@media (max-width: 580px) { + .db-kpi-row { grid-template-columns: 1fr; } + .db-greeting { font-size: 1.1rem; } +} + +.dashboard-subtitle { + color: var(--text-secondary); + font-size: 13px; + margin: var(--space-1) 0 0 0; +} + +/* Dark mode UX tune */ +:root[data-theme='dark'] .db-kpi-card, +:root[data-theme='dark'] .db-chart-card, +:root[data-theme='dark'] .db-recent-card, +:root[data-theme='dark'] .db-table-card { + background: #081226; + border-color: #1e2f4d; +} + +:root[data-theme='dark'] .db-card-year, +:root[data-theme='dark'] .db-card-badge, +:root[data-theme='dark'] .db-kpi-icon { + background: rgba(30, 41, 59, 0.8); +} + +:root[data-theme='dark'] .db-recent-item, +:root[data-theme='dark'] .db-table-row td { + background: transparent; +} + +:root[data-theme='dark'] .db-recent-item:hover, +:root[data-theme='dark'] .db-table-row:hover td { + background: rgba(30, 58, 110, 0.24); +} + +:root[data-theme='dark'] .db-recent-dot.status-paid { + background: rgba(34, 197, 94, 0.18); + color: #86efac; +} + +:root[data-theme='dark'] .db-recent-dot.status-unpaid { + background: rgba(245, 158, 11, 0.2); + color: #fcd34d; +} + +:root[data-theme='dark'] .db-recent-dot.status-draft { + background: rgba(148, 163, 184, 0.18); + color: #cbd5e1; } diff --git a/src/styles/facturas.css b/src/styles/facturas.css index e69de29..637b210 100644 --- a/src/styles/facturas.css +++ b/src/styles/facturas.css @@ -0,0 +1,270 @@ +/* ============================================ + Facturas + Tablas + Paginacion + ============================================ */ + +.facturas-page { + padding: var(--space-6); + max-width: 1400px; + margin: 0 auto; +} + +.facturas-header { margin-bottom: var(--space-5); } +.facturas-header h1 { font-size: 1.25rem; font-weight: 600; } + +.btn-new-invoice { + background-color: var(--primary); + color: white; + padding: var(--space-2) var(--space-4); + border: none; + border-radius: var(--radius-md); + cursor: pointer; + font-weight: 500; + font-size: 14px; + transition: background-color var(--transition-fast); + height: 36px; +} + +.btn-new-invoice:hover { background-color: var(--primary-hover); } + +.facturas-filters { + display: flex; + gap: var(--space-3); + margin-bottom: var(--space-4); + align-items: center; +} + +.search-input, +.filter-status { + padding: var(--space-2) var(--space-3); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + font-size: 14px; + font-family: inherit; + background: var(--card-bg); + color: var(--text-primary); + height: 36px; + transition: border-color var(--transition-fast); +} + +.search-input:focus, +.filter-status:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); +} + +.search-input { flex: 1; max-width: 320px; } +.filter-status { min-width: 180px; cursor: pointer; } + +.invoices-table-container, +.clients-table-container { + background: var(--card-bg); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); + overflow: hidden; + box-shadow: var(--shadow-xs); +} + +.invoices-table, +.clients-table { + width: 100%; + border-collapse: collapse; +} + +.invoices-table thead, +.clients-table thead { + background: var(--gray-50); + border-bottom: 1px solid var(--border-color); +} + +.invoices-table th, +.clients-table th { + font-weight: 500; + color: var(--text-secondary); + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.04em; + padding: var(--space-3) var(--space-4); + text-align: left; +} + +.invoices-table tbody tr, +.clients-table tbody tr { + border-bottom: 1px solid var(--border-color); + transition: background-color var(--transition-fast); +} + +.invoices-table tbody tr:hover, +.clients-table tbody tr:hover { background-color: var(--gray-50); } + +.invoices-table tbody tr:last-child, +.clients-table tbody tr:last-child { border-bottom: none; } + +.invoices-table td, +.clients-table td { padding: var(--space-3) var(--space-4); font-size: 14px; } + +.invoice-number { font-weight: 500; color: var(--text-primary); } + +.invoice-client { + display: flex; + align-items: center; + gap: var(--space-2); + color: var(--text-secondary); +} + +.client-icon { display: flex; align-items: center; color: var(--gray-400); } +.invoice-date { color: var(--text-primary); } + +.invoice-total, +.invoice-remain { + font-weight: 500; + font-variant-numeric: tabular-nums; + color: var(--text-primary); +} + +.invoice-actions { + display: flex; + gap: var(--space-1); + justify-content: center; +} + +.btn-view, +.btn-action { + background: transparent; + border: none; + padding: var(--space-1); + border-radius: var(--radius-sm); + cursor: pointer; + color: var(--gray-400); + transition: color var(--transition-fast), background-color var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; +} + +.btn-view:hover { color: var(--primary); background-color: var(--blue-50); } +.btn-action:hover { background-color: var(--gray-100); color: var(--text-primary); } +.btn-delete:hover { background-color: var(--red-50); color: var(--danger); } + +.loading, +.error, +.no-invoices, +.no-clients { + padding: var(--space-10); + text-align: center; + color: var(--text-secondary); + font-size: 14px; +} + +.error { color: var(--danger); } + +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: var(--space-4); + margin-top: var(--space-4); + padding: var(--space-3) var(--space-4); + background: var(--card-bg); + border-radius: var(--radius-lg); + border: 1px solid var(--border-color); +} + +.pagination-info { + font-weight: 500; + color: var(--text-secondary); + font-size: 13px; + display: flex; + gap: var(--space-1); + align-items: center; + font-variant-numeric: tabular-nums; +} + +.pagination-info .current-page, +.pagination-info .total-pages { + font-weight: 600; + color: var(--text-primary); + min-width: 20px; + text-align: center; +} + +.btn-pagination { + padding: var(--space-2) var(--space-3); + background-color: var(--card-bg); + color: var(--text-primary); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + cursor: pointer; + font-weight: 500; + font-size: 13px; + transition: background-color var(--transition-fast), border-color var(--transition-fast); + display: flex; + align-items: center; + gap: var(--space-1); +} + +.btn-pagination:hover:not(:disabled) { + background-color: var(--gray-50); + border-color: var(--gray-300); +} + +.btn-pagination:disabled { + background-color: var(--gray-50); + color: var(--gray-300); + cursor: not-allowed; + border-color: var(--gray-200); +} + +/* Dark tune */ +:root[data-theme='dark'] .invoices-table-container, +:root[data-theme='dark'] .clients-table-container, +:root[data-theme='dark'] .pagination { + background: #081226; + border-color: #1e2f4d; +} + +:root[data-theme='dark'] .invoices-table thead, +:root[data-theme='dark'] .clients-table thead { + background: rgba(15, 23, 42, 0.95); +} + +:root[data-theme='dark'] .invoices-table tbody tr:hover, +:root[data-theme='dark'] .clients-table tbody tr:hover, +:root[data-theme='dark'] .btn-pagination:hover:not(:disabled) { + background-color: rgba(30, 58, 110, 0.24); +} + +@media (max-width: 768px) { + .facturas-filters { + flex-direction: column; + } + + .search-input { + max-width: 100% !important; + } + + .pagination { + flex-wrap: wrap; + gap: var(--space-3); + } + + .btn-pagination { + flex: 1; + min-width: 100px; + justify-content: center; + } + + .pagination-info { + order: 3; + width: 100%; + justify-content: center; + } +} + +@media (max-width: 1024px) { + .facturas-page { + padding: var(--space-4); + } +} diff --git a/src/styles/login.css b/src/styles/login.css index e69de29..d7140d1 100644 --- a/src/styles/login.css +++ b/src/styles/login.css @@ -0,0 +1,179 @@ +/* ============================================ + Login + Session Notices + ============================================ */ + +.login-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + width: 100%; + background: var(--bg-page); +} + +.login-card { + background: var(--card-bg); + padding: var(--space-8); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); + width: 100%; + max-width: 380px; + border: 1px solid var(--border-color); +} + +.login-title { + color: var(--text-primary); + margin: 0 0 var(--space-6) 0; + font-size: 1.25rem; + text-align: center; + font-weight: 600; +} + +.form-group { + margin-bottom: var(--space-4); +} + +.form-group label { + display: block; + color: var(--text-secondary); + margin-bottom: var(--space-1); + font-weight: 500; + font-size: 13px; +} + +.form-group input { + width: 100%; + padding: var(--space-2) var(--space-3); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + background: var(--card-bg); + color: var(--text-primary); + font-size: 14px; + font-family: inherit; + box-sizing: border-box; + transition: border-color var(--transition-fast); + height: 36px; +} + +.form-group input:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12); +} + +.login-button { + width: 100%; + padding: var(--space-2) var(--space-4); + background-color: var(--primary); + color: white; + border: none; + border-radius: var(--radius-md); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: background-color var(--transition-fast); + height: 36px; + margin-top: var(--space-2); +} + +.login-button:hover { + background-color: var(--primary-hover); + border-color: transparent; +} + +.login-error { + color: var(--danger); + text-align: center; + margin-top: var(--space-3); + font-size: 13px; +} + +.session-warning-overlay, +.connection-lost-overlay { + position: fixed; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + padding: var(--space-4); +} + +.session-warning-overlay { + background: rgba(17, 24, 39, 0.45); + z-index: 3000; +} + +.connection-lost-overlay { + background: rgba(17, 24, 39, 0.55); + z-index: 4000; +} + +.session-warning-modal, +.connection-lost-modal { + width: 100%; + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + box-shadow: var(--shadow-lg); + padding: var(--space-6); +} + +.session-warning-modal { max-width: 430px; } +.connection-lost-modal { max-width: 460px; } + +.session-warning-modal h3 { + margin: 0 0 var(--space-3) 0; + font-size: 1.15rem; +} + +.connection-lost-modal h3 { + margin: 0 0 var(--space-2) 0; + color: var(--danger); +} + +.session-warning-modal p, +.connection-lost-modal p { + margin: 0; + color: var(--text-secondary); +} + +.session-warning-actions { + margin-top: var(--space-5); + display: flex; + justify-content: flex-end; + gap: var(--space-2); +} + +.session-warning-logout { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-secondary); +} + +.session-warning-logout:hover { + background: var(--gray-100); +} + +.session-warning-continue { + background: var(--primary); +} + +.connection-lost-sub { + margin-top: var(--space-3) !important; + font-size: 0.92rem; +} + +.connection-lost-login-btn { + margin-top: var(--space-5); + width: 100%; +} + +@media (max-width: 640px) { + .session-warning-actions { + flex-direction: column; + } + + .session-warning-actions button { + width: 100%; + } +} diff --git a/src/styles/modal.css b/src/styles/modal.css index 5086c6c..285d57b 100644 --- a/src/styles/modal.css +++ b/src/styles/modal.css @@ -87,7 +87,7 @@ } .btn-close:hover { - background-color: #f1f5f9; + background-color: var(--bg-subtle); color: var(--text-primary); } @@ -168,7 +168,7 @@ font-size: 0.9375rem; transition: all 0.2s; font-family: inherit; - background-color: #ffffff; + background-color: var(--card-bg); color: var(--text-primary); } @@ -183,19 +183,19 @@ .form-group input:disabled, .form-group textarea:disabled, .form-group select:disabled { - background-color: #f8fafc; + background-color: var(--bg-subtle); color: var(--text-secondary); cursor: not-allowed; } .form-group input[readonly] { - background-color: #f8fafc; + background-color: var(--bg-subtle); color: var(--text-secondary); } /* Add Line Form */ .add-line-form { - background-color: #f8fafc; + background-color: var(--bg-subtle); padding: 1.5rem; border-radius: 8px; margin-bottom: 1rem; @@ -219,7 +219,7 @@ } .lines-table thead { - background-color: #f8fafc; + background-color: var(--bg-subtle); } .lines-table th { @@ -236,7 +236,7 @@ } .lines-table tbody tr:hover { - background-color: #f8fafc; + background-color: var(--bg-subtle); } .no-lines { @@ -281,7 +281,7 @@ .invoice-totals { margin-top: 1.5rem; padding: 1rem; - background-color: #f8fafc; + background-color: var(--bg-subtle); border-radius: 8px; display: flex; flex-direction: column; @@ -493,7 +493,7 @@ } .btn-cancel:hover { - background-color: #f8fafc; + background-color: var(--bg-subtle); color: var(--text-primary); } @@ -519,7 +519,7 @@ } .btn-action:hover { - background-color: #f1f5f9; + background-color: var(--bg-subtle); transform: scale(1.1); } @@ -720,14 +720,14 @@ } .confirm-exit-actions .btn-exit { - background-color: #f1f5f9; + background-color: var(--bg-subtle); color: var(--text-primary, #1e293b); border: 1px solid var(--border-color, #e2e8f0); } .confirm-exit-actions .btn-exit:hover { - background-color: #e2e8f0; - border-color: #cbd5e1; + background-color: rgba(148, 163, 184, 0.18); + border-color: rgba(148, 163, 184, 0.28); } /* Responsive Confirm Modal */ diff --git a/src/styles/settings.css b/src/styles/settings.css new file mode 100644 index 0000000..b52ec45 --- /dev/null +++ b/src/styles/settings.css @@ -0,0 +1,85 @@ +/* ============================================ + Settings Page + ============================================ */ + +.settings-page { + max-width: 980px; + margin: 0 auto; + padding: var(--space-6); +} + +.settings-header { + margin-bottom: var(--space-6); +} + +.settings-header p { + margin-top: var(--space-2); + color: var(--text-secondary); +} + +.settings-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: var(--space-4); +} + +.settings-card { + background: var(--card-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: var(--space-5); + box-shadow: var(--shadow-xs); +} + +.settings-card h2 { + margin-bottom: var(--space-4); + font-size: 1.05rem; +} + +.settings-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-4); +} + +.settings-label { + margin: 0; + font-size: 0.95rem; + font-weight: 600; + color: var(--text-primary); +} + +.settings-help { + margin: var(--space-1) 0 0; + font-size: 0.85rem; + color: var(--text-secondary); +} + +.settings-theme-toggle { + min-width: 116px; +} + +.settings-session-list { + display: flex; + flex-direction: column; + gap: var(--space-4); +} + +.settings-session-item { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--space-3); + padding-bottom: var(--space-3); + border-bottom: 1px dashed var(--border-color); +} + +.settings-session-item:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.settings-token-expired { + color: var(--danger); +} diff --git a/src/styles/sidebar.css b/src/styles/sidebar.css index e69de29..f059221 100644 --- a/src/styles/sidebar.css +++ b/src/styles/sidebar.css @@ -0,0 +1,185 @@ +/* ============================================ + App Layout + Sidebar + ============================================ */ + +.app-layout { + display: flex; + min-height: 100vh; + width: 100%; +} + +.sidebar { + width: 220px; + background-color: var(--card-bg); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; + transition: width var(--transition-base); + position: relative; + z-index: 100; + flex-shrink: 0; +} + +.sidebar-header { + padding: var(--space-4); + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; + height: 52px; +} + +.sidebar-header h2 { + margin: 0; + font-size: 14px; + font-weight: 600; + color: var(--text-primary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + letter-spacing: -0.01em; +} + +.sidebar-toggle { + background: transparent; + border: none; + cursor: pointer; + padding: var(--space-1); + color: var(--text-secondary); + font-size: 14px; + border-radius: var(--radius-sm); + transition: background-color var(--transition-fast); + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; +} + +.sidebar-toggle:hover { + background-color: var(--gray-100); + border-color: transparent; +} + +.sidebar-nav { + flex: 1; + overflow-y: auto; + padding: var(--space-2) 0; +} + +.sidebar-menu { + list-style: none; + margin: 0; + padding: 0; +} + +.sidebar-menu li { + margin: 0; + padding: 0 var(--space-2); +} + +.sidebar-link { + display: flex; + align-items: center; + gap: var(--space-3); + padding: var(--space-2) var(--space-3); + color: var(--text-secondary); + text-decoration: none; + transition: color var(--transition-fast), background-color var(--transition-fast); + cursor: pointer; + border-radius: var(--radius-md); + font-size: 14px; + font-weight: 400; + margin-bottom: 1px; +} + +.sidebar-link:hover { + background-color: var(--gray-100); + color: var(--text-primary); +} + +.sidebar-link.active { + background-color: var(--blue-50); + color: var(--primary); + font-weight: 500; +} + +:root[data-theme='dark'] .sidebar-link:hover { + background-color: rgba(30, 58, 110, 0.18); + color: #dbeafe; +} + +:root[data-theme='dark'] .sidebar-link.active { + background-color: rgba(30, 58, 110, 0.32); + color: #bfdbfe; + box-shadow: inset 0 0 0 1px rgba(96, 165, 250, 0.25); +} + +.sidebar-icon { + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + flex-shrink: 0; +} + +.sidebar-icon svg { + width: 16px; + height: 16px; +} + +.sidebar-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.sidebar.collapsed { width: 56px; } + +.sidebar.collapsed .sidebar-header h2, +.sidebar.collapsed .sidebar-text { + opacity: 0; + width: 0; + overflow: hidden; +} + +.sidebar.collapsed .sidebar-icon { margin-right: 0; } + +.sidebar.collapsed .sidebar-link { + justify-content: center; + padding: var(--space-2); +} + +.main-content { + flex: 1; + overflow-y: auto; + background-color: var(--bg-page); + min-width: 0; +} + +.main-content > div { + max-width: 1280px; + margin: 0 auto; + padding: var(--space-6); +} + +@media (max-width: 768px) { + .sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + z-index: 1000; + transform: translateX(0); + } + + .sidebar.collapsed { + transform: translateX(-100%); + width: 220px; + } + + .main-content { + margin-left: 0; + } +}