diff --git a/static/css/hover-standards.css b/static/css/hover-standards.css new file mode 100644 index 0000000..35fb46c --- /dev/null +++ b/static/css/hover-standards.css @@ -0,0 +1,390 @@ +/* =================================================================== + TIMETRACK HOVER STANDARDS + Consistent hover states based on primary gradient colors + Primary: #667eea to #764ba2 + =================================================================== */ + +:root { + /* Primary gradient colors */ + --primary-gradient-start: #667eea; + --primary-gradient-end: #764ba2; + --primary-color: #667eea; + + /* Hover color variations */ + --hover-primary: #5569d6; /* Darker primary for hover */ + --hover-primary-dark: #4a5bc8; /* Even darker primary */ + --hover-secondary: #6a4195; /* Darker gradient end */ + + /* Background hover colors */ + --hover-bg-light: rgba(102, 126, 234, 0.05); /* 5% primary */ + --hover-bg-medium: rgba(102, 126, 234, 0.1); /* 10% primary */ + --hover-bg-strong: rgba(102, 126, 234, 0.15); /* 15% primary */ + + /* Shadow definitions */ + --hover-shadow-light: 0 2px 4px rgba(102, 126, 234, 0.15); + --hover-shadow-medium: 0 4px 12px rgba(102, 126, 234, 0.2); + --hover-shadow-strong: 0 6px 20px rgba(102, 126, 234, 0.25); + --hover-shadow-heavy: 0 8px 30px rgba(102, 126, 234, 0.3); + + /* Transform values */ + --hover-lift-subtle: translateY(-1px); + --hover-lift-small: translateY(-2px); + --hover-lift-medium: translateY(-3px); + --hover-lift-large: translateY(-5px); + + /* Transition timing */ + --hover-transition-fast: all 0.2s ease; + --hover-transition-normal: all 0.3s ease; + --hover-transition-smooth: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +/* =================================================================== + GLOBAL HOVER STYLES + =================================================================== */ + +/* All links */ +a { + transition: var(--hover-transition-fast); +} + +a:hover { + color: var(--primary-color); + text-decoration: none; +} + +/* =================================================================== + BUTTON HOVER STYLES + =================================================================== */ + +/* Base button hover */ +.btn { + transition: var(--hover-transition-normal); +} + +.btn:hover { + transform: var(--hover-lift-subtle); + box-shadow: var(--hover-shadow-light); +} + +/* Primary button with gradient */ +.btn-primary { + background: linear-gradient(135deg, var(--primary-gradient-start) 0%, var(--primary-gradient-end) 100%); +} + +.btn-primary:hover { + background: linear-gradient(135deg, var(--hover-primary) 0%, var(--hover-secondary) 100%); + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + border-color: var(--hover-primary); +} + +/* Secondary button */ +.btn-secondary:hover { + background-color: var(--hover-bg-medium); + border-color: var(--primary-color); + color: var(--primary-color); + transform: var(--hover-lift-subtle); + box-shadow: var(--hover-shadow-light); +} + +/* Success button - maintain green but with consistent effects */ +.btn-success:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + filter: brightness(0.9); +} + +/* Danger button - maintain red but with consistent effects */ +.btn-danger:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + filter: brightness(0.9); +} + +/* Outline buttons */ +.btn-outline:hover { + background-color: var(--primary-color); + border-color: var(--primary-color); + color: white; + transform: var(--hover-lift-subtle); + box-shadow: var(--hover-shadow-light); +} + +/* Small buttons */ +.btn-sm:hover { + transform: var(--hover-lift-subtle); + box-shadow: var(--hover-shadow-light); +} + +/* =================================================================== + NAVIGATION HOVER STYLES + =================================================================== */ + +/* Sidebar */ +.sidebar { + transition: var(--hover-transition-normal); +} + +.sidebar:hover { + box-shadow: var(--hover-shadow-heavy); +} + +/* Sidebar navigation items */ +.sidebar-nav li a { + transition: var(--hover-transition-fast); +} + +.sidebar-nav li a:hover { + background-color: var(--hover-bg-medium); + border-left-color: var(--primary-color); + color: var(--primary-color); +} + +/* Active state should be stronger */ +.sidebar-nav li.active a { + background-color: var(--hover-bg-strong); + border-left-color: var(--primary-gradient-end); + color: var(--primary-gradient-end); +} + +/* Top navigation */ +.navbar-nav .nav-link:hover { + color: var(--primary-color); + background-color: var(--hover-bg-light); + border-radius: 4px; +} + +/* Dropdown items */ +.dropdown-item:hover { + background-color: var(--hover-bg-medium); + color: var(--primary-color); +} + +/* =================================================================== + CARD & PANEL HOVER STYLES + =================================================================== */ + +/* Base card hover */ +.card, +.panel, +.dashboard-card, +.admin-card, +.stat-card { + transition: var(--hover-transition-normal); +} + +.card:hover, +.panel:hover, +.dashboard-card:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); +} + +/* Clickable cards get stronger effect */ +.admin-card:hover, +.clickable-card:hover { + transform: var(--hover-lift-medium); + box-shadow: var(--hover-shadow-strong); + cursor: pointer; +} + +/* Stat cards */ +.stat-card:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + border-color: var(--hover-bg-strong); +} + +/* Management cards */ +.management-card { + transition: var(--hover-transition-normal); +} + +.management-card:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + border-color: var(--hover-bg-medium); +} + +/* =================================================================== + TABLE HOVER STYLES + =================================================================== */ + +/* Table rows */ +.table tbody tr, +.data-table tbody tr, +.time-history tbody tr { + transition: var(--hover-transition-fast); +} + +.table tbody tr:hover, +.data-table tbody tr:hover, +.time-history tbody tr:hover { + background-color: var(--hover-bg-light); +} + +/* Clickable rows get pointer */ +.clickable-row:hover { + cursor: pointer; + background-color: var(--hover-bg-medium); +} + +/* =================================================================== + FORM ELEMENT HOVER STYLES + =================================================================== */ + +/* Input fields */ +.form-control, +.form-select { + transition: var(--hover-transition-fast); +} + +.form-control:hover:not(:focus), +.form-select:hover:not(:focus) { + border-color: var(--primary-color); + box-shadow: 0 0 0 1px var(--hover-bg-light); +} + +/* Checkboxes and radios */ +.form-check-input:hover { + border-color: var(--primary-color); + box-shadow: 0 0 0 2px var(--hover-bg-medium); +} + +/* =================================================================== + ICON HOVER STYLES + =================================================================== */ + +/* Icon buttons */ +.icon-btn { + transition: var(--hover-transition-fast); +} + +.icon-btn:hover { + color: var(--primary-color); + background-color: var(--hover-bg-medium); + border-radius: 50%; +} + +/* Action icons */ +.action-icon:hover { + color: var(--primary-color); + transform: scale(1.1); +} + +/* =================================================================== + SPECIAL COMPONENT HOVER STYLES + =================================================================== */ + +/* Task cards */ +.task-card { + transition: var(--hover-transition-normal); +} + +.task-card:hover { + transform: var(--hover-lift-subtle); + box-shadow: var(--hover-shadow-medium); + border-left-color: var(--primary-color); +} + +/* Note cards */ +.note-card:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + border-color: var(--hover-bg-strong); +} + +/* Export sections */ +.export-section:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-strong); +} + +/* Widget hover */ +.widget:hover { + transform: var(--hover-lift-small); + box-shadow: var(--hover-shadow-medium); + border-color: var(--hover-bg-medium); +} + +/* Mode buttons */ +.mode-btn:hover:not(.active) { + background-color: var(--hover-bg-medium); + color: var(--primary-color); + border-color: var(--primary-color); +} + +/* Tab buttons */ +.tab-btn:hover:not(.active) { + background-color: var(--hover-bg-light); + color: var(--primary-color); + border-bottom-color: var(--primary-color); +} + +/* =================================================================== + UTILITY HOVER CLASSES + =================================================================== */ + +/* Add these classes to elements for consistent hover effects */ +.hover-lift:hover { + transform: var(--hover-lift-small); +} + +.hover-lift-large:hover { + transform: var(--hover-lift-large); +} + +.hover-shadow:hover { + box-shadow: var(--hover-shadow-medium); +} + +.hover-shadow-strong:hover { + box-shadow: var(--hover-shadow-strong); +} + +.hover-bg:hover { + background-color: var(--hover-bg-medium); +} + +.hover-primary:hover { + color: var(--primary-color); +} + +.hover-scale:hover { + transform: scale(1.05); +} + +.hover-brightness:hover { + filter: brightness(1.1); +} + +/* =================================================================== + ANIMATION UTILITIES + =================================================================== */ + +/* Smooth all transitions */ +.smooth-transition { + transition: var(--hover-transition-smooth); +} + +/* Quick transitions for responsive feel */ +.quick-transition { + transition: var(--hover-transition-fast); +} + +/* Disable transitions on request */ +.no-transition { + transition: none !important; +} + +/* =================================================================== + DARK MODE ADJUSTMENTS (if applicable) + =================================================================== */ + +@media (prefers-color-scheme: dark) { + :root { + --hover-bg-light: rgba(102, 126, 234, 0.1); + --hover-bg-medium: rgba(102, 126, 234, 0.2); + --hover-bg-strong: rgba(102, 126, 234, 0.3); + } +} \ No newline at end of file diff --git a/static/css/splash.css b/static/css/splash.css index d4da092..5531572 100644 --- a/static/css/splash.css +++ b/static/css/splash.css @@ -64,15 +64,15 @@ } .btn-primary { - background: #4CAF50; + background: #667eea; color: white; box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3); } .btn-primary:hover { - background: #45a049; + background: linear-gradient(135deg, #5569d6 0%, #6a4195 100%); transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4); + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3); } .btn-secondary { @@ -83,7 +83,9 @@ .btn-secondary:hover { background: white; - color: #2a5298; + color: #667eea; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2); } /* Floating Clock Animation */ @@ -135,7 +137,7 @@ width: 2px; height: 110px; margin-left: -1px; - background: #4CAF50; + background: #667eea; animation: rotate 60s linear infinite; } @@ -171,8 +173,8 @@ } .feature-card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 30px rgba(0,0,0,0.12); + transform: translateY(-3px); + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.2); } .feature-icon { @@ -329,7 +331,7 @@ top: -15px; left: 50%; transform: translateX(-50%); - background: #4CAF50; + background: #667eea; color: white; padding: 0.5rem 1.5rem; border-radius: 20px; @@ -375,7 +377,7 @@ .btn-pricing { display: inline-block; padding: 1rem 2rem; - background: #4CAF50; + background: #667eea; color: white; text-decoration: none; border-radius: 6px; @@ -385,8 +387,9 @@ } .btn-pricing:hover { - background: #45a049; + background: linear-gradient(135deg, #5569d6 0%, #6a4195 100%); transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(102, 126, 234, 0.2); } .pricing-card.featured .btn-pricing { @@ -394,7 +397,8 @@ } .pricing-card.featured .btn-pricing:hover { - background: #1e3c72; + background: linear-gradient(135deg, #5569d6 0%, #6a4195 100%); + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3); } /* Final CTA */ diff --git a/static/css/style.css b/static/css/style.css index 77e34a8..730f740 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -112,7 +112,7 @@ button { } .sidebar:hover { - box-shadow: 0 6px 30px rgba(0,0,0,0.12); + box-shadow: 0 6px 30px rgba(102, 126, 234, 0.15); } /* Custom scrollbar for sidebar */ @@ -169,7 +169,7 @@ button { } .sidebar-header h2 a:hover { - color: #4CAF50; + color: #667eea; } .sidebar-header small { @@ -229,14 +229,14 @@ button { .sidebar-nav li a:hover { background-color: #e9ecef; - border-left-color: #4CAF50; + border-left-color: #667eea; color: #333; } .sidebar-nav li a.active { - background-color: #e8f5e9; - border-left-color: #4CAF50; - color: #2e7d32; + background-color: rgba(102, 126, 234, 0.1); + border-left-color: #667eea; + color: #5569d6; font-weight: 600; } @@ -366,7 +366,7 @@ body:has(.sidebar.collapsed) .main-content { } .feature h3 { - color: #4CAF50; + color: #667eea; margin-top: 0; } @@ -457,8 +457,10 @@ button { } .btn-primary:hover { - background-color: #0056b3; - border-color: #0056b3; + background-color: #5569d6; + border-color: #5569d6; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2); } .btn-secondary { @@ -470,6 +472,8 @@ button { .btn-secondary:hover { background-color: #545b62; border-color: #545b62; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .btn-success { @@ -481,6 +485,8 @@ button { .btn-success:hover { background-color: #218838; border-color: #218838; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .btn-danger { @@ -492,6 +498,8 @@ button { .btn-danger:hover { background-color: #c82333; border-color: #c82333; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .btn-warning { @@ -503,6 +511,8 @@ button { .btn-warning:hover { background-color: #e0a800; border-color: #e0a800; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .btn-info { @@ -514,6 +524,8 @@ button { .btn-info:hover { background-color: #138496; border-color: #138496; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } /* Button Outline Variants */ @@ -524,8 +536,11 @@ button { } .btn-outline:hover { - background-color: #007bff; + background-color: #667eea; color: white; + border-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2); } /* Special Button Styles */ @@ -539,7 +554,9 @@ button { .btn-filter:hover { background-color: #f8f9fa; - border-color: #adb5bd; + border-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(102, 126, 234, 0.15); } .btn-filter.active { @@ -551,7 +568,7 @@ button { /* Generic Button Hover */ .btn:hover { transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0,0,0,0.1); + box-shadow: 0 2px 4px rgba(102, 126, 234, 0.15); } footer { @@ -600,7 +617,7 @@ footer { } .footer-links a:hover { - color: var(--primary-color); + color: #667eea; } .footer-separator { @@ -662,8 +679,8 @@ footer { } .email-nag-dismiss:hover { - background-color: rgba(0,0,0,0.1); - color: #333; + background-color: rgba(102, 126, 234, 0.1); + color: #5569d6; } @keyframes slideDown { @@ -748,7 +765,9 @@ body:has(.sidebar.collapsed) footer { } .arrive-btn:hover { - background-color: #45a049; + background-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2); } .leave-btn { @@ -760,6 +779,8 @@ body:has(.sidebar.collapsed) footer { .leave-btn:hover { background-color: #d32f2f; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .time-history { @@ -788,7 +809,7 @@ body:has(.sidebar.collapsed) footer { } .time-history tr:hover { - background-color: #f5f5f5; + background-color: rgba(102, 126, 234, 0.05); } .button-group { @@ -807,6 +828,8 @@ body:has(.sidebar.collapsed) footer { .pause-btn:hover { background-color: #f57c00; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15); } .resume-btn { @@ -817,7 +840,9 @@ body:has(.sidebar.collapsed) footer { } .resume-btn:hover { - background-color: #1976D2; + background-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2); } .break-info { @@ -971,7 +996,9 @@ body:has(.sidebar.collapsed) footer { } .edit-entry-btn:hover { - background-color: #0b7dda; + background-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(102, 126, 234, 0.2); } .delete-entry-btn { @@ -981,6 +1008,8 @@ body:has(.sidebar.collapsed) footer { .delete-entry-btn:hover { background-color: #d32f2f; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(102, 126, 234, 0.15); } input[type="date"], input[type="time"] { @@ -1037,8 +1066,8 @@ input[type="time"]::-webkit-datetime-edit { } .admin-card:hover { - transform: translateY(-5px); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); + transform: translateY(-3px); + box-shadow: 0 5px 15px rgba(102, 126, 234, 0.15); } .admin-card h2 { @@ -1113,11 +1142,11 @@ input[type="time"]::-webkit-datetime-edit { } .checkbox-container:hover input ~ .checkmark { - background-color: #ccc; + background-color: rgba(102, 126, 234, 0.15); } .checkbox-container input:checked ~ .checkmark { - background-color: #2196F3; + background-color: #667eea; } .checkmark:after { @@ -1171,7 +1200,7 @@ input[type="time"]::-webkit-datetime-edit { } .data-table tr:hover { - background-color: #f5f5f5; + background-color: rgba(102, 126, 234, 0.05); } /* Team Hours Page Styles */ @@ -1266,16 +1295,16 @@ input[type="time"]::-webkit-datetime-edit { .export-section:hover { transform: translateY(-2px); - box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.2); } .export-section h3 { - color: #4CAF50; + color: #667eea; margin-top: 0; margin-bottom: 1.5rem; font-size: 1.3rem; font-weight: 600; - border-bottom: 2px solid #4CAF50; + border-bottom: 2px solid #667eea; padding-bottom: 0.5rem; } @@ -1296,7 +1325,7 @@ input[type="time"]::-webkit-datetime-edit { .quick-export-buttons .btn:hover { transform: translateY(-1px); - box-shadow: 0 3px 10px rgba(76, 175, 80, 0.3); + box-shadow: 0 3px 10px rgba(102, 126, 234, 0.25); } .export-button-container { @@ -1305,7 +1334,7 @@ input[type="time"]::-webkit-datetime-edit { } .export-button-container .btn { - background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%); + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 1rem 2rem; font-size: 1.1rem; @@ -1314,13 +1343,13 @@ input[type="time"]::-webkit-datetime-edit { display: inline-block; transition: all 0.2s ease; font-weight: 600; - box-shadow: 0 2px 10px rgba(76, 175, 80, 0.3); + box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3); } .export-button-container .btn:hover { transform: translateY(-2px); - box-shadow: 0 4px 15px rgba(76, 175, 80, 0.4); - background: linear-gradient(135deg, #45a049 0%, #4CAF50 100%); + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.25); + background: linear-gradient(135deg, #764ba2 0%, #667eea 100%); } /* Custom date range form styling */ @@ -1348,8 +1377,8 @@ input[type="time"]::-webkit-datetime-edit { .export-section .form-group input:focus, .export-section .form-group select:focus { outline: none; - border-color: #4CAF50; - box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1); + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } /* Team Hours Export Styling */ @@ -1364,7 +1393,7 @@ input[type="time"]::-webkit-datetime-edit { } #export-buttons h4 { - color: #4CAF50; + color: #667eea; margin-bottom: 1rem; font-size: 1.2rem; font-weight: 600; @@ -1387,7 +1416,7 @@ input[type="time"]::-webkit-datetime-edit { #export-buttons .quick-export-buttons .btn:hover { transform: translateY(-1px); - box-shadow: 0 3px 10px rgba(76, 175, 80, 0.3); + box-shadow: 0 3px 10px rgba(102, 126, 234, 0.25); } /* Responsive Design for Sidebar Navigation */ @media (max-width: 1024px) { @@ -1528,14 +1557,14 @@ input[type="time"]::-webkit-datetime-edit { } .mode-btn.active { - background: #4CAF50; + background: #667eea; color: white; - box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3); + box-shadow: 0 2px 4px rgba(102, 126, 234, 0.3); } .mode-btn:hover:not(.active) { - background: #e9ecef; - color: #495057; + background: rgba(102, 126, 234, 0.1); + color: #5569d6; } .filter-panel { @@ -1579,8 +1608,8 @@ input[type="time"]::-webkit-datetime-edit { .filter-group input:focus, .filter-group select:focus { outline: none; - border-color: #4CAF50; - box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1); + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } .view-tabs { @@ -1603,14 +1632,14 @@ input[type="time"]::-webkit-datetime-edit { } .tab-btn.active { - color: #4CAF50; - border-bottom-color: #4CAF50; - background: rgba(76, 175, 80, 0.05); + color: #667eea; + border-bottom-color: #667eea; + background: rgba(102, 126, 234, 0.05); } .tab-btn:hover:not(.active) { - color: #495057; - background: rgba(0, 0, 0, 0.05); + color: #5569d6; + background: rgba(102, 126, 234, 0.05); } .view-content { @@ -1700,7 +1729,7 @@ input[type="time"]::-webkit-datetime-edit { border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); text-align: center; - border-left: 4px solid #4CAF50; + border-left: 4px solid #667eea; } .stat-card h4 { @@ -1796,8 +1825,8 @@ input[type="time"]::-webkit-datetime-edit { .form-group textarea:focus, .form-group select:focus { outline: none; - border-color: #4CAF50; - box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1); + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } /* Responsive Design for Analytics */ @@ -2031,7 +2060,7 @@ input[type="time"]::-webkit-datetime-edit { } .view-btn:hover:not(.active) { - background: #e9ecef; + background: rgba(102, 126, 234, 0.1); } /* Statistics Cards */ @@ -2165,7 +2194,7 @@ input[type="time"]::-webkit-datetime-edit { } .management-card:hover { - box-shadow: 0 4px 12px rgba(0,0,0,0.1); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15); transform: translateY(-2px); } @@ -2289,7 +2318,7 @@ input[type="time"]::-webkit-datetime-edit { } .card:hover { - box-shadow: 0 4px 12px rgba(0,0,0,0.15); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2); } .card-header { @@ -2362,7 +2391,7 @@ input[type="time"]::-webkit-datetime-edit { } .widget:hover { - box-shadow: 0 4px 8px rgba(0,0,0,0.15); + box-shadow: 0 4px 8px rgba(102, 126, 234, 0.2); } .widget-header { @@ -2549,8 +2578,8 @@ input[type="time"]::-webkit-datetime-edit { } .user-dropdown-toggle:hover { - background-color: #e9ecef; - color: #333; + background-color: rgba(102, 126, 234, 0.1); + color: #5569d6; } /* Removed nav-icon style as we're using avatar instead */ @@ -2643,7 +2672,7 @@ input[type="time"]::-webkit-datetime-edit { } .user-dropdown-menu a:hover { - background-color: #f0f0f0; + background-color: rgba(102, 126, 234, 0.1); } .user-dropdown-menu .nav-icon { diff --git a/static/css/time-tracking.css b/static/css/time-tracking.css new file mode 100644 index 0000000..14a042c --- /dev/null +++ b/static/css/time-tracking.css @@ -0,0 +1,770 @@ +/* Time Tracking Styles */ + +/* Container */ +.time-tracking-container { + max-width: 1400px; + margin: 0 auto; + padding: 2rem; +} + +/* Page Header - reuse existing styles */ +.page-header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 16px; + padding: 2rem; + color: white; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + margin-bottom: 2rem; +} + +.header-content { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 2rem; +} + +.page-title { + font-size: 2rem; + font-weight: 700; + margin: 0; + display: flex; + align-items: center; + gap: 0.75rem; +} + +.page-icon { + font-size: 2.5rem; + display: inline-block; + animation: float 3s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-10px); } +} + +.page-subtitle { + font-size: 1.1rem; + opacity: 0.9; + margin: 0.5rem 0 0 0; +} + +.header-actions { + display: flex; + gap: 1rem; +} + +/* Timer Section */ +.timer-section { + margin-bottom: 2rem; +} + +.timer-card { + background: white; + border-radius: 16px; + padding: 2rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); + border: 1px solid #e5e7eb; +} + +.timer-card.active { + border: 2px solid #10b981; + background: linear-gradient(135deg, #10b98110 0%, #059b6910 100%); +} + +.timer-display { + text-align: center; + margin-bottom: 2rem; +} + +.timer-value { + font-size: 4rem; + font-weight: 700; + color: #1f2937; + font-family: 'Monaco', 'Courier New', monospace; + letter-spacing: 0.1em; +} + +.timer-status { + margin-top: 0.5rem; +} + +.status-badge { + display: inline-block; + padding: 0.5rem 1rem; + border-radius: 20px; + font-size: 0.875rem; + font-weight: 600; + text-transform: uppercase; +} + +.status-badge.active { + background: #10b981; + color: white; +} + +.status-badge.paused { + background: #f59e0b; + color: white; +} + +.timer-info { + background: #f8f9fa; + border-radius: 12px; + padding: 1.5rem; + margin-bottom: 1.5rem; +} + +.info-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.5rem 0; + border-bottom: 1px solid #e5e7eb; +} + +.info-row:last-child { + border-bottom: none; +} + +.info-label { + font-weight: 600; + color: #6b7280; +} + +.info-value { + color: #1f2937; +} + +.project-badge { + display: inline-block; + padding: 0.25rem 0.75rem; + border-radius: 16px; + color: white; + font-size: 0.875rem; + font-weight: 500; +} + +.task-badge { + display: inline-block; + padding: 0.25rem 0.75rem; + background: #e5e7eb; + border-radius: 8px; + font-size: 0.875rem; +} + +.timer-actions { + display: flex; + gap: 1rem; + justify-content: center; +} + +/* Start Work Form */ +.start-work-container { + text-align: center; +} + +.start-work-container h2 { + font-size: 1.75rem; + color: #1f2937; + margin-bottom: 0.5rem; +} + +.start-work-container p { + color: #6b7280; + margin-bottom: 2rem; +} + +.modern-form { + max-width: 600px; + margin: 0 auto; +} + +.form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.form-label { + font-weight: 600; + color: #374151; + font-size: 0.95rem; +} + +.optional-badge { + background: #e5e7eb; + color: #6b7280; + padding: 0.125rem 0.5rem; + border-radius: 12px; + font-size: 0.75rem; + font-weight: 500; + margin-left: 0.5rem; +} + +.form-control { + padding: 0.75rem 1rem; + border: 2px solid #e5e7eb; + border-radius: 8px; + font-size: 1rem; + transition: all 0.2s ease; + background-color: #f9fafb; +} + +.form-control:focus { + outline: none; + border-color: #667eea; + background-color: white; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +.form-actions { + margin-top: 1.5rem; +} + +/* Stats Section */ +.stats-section { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; +} + +.stat-card { + background: white; + padding: 1.5rem; + border-radius: 12px; + text-align: center; + border: 1px solid #e5e7eb; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + transition: all 0.3s ease; +} + +.stat-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1); +} + +.stat-value { + font-size: 2rem; + font-weight: 700; + margin-bottom: 0.5rem; + color: #667eea; +} + +.stat-label { + font-size: 0.9rem; + color: #6b7280; + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 600; +} + +/* Entries Section */ +.entries-section { + background: white; + border-radius: 16px; + padding: 2rem; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); + border: 1px solid #e5e7eb; +} + +.section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; +} + +.section-title { + font-size: 1.5rem; + font-weight: 600; + color: #1f2937; + margin: 0; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.view-toggle { + display: flex; + gap: 0.5rem; +} + +.toggle-btn { + padding: 0.5rem 1rem; + border: 2px solid #e5e7eb; + background: white; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + gap: 0.25rem; + font-weight: 500; +} + +.toggle-btn.active { + background: #667eea; + color: white; + border-color: #667eea; +} + +.view-container { + display: none; +} + +.view-container.active { + display: block; +} + +/* Table Styles */ +.entries-table-container { + overflow-x: auto; +} + +.entries-table { + width: 100%; + border-collapse: collapse; +} + +.entries-table th { + text-align: left; + padding: 1rem; + border-bottom: 2px solid #e5e7eb; + font-weight: 600; + color: #374151; + background: #f8f9fa; +} + +.entries-table td { + padding: 1rem; + border-bottom: 1px solid #e5e7eb; +} + +.entry-row:hover { + background: #f8f9fa; +} + +.date-cell { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.date-day { + font-size: 1.25rem; + font-weight: 700; + color: #1f2937; +} + +.date-month { + font-size: 0.875rem; + color: #6b7280; + text-transform: uppercase; +} + +.time-cell { + display: flex; + align-items: center; + gap: 0.5rem; + font-family: 'Monaco', 'Courier New', monospace; +} + +.time-separator { + color: #9ca3af; +} + +.project-task-cell { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.project-tag { + display: inline-block; + padding: 0.25rem 0.5rem; + border-radius: 4px; + color: white; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; +} + +.task-name, +.project-name { + color: #374151; +} + +.no-project { + color: #9ca3af; + font-style: italic; +} + +.duration-badge { + display: inline-block; + padding: 0.25rem 0.75rem; + background: #ede9fe; + color: #5b21b6; + border-radius: 16px; + font-weight: 600; + font-size: 0.875rem; +} + +.break-duration { + color: #6b7280; +} + +.notes-preview { + color: #6b7280; + font-size: 0.875rem; +} + +.actions-cell { + display: flex; + gap: 0.5rem; +} + +/* Specific button hover states */ +.btn-icon.resume-work-btn:hover:not(:disabled) { + color: #10b981; + border-color: #10b981; + background: #f0fdf4; +} + +.btn-icon.edit-entry-btn:hover { + color: #667eea; + border-color: #667eea; + background: #f3f4f6; +} + +.btn-icon.delete-entry-btn:hover { + color: #ef4444; + border-color: #ef4444; + background: #fef2f2; +} + +/* Grid View */ +.entries-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); + gap: 1.5rem; +} + +.entry-card { + background: #f8f9fa; + border-radius: 12px; + padding: 1.5rem; + border: 1px solid #e5e7eb; + transition: all 0.3s ease; +} + +.entry-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + transform: translateY(-2px); +} + +.entry-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.entry-date { + font-weight: 600; + color: #374151; +} + +.entry-duration { + font-size: 1.25rem; + font-weight: 700; + color: #667eea; +} + +.entry-body { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.entry-project { + padding-left: 1rem; + border-left: 4px solid; +} + +.entry-task, +.entry-time, +.entry-notes { + display: flex; + align-items: flex-start; + gap: 0.5rem; + color: #6b7280; + font-size: 0.875rem; +} + +.entry-footer { + display: flex; + gap: 0.5rem; + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid #e5e7eb; +} + +/* Buttons */ +.btn { + padding: 0.75rem 1.5rem; + border: none; + border-radius: 8px; + font-weight: 600; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + gap: 0.5rem; + text-decoration: none; +} + +.btn-large { + padding: 1rem 2rem; + font-size: 1.125rem; +} + +.btn-sm { + padding: 0.5rem 1rem; + font-size: 0.875rem; +} + +.btn-icon { + padding: 0.5rem; + border: 1px solid #e5e7eb; + background: white; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + color: #6b7280; + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; +} + +.btn-icon:hover { + background: #f3f4f6; + transform: translateY(-2px); + color: #374151; +} + +.btn-icon:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.btn-icon:disabled:hover { + transform: none; + background: white; + color: #6b7280; +} + +.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); +} + +.btn-secondary { + background: white; + color: #4b5563; + border: 2px solid #e5e7eb; +} + +.btn-secondary:hover { + background: #f3f4f6; +} + +.btn-success { + background: #10b981; + color: white; +} + +.btn-success:hover { + background: #059669; + transform: translateY(-2px); +} + +.btn-warning { + background: #f59e0b; + color: white; +} + +.btn-warning:hover { + background: #d97706; + transform: translateY(-2px); +} + +.btn-danger { + background: #ef4444; + color: white; +} + +.btn-danger:hover { + background: #dc2626; + transform: translateY(-2px); +} + +.btn-ghost { + background: transparent; + color: #6b7280; +} + +.btn-ghost:hover { + color: #374151; + background: #f3f4f6; +} + +/* Empty State */ +.empty-state { + text-align: center; + padding: 4rem 2rem; +} + +.empty-icon { + font-size: 4rem; + margin-bottom: 1rem; +} + +.empty-state h3 { + font-size: 1.5rem; + font-weight: 600; + color: #1f2937; + margin-bottom: 0.5rem; +} + +.empty-state p { + color: #6b7280; +} + +/* Modal Styles */ +.modal { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; +} + +.modal-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); +} + +.modal-content { + position: relative; + background: white; + border-radius: 16px; + max-width: 600px; + margin: 5vh auto; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2); +} + +.modal-small { + max-width: 400px; +} + +.modal-header { + padding: 2rem; + border-bottom: 1px solid #e5e7eb; + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-title { + font-size: 1.5rem; + font-weight: 600; + color: #1f2937; + margin: 0; +} + +.modal-close { + background: none; + border: none; + font-size: 1.5rem; + cursor: pointer; + color: #6b7280; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 8px; + transition: all 0.2s ease; +} + +.modal-close:hover { + background: #f3f4f6; + color: #1f2937; +} + +.modal-body { + padding: 2rem; +} + +.modal-footer { + padding: 1.5rem 2rem; + border-top: 1px solid #e5e7eb; + display: flex; + justify-content: flex-end; + gap: 1rem; +} + +/* Responsive */ +@media (max-width: 768px) { + .time-tracking-container { + padding: 1rem; + } + + .form-row { + grid-template-columns: 1fr; + } + + .timer-value { + font-size: 3rem; + } + + .entries-grid { + grid-template-columns: 1fr; + } + + .entries-table { + font-size: 0.875rem; + } + + .entries-table th, + .entries-table td { + padding: 0.5rem; + } +} \ No newline at end of file diff --git a/templates/_time_tracking_interface.html b/templates/_time_tracking_interface.html new file mode 100644 index 0000000..b6f6eec --- /dev/null +++ b/templates/_time_tracking_interface.html @@ -0,0 +1,356 @@ + +
Track your work hours efficiently
+Select a project and task to begin tracking your work
+ + +| Date | +Time | +Project / Task | +Duration | +Break | +Notes | +Actions | +
|---|---|---|---|---|---|---|
|
+
+ {{ entry.arrival_time.strftime('%d') }}
+ {{ entry.arrival_time.strftime('%b') }}
+
+ |
+
+
+ {{ entry.arrival_time|format_time }}
+
+ {{ entry.departure_time|format_time if entry.departure_time else 'Active' }}
+
+ |
+
+
+ {% if entry.project %}
+
+ {{ entry.project.code }}
+
+ {% endif %}
+ {% if entry.task %}
+ {{ entry.task.title }}
+ {% elif entry.project %}
+ {{ entry.project.name }}
+ {% else %}
+ No project
+ {% endif %}
+
+ |
+ + + {{ entry.duration|format_duration if entry.duration is not none else 'In progress' }} + + | ++ + {{ entry.total_break_duration|format_duration if entry.total_break_duration else '-' }} + + | ++ + {{ entry.notes[:30] + '...' if entry.notes and entry.notes|length > 30 else entry.notes or '-' }} + + | +
+
+ {% if entry.departure_time and not active_entry %}
+ {% if entry.arrival_time.date() >= today %}
+
+ {% else %}
+
+ {% endif %}
+ {% endif %}
+
+
+
+ |
+
Start tracking your time to see entries here
+Manage user accounts and permissions across your organization
@@ -49,7 +49,7 @@Organize work into sprints with agile project tracking
Manage teams, projects, and resources all in one place
Bank-level encryption with role-based access control
Perfect for agencies managing multiple client accounts
Create your free account in seconds. No credit card required.
Add your company, teams, and projects to organize your time tracking.
Click "Arrive" to start tracking, "Leave" when done. It's that simple!
Track your work hours efficiently
-Select a project and task to begin tracking your work
- - -| Date | -Time | -Project / Task | -Duration | -Break | -Notes | -Actions | -
|---|---|---|---|---|---|---|
|
-
- {{ entry.arrival_time.strftime('%d') }}
- {{ entry.arrival_time.strftime('%b') }}
-
- |
-
-
- {{ entry.arrival_time|format_time }}
-
- {{ entry.departure_time|format_time if entry.departure_time else 'Active' }}
-
- |
-
-
- {% if entry.project %}
-
- {{ entry.project.code }}
-
- {% endif %}
- {% if entry.task %}
- {{ entry.task.title }}
- {% elif entry.project %}
- {{ entry.project.name }}
- {% else %}
- No project
- {% endif %}
-
- |
- - - {{ entry.duration|format_duration if entry.duration is not none else 'In progress' }} - - | -- - {{ entry.total_break_duration|format_duration if entry.total_break_duration else '-' }} - - | -- - {{ entry.notes[:30] + '...' if entry.notes and entry.notes|length > 30 else entry.notes or '-' }} - - | -
-
- {% if entry.departure_time and not active_entry %}
-
- {% endif %}
-
-
-
- |
-
Start tracking your time to see entries here
-Manage team invitations for {{ g.user.company.name }}
@@ -45,7 +45,7 @@ {% if pending_invitations %}Start building your team by sending invitations
diff --git a/templates/invitations/send.html b/templates/invitations/send.html index 4b5aab3..ead2ad1 100644 --- a/templates/invitations/send.html +++ b/templates/invitations/send.html @@ -7,7 +7,7 @@Invite team members to join {{ g.user.company.name }}
@@ -60,7 +60,7 @@