chore: init
This commit is contained in:
167
.cursor/rules/css-variables-theme.mdc
Normal file
167
.cursor/rules/css-variables-theme.mdc
Normal file
@@ -0,0 +1,167 @@
|
||||
---
|
||||
alwaysApply: true
|
||||
description: CSS Variables theme system best practices
|
||||
---
|
||||
|
||||
# CSS Variables Theme System
|
||||
|
||||
## Core Principle: Pure CSS Variables for Theming
|
||||
|
||||
This project uses **CSS Variables exclusively** for theming. No Tailwind `dark:` classes or conditional CSS classes.
|
||||
|
||||
## ✅ Architecture Pattern
|
||||
|
||||
### CSS Structure
|
||||
```css
|
||||
:root {
|
||||
/* Light theme (default values) */
|
||||
--background: #f1f5f9;
|
||||
--foreground: #0f172a;
|
||||
--primary: #0891b2;
|
||||
--success: #059669;
|
||||
--destructive: #dc2626;
|
||||
--accent: #d97706;
|
||||
--purple: #8b5cf6;
|
||||
--yellow: #eab308;
|
||||
--green: #059669;
|
||||
--blue: #2563eb;
|
||||
--gray: #6b7280;
|
||||
--gray-light: #e5e7eb;
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Dark theme (override values) */
|
||||
--background: #1e293b;
|
||||
--foreground: #f1f5f9;
|
||||
--primary: #06b6d4;
|
||||
--success: #10b981;
|
||||
--destructive: #ef4444;
|
||||
--accent: #f59e0b;
|
||||
--purple: #8b5cf6;
|
||||
--yellow: #eab308;
|
||||
--green: #10b981;
|
||||
--blue: #3b82f6;
|
||||
--gray: #9ca3af;
|
||||
--gray-light: #374151;
|
||||
}
|
||||
```
|
||||
|
||||
### Theme Application
|
||||
- **Single source of truth**: [ThemeContext.tsx](mdc:src/contexts/ThemeContext.tsx) applies theme class to `document.documentElement`
|
||||
- **No duplication**: Theme is applied only once, not in multiple places
|
||||
- **SSR safe**: Initial theme from server-side preferences
|
||||
|
||||
## ✅ Component Usage Patterns
|
||||
|
||||
### Correct: Using CSS Variables
|
||||
```tsx
|
||||
// ✅ GOOD: CSS Variables in className
|
||||
<div className="bg-[var(--card)] text-[var(--foreground)] border-[var(--border)]">
|
||||
|
||||
// ✅ GOOD: CSS Variables in style prop
|
||||
<div style={{ color: 'var(--primary)', backgroundColor: 'var(--card)' }}>
|
||||
|
||||
// ✅ GOOD: CSS Variables with color-mix for transparency
|
||||
<div style={{
|
||||
backgroundColor: 'color-mix(in srgb, var(--primary) 10%, transparent)',
|
||||
borderColor: 'color-mix(in srgb, var(--primary) 20%, var(--border))'
|
||||
}}>
|
||||
```
|
||||
|
||||
### ❌ Forbidden: Tailwind Dark Mode Classes
|
||||
```tsx
|
||||
// ❌ BAD: Tailwind dark: classes
|
||||
<div className="bg-white dark:bg-gray-800 text-black dark:text-white">
|
||||
|
||||
// ❌ BAD: Conditional classes
|
||||
<div className={theme === 'dark' ? 'bg-gray-800' : 'bg-white'}>
|
||||
|
||||
// ❌ BAD: Hardcoded colors
|
||||
<div className="bg-red-500 text-blue-600">
|
||||
```
|
||||
|
||||
## ✅ Color System
|
||||
|
||||
### Semantic Color Tokens
|
||||
- `--background`: Main background color
|
||||
- `--foreground`: Main text color
|
||||
- `--card`: Card/panel background
|
||||
- `--card-hover`: Card hover state
|
||||
- `--card-column`: Column background (darker than cards)
|
||||
- `--border`: Border color
|
||||
- `--input`: Input field background
|
||||
- `--primary`: Primary brand color
|
||||
- `--primary-foreground`: Text on primary background
|
||||
- `--muted`: Muted text color
|
||||
- `--muted-foreground`: Secondary text color
|
||||
- `--accent`: Accent color (orange/amber)
|
||||
- `--destructive`: Error/danger color (red)
|
||||
- `--success`: Success color (green)
|
||||
- `--purple`: Purple accent
|
||||
- `--yellow`: Yellow accent
|
||||
- `--green`: Green accent
|
||||
- `--blue`: Blue accent
|
||||
- `--gray`: Gray color
|
||||
- `--gray-light`: Light gray background
|
||||
|
||||
### Color Mixing Patterns
|
||||
```css
|
||||
/* Background with transparency */
|
||||
background-color: color-mix(in srgb, var(--primary) 10%, transparent);
|
||||
|
||||
/* Border with transparency */
|
||||
border-color: color-mix(in srgb, var(--primary) 20%, var(--border));
|
||||
|
||||
/* Text with opacity */
|
||||
color: color-mix(in srgb, var(--destructive) 80%, transparent);
|
||||
```
|
||||
|
||||
## ✅ Theme Context Usage
|
||||
|
||||
### ThemeProvider Setup
|
||||
```tsx
|
||||
// In layout.tsx
|
||||
<ThemeProvider initialTheme={initialPreferences.viewPreferences.theme}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
```
|
||||
|
||||
### Component Usage
|
||||
```tsx
|
||||
import { useTheme } from '@/contexts/ThemeContext';
|
||||
|
||||
function MyComponent() {
|
||||
const { theme, toggleTheme, setTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<button onClick={toggleTheme}>
|
||||
Switch to {theme === 'dark' ? 'light' : 'dark'} theme
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ Future Extensibility
|
||||
|
||||
This system is designed to support:
|
||||
- **Custom color themes**: Easy to add new color variables
|
||||
- **User preferences**: Colors can be dynamically changed
|
||||
- **Theme presets**: Multiple predefined themes
|
||||
- **Accessibility**: High contrast modes
|
||||
|
||||
## 🚨 Anti-patterns to Avoid
|
||||
|
||||
1. **Don't mix approaches**: Never use both CSS variables and Tailwind dark: classes
|
||||
2. **Don't duplicate theme application**: Theme should be applied only in ThemeContext
|
||||
3. **Don't hardcode colors**: Always use semantic color tokens
|
||||
4. **Don't use conditional classes**: Use CSS variables instead
|
||||
5. **Don't forget transparency**: Use `color-mix()` for semi-transparent colors
|
||||
|
||||
## 📁 Key Files
|
||||
|
||||
- [globals.css](mdc:src/app/globals.css) - CSS Variables definitions
|
||||
- [ThemeContext.tsx](mdc:src/contexts/ThemeContext.tsx) - Theme management
|
||||
- [UserPreferencesContext.tsx](mdc:src/contexts/UserPreferencesContext.tsx) - Preferences sync
|
||||
- [layout.tsx](mdc:src/app/layout.tsx) - Theme provider setup
|
||||
|
||||
Remember: **CSS Variables are the single source of truth for theming. Keep it pure and consistent.**
|
||||
Reference in New Issue
Block a user