mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-17 18:38:46 -05:00
refactor(ui): refresh Tailwind design system tokens
Adopt an indigo brand palette with slate neutrals, add semantic colors, and introduce base/component layers (buttons, cards, badges). Move Inter loading to the Tailwind input CSS and update brand guidelines accordingly.
This commit is contained in:
+80
-31
@@ -1,3 +1,5 @@
|
||||
@import url('https://fonts.bunny.net/css?family=Inter:400,500,600,700&display=swap');
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -6,36 +8,41 @@
|
||||
@layer base {
|
||||
:root {
|
||||
/* Brand (brand-colors.css) */
|
||||
--brand-primary: #4A90E2;
|
||||
--brand-primary-dark: #3b82f6;
|
||||
--brand-primary: #4F46E5;
|
||||
--brand-primary-dark: #4338ca;
|
||||
--brand-secondary: #50E3C2;
|
||||
--brand-secondary-dark: #06b6d4;
|
||||
--brand-gradient: linear-gradient(135deg, #4A90E2 0%, #50E3C2 100%);
|
||||
--brand-gradient-horizontal: linear-gradient(to right, #4A90E2 0%, #50E3C2 100%);
|
||||
--color-success: #4CAF50;
|
||||
--color-warning: #FF9800;
|
||||
--color-error: #E53935;
|
||||
--color-info: #2196F3;
|
||||
--color-bg-light: #F7F9FB;
|
||||
--color-bg-light-secondary: #FFFFFF;
|
||||
--color-text-light: #2D3748;
|
||||
--color-text-light-secondary: #A0AEC0;
|
||||
--color-text-light-muted: #718096;
|
||||
--color-border-light: #E2E8F0;
|
||||
--color-bg-dark: #1A202C;
|
||||
--color-bg-dark-secondary: #2D3748;
|
||||
--color-text-dark: #E2E8F0;
|
||||
--color-text-dark-secondary: #718096;
|
||||
--color-text-dark-muted: #A0AEC0;
|
||||
--color-border-dark: #4A5568;
|
||||
--brand-gradient: linear-gradient(135deg, #4F46E5 0%, #50E3C2 100%);
|
||||
--brand-gradient-horizontal: linear-gradient(to right, #4F46E5 0%, #50E3C2 100%);
|
||||
|
||||
/* Semantic */
|
||||
--color-success: #10b981;
|
||||
--color-warning: #f59e0b;
|
||||
--color-error: #ef4444;
|
||||
--color-info: #3b82f6;
|
||||
|
||||
/* Neutrals (slate-based) */
|
||||
--color-bg-light: #f8fafc;
|
||||
--color-bg-light-secondary: #ffffff;
|
||||
--color-text-light: #0f172a;
|
||||
--color-text-light-secondary: #64748b;
|
||||
--color-text-light-muted: #94a3b8;
|
||||
--color-border-light: #e2e8f0;
|
||||
|
||||
--color-bg-dark: #0b1220;
|
||||
--color-bg-dark-secondary: #0f172a;
|
||||
--color-text-dark: #e2e8f0;
|
||||
--color-text-dark-secondary: #94a3b8;
|
||||
--color-text-dark-muted: #64748b;
|
||||
--color-border-dark: #334155;
|
||||
/* Aliases for keyboard-shortcuts.css */
|
||||
--color-primary: #4A90E2;
|
||||
--color-primary: #4F46E5;
|
||||
--color-card-light: #FFFFFF;
|
||||
--color-background-light: #F7F9FB;
|
||||
--color-background-dark: #1A202C;
|
||||
--color-card-dark: #2D3748;
|
||||
--color-text-muted-light: #A0AEC0;
|
||||
--color-text-muted-dark: #718096;
|
||||
--color-background-light: #f8fafc;
|
||||
--color-background-dark: #0b1220;
|
||||
--color-card-dark: #0f172a;
|
||||
--color-text-muted-light: #64748b;
|
||||
--color-text-muted-dark: #94a3b8;
|
||||
/* Spacing (ui-enhancements) */
|
||||
--spacing-xs: 0.25rem;
|
||||
--spacing-sm: 0.5rem;
|
||||
@@ -45,6 +52,35 @@
|
||||
--spacing-2xl: 3rem;
|
||||
--spacing-3xl: 4rem;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: theme(fontFamily.sans);
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply font-sans antialiased bg-background-light text-text-light dark:bg-background-dark dark:text-text-dark;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@apply text-text-light dark:text-text-dark font-semibold tracking-tight;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-primary hover:text-primary-dark underline-offset-4;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
@apply underline;
|
||||
}
|
||||
|
||||
:is(button, [type='button'], [type='submit'], [role='button']) {
|
||||
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900;
|
||||
}
|
||||
|
||||
:is(input, select, textarea) {
|
||||
@apply placeholder:text-slate-400 dark:placeholder:text-slate-500;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== Layer: Components ========== */
|
||||
@@ -99,6 +135,19 @@
|
||||
@apply px-6 py-3 text-base;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply rounded-lg border border-border-light bg-card-light shadow-tt-soft dark:border-border-dark dark:bg-card-dark;
|
||||
}
|
||||
|
||||
.badge {
|
||||
@apply inline-flex items-center gap-1 rounded-full border border-border-light bg-background-light px-2.5 py-1 text-xs font-medium text-text-light dark:border-border-dark dark:bg-background-dark dark:text-text-dark;
|
||||
}
|
||||
|
||||
.badge-success { @apply badge border-success/20 bg-success/10 text-success dark:border-success/30 dark:bg-success/15; }
|
||||
.badge-warning { @apply badge border-warning/20 bg-warning/10 text-warning dark:border-warning/30 dark:bg-warning/15; }
|
||||
.badge-danger { @apply badge border-danger/20 bg-danger/10 text-danger dark:border-danger/30 dark:bg-danger/15; }
|
||||
.badge-info { @apply badge border-info/20 bg-info/10 text-info dark:border-info/30 dark:bg-info/15; }
|
||||
|
||||
/* Brand utilities (from brand-colors.css) */
|
||||
.bg-brand-gradient { background: var(--brand-gradient); }
|
||||
.bg-brand-gradient-horizontal { background: var(--brand-gradient-horizontal); }
|
||||
@@ -282,12 +331,12 @@
|
||||
.enhanced-table tbody tr { transition: background-color 0.15s; }
|
||||
.enhanced-table tbody tr:nth-child(even) { background-color: rgba(0, 0, 0, 0.02); }
|
||||
.dark .enhanced-table tbody tr:nth-child(even) { background-color: rgba(255, 255, 255, 0.03); }
|
||||
.enhanced-table tbody tr:hover { background-color: rgba(0, 0, 0, 0.04); border-left: 3px solid #4A90E2; }
|
||||
.enhanced-table tbody tr:hover { background-color: rgba(0, 0, 0, 0.04); border-left: 3px solid #4F46E5; }
|
||||
.dark .enhanced-table tbody tr:hover { background-color: rgba(255, 255, 255, 0.05); border-left-color: #60a5fa; }
|
||||
.enhanced-table thead th { position: sticky; top: 0; z-index: 10; background: #fff; box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.06); }
|
||||
.dark .enhanced-table thead th { background: #1e293b; box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.3); }
|
||||
.table-count-badge { display: inline-flex; align-items: center; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.875rem; font-weight: 500; background: rgba(74, 144, 226, 0.12); color: #4A90E2; }
|
||||
.dark .table-count-badge { background: rgba(74, 144, 226, 0.2); color: #93c5fd; }
|
||||
.table-count-badge { display: inline-flex; align-items: center; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.875rem; font-weight: 500; background: rgba(79, 70, 229, 0.12); color: #4F46E5; }
|
||||
.dark .table-count-badge { background: rgba(79, 70, 229, 0.22); color: #c7d2fe; }
|
||||
|
||||
.bulk-actions-bar {
|
||||
position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%) translateY(100px);
|
||||
@@ -498,8 +547,8 @@
|
||||
|
||||
/* File input drag-over state */
|
||||
.form-group-wrapper label:has(input[type="file"]).drag-over {
|
||||
border-color: #4A90E2;
|
||||
background-color: rgba(74, 144, 226, 0.08);
|
||||
border-color: #4F46E5;
|
||||
background-color: rgba(79, 70, 229, 0.08);
|
||||
}
|
||||
|
||||
/* ----- Responsive Table → Card Layout ----- */
|
||||
|
||||
@@ -45,9 +45,7 @@
|
||||
<link rel="manifest" href="{{ url_for('main.manifest') }}">
|
||||
<meta name="vapid-public-key" content="{{ config.get('VAPID_PUBLIC_KEY', '') }}">
|
||||
<script src="{{ url_for('static', filename='pwa-enhancements.js') }}"></script>
|
||||
<!-- Inter font (Bunny Fonts, GDPR-friendly) -->
|
||||
<link rel="preconnect" href="https://fonts.bunny.net" crossorigin>
|
||||
<link href="https://fonts.bunny.net/css?family=Inter:400,500,600,700&display=swap" rel="stylesheet">
|
||||
<!-- Inter font is loaded via CSS @import in app/static/src/input.css -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/output.css') }}?v={{ app_version }}-toastfix1">
|
||||
<!-- Font Awesome -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
||||
|
||||
+35
-36
@@ -68,81 +68,80 @@ The primary TimeTracker logo features a rounded square with a gradient backgroun
|
||||
|
||||
### Primary Colors
|
||||
|
||||
**Primary Blue**
|
||||
- Hex: `#4A90E2`
|
||||
- RGB: `74, 144, 226`
|
||||
- Usage: Primary actions, links, highlights
|
||||
- WCAG AA compliant on white backgrounds
|
||||
**Primary Indigo (Brand)**
|
||||
- Hex: `#4F46E5`
|
||||
- RGB: `79, 70, 229`
|
||||
- Usage: Primary actions, links, focus rings, highlights
|
||||
- Notes: Designed to work with slate-based neutrals in light/dark mode
|
||||
|
||||
**Secondary Cyan**
|
||||
**Secondary Cyan (Accent)**
|
||||
- Hex: `#50E3C2`
|
||||
- RGB: `80, 227, 194`
|
||||
- Usage: Secondary actions, accents, gradients
|
||||
- WCAG AA compliant on dark backgrounds
|
||||
- Usage: Secondary accents, gradients, non-critical highlights
|
||||
|
||||
**Theme Blue**
|
||||
**Info Blue**
|
||||
- Hex: `#3b82f6`
|
||||
- RGB: `59, 130, 246`
|
||||
- Usage: PWA theme color, browser chrome
|
||||
- Usage: Informational states and highlights (not the primary brand color)
|
||||
|
||||
### Gradient
|
||||
|
||||
The brand uses a gradient from Primary Blue to Secondary Cyan:
|
||||
- Start: `#4A90E2` (Primary Blue)
|
||||
The brand uses a gradient from Primary Indigo to Secondary Cyan:
|
||||
- Start: `#4F46E5` (Primary Indigo)
|
||||
- End: `#50E3C2` (Secondary Cyan)
|
||||
- Direction: Diagonal (135deg) or horizontal as needed
|
||||
|
||||
### Status Colors
|
||||
|
||||
**Success (Green)**
|
||||
- Hex: `#4CAF50`
|
||||
- Hex: `#10b981`
|
||||
- Usage: Success messages, positive indicators
|
||||
|
||||
**Warning (Orange)**
|
||||
- Hex: `#FF9800`
|
||||
**Warning (Amber)**
|
||||
- Hex: `#f59e0b`
|
||||
- Usage: Warnings, caution messages
|
||||
|
||||
**Error (Red)**
|
||||
- Hex: `#E53935`
|
||||
**Error / Danger (Red)**
|
||||
- Hex: `#ef4444`
|
||||
- Usage: Error messages, destructive actions
|
||||
|
||||
### Background Colors
|
||||
|
||||
**Light Mode:**
|
||||
- Background: `#F7F9FB`
|
||||
- Card: `#FFFFFF`
|
||||
- Secondary: `#f5f5f5`
|
||||
**Light Mode (Slate):**
|
||||
- Background: `#f8fafc`
|
||||
- Card: `#ffffff`
|
||||
- Border: `#e2e8f0`
|
||||
|
||||
**Dark Mode:**
|
||||
- Background: `#1A202C`
|
||||
- Card: `#2D3748`
|
||||
- Secondary: `#4A5568`
|
||||
**Dark Mode (Slate):**
|
||||
- Background: `#0b1220`
|
||||
- Card: `#0f172a`
|
||||
- Border: `#334155`
|
||||
|
||||
### Text Colors
|
||||
|
||||
**Light Mode:**
|
||||
- Primary Text: `#2D3748`
|
||||
- Secondary Text: `#A0AEC0`
|
||||
- Muted Text: `#718096`
|
||||
**Light Mode (Slate):**
|
||||
- Primary Text: `#0f172a`
|
||||
- Secondary Text: `#64748b`
|
||||
- Muted Text: `#94a3b8`
|
||||
|
||||
**Dark Mode:**
|
||||
- Primary Text: `#E2E8F0`
|
||||
- Secondary Text: `#718096`
|
||||
- Muted Text: `#A0AEC0`
|
||||
**Dark Mode (Slate):**
|
||||
- Primary Text: `#e2e8f0`
|
||||
- Secondary Text: `#94a3b8`
|
||||
- Muted Text: `#64748b`
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Families
|
||||
|
||||
**Primary (System Fonts):**
|
||||
**Primary (Inter):**
|
||||
```css
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', Arial, sans-serif;
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
- Body text
|
||||
- UI elements
|
||||
- Default text throughout application
|
||||
- Headings and navigation
|
||||
|
||||
### Font Weights
|
||||
|
||||
|
||||
+80
-22
@@ -14,18 +14,21 @@ module.exports = {
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#4A90E2',
|
||||
600: '#3b82f6',
|
||||
700: '#2563eb',
|
||||
800: '#1d4ed8',
|
||||
900: '#1e3a8a',
|
||||
DEFAULT: '#4A90E2',
|
||||
dark: '#3b82f6',
|
||||
// Brand: deep indigo
|
||||
50: '#eef2ff',
|
||||
100: '#e0e7ff',
|
||||
200: '#c7d2fe',
|
||||
300: '#a5b4fc',
|
||||
400: '#818cf8',
|
||||
500: '#6366f1',
|
||||
600: '#4F46E5',
|
||||
700: '#4338ca',
|
||||
800: '#3730a3',
|
||||
900: '#312e81',
|
||||
950: '#1e1b4b',
|
||||
DEFAULT: '#4F46E5',
|
||||
// Back-compat for `hover:bg-primary-dark` etc.
|
||||
dark: '#4338ca',
|
||||
},
|
||||
secondary: {
|
||||
50: '#ecfeff',
|
||||
@@ -41,16 +44,71 @@ module.exports = {
|
||||
DEFAULT: '#50E3C2',
|
||||
dark: '#06b6d4',
|
||||
},
|
||||
'background-light': '#F7F9FB',
|
||||
'background-dark': '#1A202C',
|
||||
'card-light': '#FFFFFF',
|
||||
'card-dark': '#2D3748',
|
||||
'text-light': '#2D3748',
|
||||
'text-dark': '#E2E8F0',
|
||||
'text-muted-light': '#A0AEC0',
|
||||
'text-muted-dark': '#718096',
|
||||
'border-light': '#E2E8F0',
|
||||
'border-dark': '#4A5568',
|
||||
// Semantic colors
|
||||
success: {
|
||||
50: '#ecfdf5',
|
||||
100: '#d1fae5',
|
||||
500: '#10b981',
|
||||
600: '#059669',
|
||||
700: '#047857',
|
||||
DEFAULT: '#10b981',
|
||||
},
|
||||
warning: {
|
||||
50: '#fffbeb',
|
||||
100: '#fef3c7',
|
||||
500: '#f59e0b',
|
||||
600: '#d97706',
|
||||
700: '#b45309',
|
||||
DEFAULT: '#f59e0b',
|
||||
},
|
||||
danger: {
|
||||
50: '#fff1f2',
|
||||
100: '#ffe4e6',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
DEFAULT: '#ef4444',
|
||||
},
|
||||
info: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
DEFAULT: '#3b82f6',
|
||||
},
|
||||
|
||||
// Neutrals (slate-based) + compatibility aliases used throughout templates
|
||||
'background-light': '#f8fafc', // slate-50
|
||||
'background-dark': '#0b1220', // deep slate-ish
|
||||
'card-light': '#ffffff',
|
||||
'card-dark': '#0f172a', // slate-900
|
||||
'text-light': '#0f172a', // slate-900
|
||||
'text-dark': '#e2e8f0', // slate-200
|
||||
'text-muted-light': '#64748b', // slate-500
|
||||
'text-muted-dark': '#94a3b8', // slate-400
|
||||
'border-light': '#e2e8f0', // slate-200
|
||||
'border-dark': '#334155', // slate-700
|
||||
},
|
||||
borderRadius: {
|
||||
// Additive tokens (avoid overriding Tailwind defaults)
|
||||
tt: '0.75rem',
|
||||
'tt-lg': '1rem',
|
||||
'tt-xl': '1.25rem',
|
||||
},
|
||||
boxShadow: {
|
||||
// Additive tokens (avoid overriding Tailwind defaults)
|
||||
'tt-soft': '0 1px 2px rgba(15, 23, 42, 0.04), 0 2px 6px rgba(15, 23, 42, 0.06)',
|
||||
'tt-card': '0 1px 2px rgba(15, 23, 42, 0.06), 0 6px 18px rgba(15, 23, 42, 0.08)',
|
||||
'tt-lifted': '0 10px 25px rgba(15, 23, 42, 0.14), 0 4px 10px rgba(15, 23, 42, 0.08)',
|
||||
},
|
||||
spacing: {
|
||||
// Additive tokens (avoid overriding Tailwind defaults)
|
||||
'tt-xs': '0.375rem',
|
||||
'tt-sm': '0.625rem',
|
||||
'tt-md': '0.875rem',
|
||||
'tt-lg': '1.125rem',
|
||||
'tt-xl': '1.375rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user