ai: theme

This commit is contained in:
Alejandro Gómez
2025-12-15 17:30:18 +01:00
parent 98723a25aa
commit 78a2deeadd

View File

@@ -0,0 +1,812 @@
# Grimoire Theme Token System
## Overview
Comprehensive design token system for Grimoire's visual styling. This system abstracts all visual properties into semantic tokens that can be applied to any theme (dark, light, or custom). Built on industry-standard design token patterns used by Tailwind, Radix, and Material Design.
**Status**: Design Complete - Ready for Implementation
**Approach**: Two-tier token system (Base + Semantic)
**Format**: HSL for colors, CSS length units for spacing/sizing
**Philosophy**: Theme-agnostic components, theme-specific values
---
## Token Categories
### 1. Colors (Surfaces & Interactive)
Semantic color tokens for backgrounds, text, and UI elements.
**Structure**:
```typescript
colors: {
// Surfaces
background: HSL; // Main app background
foreground: HSL; // Main text color
card: HSL; // Elevated surface
"card-foreground": HSL;
popover: HSL; // Floating elements
"popover-foreground": HSL;
// Interactive Elements
primary: HSL; // Primary actions (buttons, links)
"primary-foreground": HSL;
secondary: HSL; // Secondary actions
"secondary-foreground": HSL;
muted: HSL; // Subtle backgrounds
"muted-foreground": HSL; // Secondary text
accent: HSL; // Highlight/emphasis (purple!)
"accent-foreground": HSL;
destructive: HSL; // Errors, danger
"destructive-foreground": HSL;
// UI Elements
border: HSL; // Dividers, borders
input: HSL; // Input backgrounds
ring: HSL; // Focus indicators
}
```
**Current Dark Theme Values**:
```typescript
colors: {
background: "222.2 84% 4.9%", // Deep blue-gray
foreground: "210 40% 98%", // Almost white
accent: "270 100% 70%", // Grimoire purple!
// ... full definition in grimoire-dark.ts
}
```
**Light Theme Values**:
```typescript
colors: {
background: "40 20% 97%", // Warm off-white
foreground: "222 84% 8%", // Very dark
accent: "270 100% 50%", // Darker purple (contrast)
// ... full definition in grimoire-light.ts
}
```
---
### 2. Gradients
Multi-stop gradient definitions for brand and decorative purposes.
**Structure**:
```typescript
gradients: {
brand: [HSL, HSL, HSL, HSL]; // Grimoire 4-color brand gradient
}
```
**Current Values**:
```typescript
// Dark theme
gradients: {
brand: [
"43 100% 54%", // Yellow
"25 95% 61%", // Orange
"270 91% 65%", // Purple
"188 86% 53%", // Cyan
],
}
// Light theme (adjusted for contrast)
gradients: {
brand: [
"43 100% 45%", // Darker yellow
"25 95% 50%", // Darker orange
"270 91% 50%", // Darker purple
"188 86% 40%", // Darker cyan
],
}
```
**Usage**:
```css
.text-grimoire-gradient {
background: linear-gradient(
to bottom,
hsl(var(--gradient-brand-1)),
hsl(var(--gradient-brand-2)),
hsl(var(--gradient-brand-3)),
hsl(var(--gradient-brand-4))
);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
```
---
### 3. Syntax Highlighting
Code syntax highlighting colors for Prism.js integration.
**Structure**:
```typescript
syntax: {
// General syntax tokens
comment: HSL;
keyword: HSL;
string: HSL;
function: HSL;
number: HSL;
operator: HSL;
"operator-opacity"?: Opacity;
// Diff-specific tokens (git diffs in code blocks)
deleted: HSL; // Removed lines
"deleted-bg": HSL;
"deleted-bg-opacity": Opacity;
inserted: HSL; // Added lines
"inserted-bg": HSL;
"inserted-bg-opacity": Opacity;
coord: HSL; // Hunk headers (@@ -1,5 +1,7 @@)
"coord-bg": HSL;
"coord-bg-opacity": Opacity;
}
```
**Current Values**:
```typescript
// Dark theme
syntax: {
comment: "215 20.2% 70%", // Medium gray
keyword: "210 40% 98%", // Bright
deleted: "0 70% 75%", // Light red
"deleted-bg": "0 70% 60%",
"deleted-bg-opacity": 0.1,
// ... etc
}
// Light theme (inverted lightness)
syntax: {
comment: "222 30% 35%", // Dark gray
keyword: "222 47% 11%", // Very dark
deleted: "0 70% 40%", // Dark red
"deleted-bg": "0 70% 60%",
"deleted-bg-opacity": 0.1,
// ... etc
}
```
**Usage**:
```css
.token.deleted {
color: hsl(var(--syntax-deleted));
background: hsl(var(--syntax-deleted-bg) / var(--syntax-deleted-bg-opacity));
}
```
---
### 4. Effects & Transparency
Visual effects like shadows, overlays, and opacity values.
**Structure**:
```typescript
effects: {
"scrollbar-opacity": Opacity; // Scrollbar thumb opacity
"scrollbar-hover-opacity": Opacity; // Hover state
"overlay-opacity": Opacity; // Modal/fullscreen overlays
"preview-opacity": Opacity; // Mosaic drag preview
"shadow-color": HSL; // Shadow base color
"shadow-blur": CSSLength; // Shadow blur radius
}
```
**Current Values** (theme-agnostic):
```typescript
effects: {
"scrollbar-opacity": 0.2,
"scrollbar-hover-opacity": 0.3,
"overlay-opacity": 0.92,
"preview-opacity": 0.3,
"shadow-color": "0 0% 0%", // Black for shadows
"shadow-blur": "40px",
}
```
**Usage**:
```css
*::-webkit-scrollbar-thumb {
background-color: hsl(var(--foreground) / var(--scrollbar-opacity));
}
*::-webkit-scrollbar-thumb:hover {
background-color: hsl(var(--foreground) / var(--scrollbar-hover-opacity));
}
[data-rmiz-modal-overlay] {
background-color: hsl(var(--background) / var(--overlay-opacity)) !important;
}
```
---
### 5. Spacing & Sizing
Layout dimensions and component sizes.
**Structure**:
```typescript
spacing: {
"toolbar-height": CSSLength; // Mosaic window toolbar
"split-width": CSSLength; // Window split handle
"scrollbar-width": CSSLength; // Scrollbar thickness
}
```
**Current Values** (theme-agnostic):
```typescript
spacing: {
"toolbar-height": "30px",
"split-width": "4px",
"scrollbar-width": "8px",
}
```
**Usage**:
```css
.mosaic-window .mosaic-window-toolbar {
height: var(--toolbar-height);
}
.mosaic-split.-row {
width: var(--split-width);
}
```
---
### 6. Typography
Font families, sizes, and line heights.
**Structure**:
```typescript
typography: {
"font-family-mono": string; // Monospace font stack
"font-size-base": CSSLength; // Base text size
"font-size-code": CSSLength; // Code block text size
"line-height-base": string; // Base line height
"line-height-code": string; // Code block line height
}
```
**Current Values** (theme-agnostic):
```typescript
typography: {
"font-family-mono": "'Oxygen Mono', monospace",
"font-size-base": "1rem",
"font-size-code": "0.75rem",
"line-height-base": "1.5",
"line-height-code": "1.5",
}
```
**Usage**:
```css
body {
font-family: var(--font-mono);
font-size: var(--font-size-base);
line-height: var(--line-height-base);
}
code {
font-size: var(--font-size-code);
line-height: var(--line-height-code);
}
```
---
### 7. Geometry
Border radius and shape properties.
**Structure**:
```typescript
geometry: {
radius: CSSLength; // Standard border radius
}
```
**Current Values** (theme-agnostic):
```typescript
geometry: {
radius: "0.5rem", // 8px at default font size
}
```
**Usage**:
```css
.button {
border-radius: var(--radius);
}
/* Derived values */
.card {
border-radius: calc(var(--radius) - 2px); /* Slightly smaller */
}
```
---
### 8. Charts (Optional)
Data visualization color palette.
**Structure**:
```typescript
charts: {
1: HSL;
2: HSL;
3: HSL;
4: HSL;
5: HSL;
}
```
**Current Values**:
```typescript
// Dark theme
charts: {
1: "220 70% 50%", // Blue
2: "160 60% 45%", // Green
3: "30 80% 55%", // Orange
4: "280 65% 60%", // Purple
5: "340 75% 55%", // Pink
}
// Light theme (adjusted)
charts: {
1: "220 70% 45%",
2: "160 60% 40%",
3: "30 80% 50%",
4: "280 65% 50%",
5: "340 75% 50%",
}
```
---
## TypeScript Schema
Complete type definitions for theme system:
```typescript
// src/types/theme.ts
/**
* HSL color format: "hue saturation% lightness%"
* Example: "270 100% 70%"
* Note: No hsl() wrapper - used as: hsl(var(--token))
*/
export type HSL = string;
/**
* Opacity value between 0 and 1
*/
export type Opacity = number;
/**
* CSS length value (px, rem, em, etc.)
*/
export type CSSLength = string;
/**
* Complete Grimoire theme definition
*/
export interface GrimoireTheme {
/** Unique identifier */
id: string;
/** Display name */
name: string;
/** Base type for contrast calculations */
type: "light" | "dark";
/** Optional metadata */
author?: string;
description?: string;
version?: string;
/** Color tokens */
colors: {
background: HSL;
foreground: HSL;
card: HSL;
"card-foreground": HSL;
popover: HSL;
"popover-foreground": HSL;
primary: HSL;
"primary-foreground": HSL;
secondary: HSL;
"secondary-foreground": HSL;
muted: HSL;
"muted-foreground": HSL;
accent: HSL;
"accent-foreground": HSL;
destructive: HSL;
"destructive-foreground": HSL;
border: HSL;
input: HSL;
ring: HSL;
};
/** Gradient definitions */
gradients: {
brand: [HSL, HSL, HSL, HSL];
};
/** Syntax highlighting */
syntax: {
comment: HSL;
keyword: HSL;
string: HSL;
function: HSL;
number: HSL;
operator: HSL;
"operator-opacity"?: Opacity;
deleted: HSL;
"deleted-bg": HSL;
"deleted-bg-opacity": Opacity;
inserted: HSL;
"inserted-bg": HSL;
"inserted-bg-opacity": Opacity;
coord: HSL;
"coord-bg": HSL;
"coord-bg-opacity": Opacity;
};
/** Visual effects */
effects: {
"scrollbar-opacity": Opacity;
"scrollbar-hover-opacity": Opacity;
"overlay-opacity": Opacity;
"preview-opacity": Opacity;
"shadow-color": HSL;
"shadow-blur": CSSLength;
};
/** Spacing & sizing */
spacing: {
"toolbar-height": CSSLength;
"split-width": CSSLength;
"scrollbar-width": CSSLength;
};
/** Typography */
typography: {
"font-family-mono": string;
"font-size-base": CSSLength;
"font-size-code": CSSLength;
"line-height-base": string;
"line-height-code": string;
};
/** Geometry */
geometry: {
radius: CSSLength;
};
}
/**
* Chart colors (optional, separate for flexibility)
*/
export interface ChartColors {
1: HSL;
2: HSL;
3: HSL;
4: HSL;
5: HSL;
}
/**
* Complete theme with chart colors
*/
export interface GrimoireThemeComplete extends GrimoireTheme {
charts: ChartColors;
}
```
---
## Usage Guidelines
### HSL Format Requirements
**Correct Format**:
```typescript
"270 100% 70%" // Basic color
"270 100% 70% / 0.5" // With inline opacity
```
**❌ Wrong**:
```typescript
"hsl(270 100% 70%)" // Don't wrap in hsl()
"270, 100%, 70%" // Don't use commas
"#B388FF" // Don't use hex
"rgb(179, 136, 255)" // Don't use RGB
```
**Rationale**: CSS variables need unwrapped values for flexible composition:
```css
/* ✅ This works */
color: hsl(var(--accent));
background: hsl(var(--accent) / 0.1);
/* ❌ This doesn't */
color: var(--accent); /* Missing hsl() */
```
### Token Naming Conventions
1. **Semantic over Visual**:
-`accent` (semantic: highlight/emphasis)
-`purple` (visual: describes appearance)
2. **Purpose over Position**:
-`card-foreground` (purpose: text on cards)
-`text-2` (position: arbitrary numbering)
3. **Component-Specific when Needed**:
-`toolbar-height` (specific to toolbars)
-`height-1` (generic, unclear usage)
### CSS Variable Usage
**Colors**:
```css
/* ✅ Correct */
color: hsl(var(--foreground));
background: hsl(var(--background));
border: 1px solid hsl(var(--border));
/* With opacity */
background: hsl(var(--accent) / 0.1);
color: hsl(var(--foreground) / var(--scrollbar-opacity));
/* ❌ Wrong */
color: var(--foreground); /* Missing hsl() */
background: hsl(var(--background), 0.9); /* Wrong opacity syntax */
```
**Gradients**:
```css
/* ✅ Correct */
background: linear-gradient(
to bottom,
hsl(var(--gradient-brand-1)),
hsl(var(--gradient-brand-2)),
hsl(var(--gradient-brand-3)),
hsl(var(--gradient-brand-4))
);
/* ❌ Wrong */
background: var(--gradient-brand); /* No single gradient variable exists */
```
**Spacing & Sizing**:
```css
/* ✅ Correct - direct usage */
height: var(--toolbar-height);
width: var(--split-width);
/* ✅ Correct - with calc */
padding: calc(var(--toolbar-height) / 2);
```
### Contrast Requirements
**WCAG AA Standards** (minimum):
- **Normal text** (<18pt): 4.5:1 contrast ratio
- **Large text** (≥18pt or bold ≥14pt): 3:1 contrast ratio
- **UI components**: 3:1 contrast ratio
**Testing**:
```typescript
import { calculateContrast } from "@/lib/theme-utils";
// Check contrast
const ratio = calculateContrast(
theme.colors.foreground,
theme.colors.background
);
if (ratio < 4.5) {
console.warn("Insufficient contrast for normal text");
}
```
**Common Fixes**:
- Light themes: Darken accent colors (50% instead of 70% lightness)
- Dark themes: Lighten accent colors (70% instead of 50% lightness)
- Always test with actual text, not just theory
---
## Theme Creation Workflow
### 1. Start from Existing Theme
```typescript
import { GRIMOIRE_DARK } from "@/lib/themes/grimoire-dark";
const MY_THEME: GrimoireThemeComplete = {
...GRIMOIRE_DARK, // Start with dark theme
id: "my-custom-theme",
name: "My Custom Theme",
// Override specific tokens...
};
```
### 2. Modify Colors
Focus on semantic tokens first:
```typescript
colors: {
...GRIMOIRE_DARK.colors,
background: "210 30% 10%", // Slightly different blue
accent: "150 80% 60%", // Green accent instead of purple
}
```
### 3. Adjust Syntax Highlighting
Match your color scheme:
```typescript
syntax: {
...GRIMOIRE_DARK.syntax,
keyword: "150 80% 60%", // Green keywords to match accent
deleted: "0 80% 70%", // Brighter red
}
```
### 4. Update Gradients
Keep brand consistency or create new:
```typescript
gradients: {
brand: [
"150 80% 60%", // Green
"180 70% 50%", // Cyan
"210 60% 50%", // Blue
"240 70% 60%", // Purple
],
}
```
### 5. Validate Theme
```typescript
import { validateTheme } from "@/lib/theme-utils";
const validation = validateTheme(MY_THEME);
if (!validation.valid) {
console.error("Theme validation failed:", validation.errors);
}
if (validation.warnings.length > 0) {
console.warn("Theme warnings:", validation.warnings);
}
```
### 6. Test Visually
- Load theme in browser
- Check all UI components
- Test with real content
- Verify contrast with browser DevTools
- Test in different screen sizes
### 7. Export & Share
```typescript
import { exportTheme } from "@/lib/theme-utils";
const json = exportTheme(MY_THEME);
// Save to file or share with others
```
---
## File Structure
```
src/
├── types/
│ └── theme.ts TypeScript interfaces
├── lib/
│ ├── themes/
│ │ ├── index.ts Theme registry & utilities
│ │ ├── grimoire-dark.ts Dark theme definition (const)
│ │ └── grimoire-light.ts Light theme definition (const)
│ │
│ └── theme-utils.ts Utilities (validate, convert, etc.)
├── index.css CSS variables (all tokens)
└── styles/
└── prism-theme.css Syntax highlighting styles
```
---
## Implementation Phases
### Phase 1: Type System ✅
- [x] Create `src/types/theme.ts`
- [x] Define all interfaces
- [x] Document token types
### Phase 2: Theme Definitions
- [ ] Create `src/lib/themes/grimoire-dark.ts`
- [ ] Create `src/lib/themes/grimoire-light.ts`
- [ ] Create `src/lib/themes/index.ts` (registry)
- [ ] Add complete token values for both themes
### Phase 3: CSS Migration
- [ ] Add all tokens to `:root` in `src/index.css`
- [ ] Add all tokens to `.dark` in `src/index.css`
- [ ] Replace hardcoded colors with token references
- [ ] Update `src/styles/prism-theme.css` to use syntax tokens
- [ ] Update gradient usage in components
### Phase 4: Utilities
- [ ] Implement `themeToCSSVariables()` in `src/lib/theme-utils.ts`
- [ ] Implement `applyTheme()` for dynamic theme switching
- [ ] Implement `validateTheme()` with contrast checking
- [ ] Implement `exportTheme()` / `importTheme()` for sharing
- [ ] Implement `calculateContrast()` (WCAG compliance)
### Phase 5: Testing
- [ ] Unit tests for validation functions
- [ ] Unit tests for conversion utilities
- [ ] Visual testing in both themes
- [ ] Contrast testing with automated tools
- [ ] Cross-browser compatibility testing
---
## Benefits of This System
1. **Complete Abstraction**: All visual properties tokenized, no hardcoded values
2. **Type Safety**: TypeScript enforces token structure and catches errors
3. **Validation**: Automated checks for completeness and contrast
4. **Extensibility**: Easy to add new themes (just define tokens)
5. **Portability**: Import/export themes as JSON
6. **Maintainability**: Single source of truth for visual properties
7. **Consistency**: Enforced visual coherence across all components
8. **Accessibility**: Built-in contrast validation (WCAG compliance)
9. **Future-Proof**: Architecture supports user-defined themes
10. **Developer Experience**: IntelliSense, autocomplete, documentation built-in
---
## Next Steps
1. **Review this design** - Confirm token structure meets requirements
2. **Approve naming conventions** - Ensure token names are clear and semantic
3. **Begin Phase 2** - Create TypeScript theme definition files
4. **Validate with real data** - Test token system with actual component usage
5. **Iterate** - Refine token structure based on implementation feedback
---
## References
- **WCAG 2.1 Guidelines**: https://www.w3.org/WAI/WCAG21/Understanding/
- **Design Tokens W3C Community**: https://design-tokens.github.io/community-group/
- **HSL Color Model**: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
- **CSS Custom Properties**: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
- **Tailwind Color System**: https://tailwindcss.com/docs/customizing-colors
- **Radix Themes**: https://www.radix-ui.com/themes/docs/theme/overview
---
**Document Version**: 1.0
**Created**: 2025-12-15
**Author**: Claude (ultrathink analysis)
**Status**: Design Complete - Ready for Implementation