logicaffeine_web/ui/theme.rs
1//! Design token system for consistent styling.
2//!
3//! Centralizes all visual design constants—colors, typography, spacing, and
4//! border radii—as Rust constants. These tokens ensure visual consistency
5//! across all components.
6//!
7//! # Philosophy
8//!
9//! Design tokens are the single source of truth for styling:
10//! - **Colors**: Brand palette, semantic colors, syntax highlighting
11//! - **Typography**: Font sizes optimized for accessibility (+2px base)
12//! - **Spacing**: Consistent rhythm for margins and padding
13//! - **Radii**: Border radius scale from sharp to fully rounded
14//!
15//! # Usage
16//!
17//! Import tokens directly or use CSS custom properties:
18//!
19//! ```no_run
20//! # use dioxus::prelude::*;
21//! use logicaffeine_web::ui::theme::{self, colors, font_size, spacing};
22//!
23//! // Direct constant usage
24//! let style = format!("color: {}; font-size: {};", colors::PRIMARY_BLUE, font_size::BODY_LG);
25//!
26//! // Or inject CSS variables and use var(--name)
27//! let vars = theme::css_variables();
28//! # fn Example() -> Element {
29//! # let vars = theme::css_variables();
30//! rsx! {
31//! style { "{vars}" }
32//! div { style: "color: var(--color-primary-blue);", "Hello" }
33//! }
34//! # }
35//! ```
36//!
37//! # Accessibility
38//!
39//! All font sizes have been increased by 2px from typical values to improve
40//! readability. Text colors use sufficient contrast ratios against dark
41//! backgrounds.
42
43// =============================================================================
44// COLORS
45// =============================================================================
46
47/// Color palette for the application.
48///
49/// Organized into categories:
50/// - Primary/accent: Brand identity colors
51/// - Semantic: Success, warning, error, info
52/// - Gamification: XP, combos, achievements
53/// - Syntax: Code highlighting colors
54/// - Text: Accessible text color scale
55/// - Background/Border: Surface colors
56pub mod colors {
57 // Primary palette - Modern tech aesthetic
58 pub const PRIMARY_BLUE: &str = "#00d4ff";
59 pub const PRIMARY_PURPLE: &str = "#818cf8";
60 pub const ACCENT_BLUE: &str = "#22d3ee";
61 pub const ACCENT_PURPLE: &str = "#a78bfa";
62
63 // Semantic colors
64 pub const SUCCESS: &str = "#22c55e";
65 pub const WARNING: &str = "#f59e0b";
66 pub const ERROR: &str = "#ef4444";
67 pub const INFO: &str = "#00d4ff";
68
69 // Achievement/gamification colors
70 pub const XP_GREEN: &str = "#4ade80";
71 pub const COMBO_ORANGE: &str = "#f97316";
72 pub const COMBO_LIGHT: &str = "#fb923c";
73 pub const ACHIEVEMENT_GOLD: &str = "#fbbf24";
74
75 // Syntax highlighting colors
76 pub const SYNTAX_QUANTIFIER: &str = "#c678dd";
77 pub const SYNTAX_VARIABLE: &str = "#61afef";
78 pub const SYNTAX_PREDICATE: &str = "#98c379";
79 pub const SYNTAX_CONSTANT: &str = "#e5c07b";
80 pub const SYNTAX_DETERMINER: &str = "#56b6c2";
81 pub const SYNTAX_CONNECTIVE: &str = "#c678dd";
82
83 // Text colors - MUCH lighter for readability
84 pub const TEXT_PRIMARY: &str = "#f5f5f5";
85 pub const TEXT_SECONDARY: &str = "#d0d0d0";
86 pub const TEXT_TERTIARY: &str = "#b8b8b8";
87 pub const TEXT_MUTED: &str = "#c0c0c0";
88 pub const TEXT_PLACEHOLDER: &str = "#a0a0a0";
89
90 // Text with opacity (for overlays/backgrounds) - higher opacity for readability
91 pub const TEXT_HIGH_CONTRAST: &str = "rgba(245,245,245,0.98)";
92 pub const TEXT_MEDIUM: &str = "rgba(245,245,245,0.88)";
93 pub const TEXT_LOW: &str = "rgba(245,245,245,0.78)";
94 pub const TEXT_SUBTLE: &str = "rgba(245,245,245,0.68)";
95 pub const TEXT_VERY_SUBTLE: &str = "rgba(245,245,245,0.58)";
96
97 // Background colors
98 pub const BG_DARK: &str = "#060814";
99 pub const BG_OVERLAY_DARK: &str = "rgba(0,0,0,0.8)";
100 pub const BG_OVERLAY_LIGHT: &str = "rgba(0,0,0,0.25)";
101 pub const BG_SUBTLE: &str = "rgba(255,255,255,0.08)";
102 pub const BG_VERY_SUBTLE: &str = "rgba(255,255,255,0.04)";
103 pub const BG_HOVER: &str = "rgba(255,255,255,0.1)";
104
105 // Border colors
106 pub const BORDER_SUBTLE: &str = "rgba(255,255,255,0.1)";
107 pub const BORDER_MEDIUM: &str = "rgba(255,255,255,0.2)";
108}
109
110// =============================================================================
111// TYPOGRAPHY
112// =============================================================================
113
114/// Font size scale.
115///
116/// Minimum 14px for all text to ensure readability.
117/// Organized from display (largest) to caption (smallest).
118pub mod font_size {
119 // Display sizes
120 pub const DISPLAY_XL: &str = "66px";
121 pub const DISPLAY_LG: &str = "50px";
122 pub const DISPLAY_MD: &str = "34px";
123
124 // Heading sizes
125 pub const HEADING_LG: &str = "26px";
126 pub const HEADING_MD: &str = "22px";
127 pub const HEADING_SM: &str = "20px";
128
129 // Body sizes
130 pub const BODY_LG: &str = "18px";
131 pub const BODY_MD: &str = "16px";
132 pub const BODY_SM: &str = "15px";
133
134 // Caption sizes - minimum 14px for readability
135 pub const CAPTION_LG: &str = "15px";
136 pub const CAPTION_MD: &str = "14px";
137 pub const CAPTION_SM: &str = "14px";
138}
139
140/// Font family stacks with fallbacks.
141///
142/// - `MONO`: Code and logic expressions
143/// - `MONO_SYSTEM`: System monospace (better kerning)
144/// - `SANS`: UI text and prose
145pub mod font_family {
146 /// Primary monospace for code editing.
147 pub const MONO: &str = "'SF Mono', 'Fira Code', 'Consolas', monospace";
148 /// System monospace with better native rendering.
149 pub const MONO_SYSTEM: &str = "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, 'Cascadia Code', monospace";
150 /// System sans-serif for UI text.
151 pub const SANS: &str = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif";
152}
153
154// =============================================================================
155// SPACING
156// =============================================================================
157
158/// Spacing scale for consistent rhythm.
159///
160/// Use these for padding, margin, and gap values:
161/// - `XS` (4px): Tight spacing within components
162/// - `SM` (8px): Default component padding
163/// - `MD` (12px): Medium gaps
164/// - `LG` (16px): Section spacing
165/// - `XL` (24px): Large section gaps
166/// - `XXL` (32px): Page-level spacing
167pub mod spacing {
168 pub const XS: &str = "4px";
169 pub const SM: &str = "8px";
170 pub const MD: &str = "12px";
171 pub const LG: &str = "16px";
172 pub const XL: &str = "24px";
173 pub const XXL: &str = "32px";
174}
175
176// =============================================================================
177// BORDER RADIUS
178// =============================================================================
179
180/// Border radius scale.
181///
182/// - `SM`: Subtle rounding for inputs
183/// - `MD`: Default button/card rounding
184/// - `LG`: Prominent card rounding
185/// - `XL`: Modal/dialog rounding
186/// - `FULL`: Pill shapes and circles
187pub mod radius {
188 /// Subtle rounding (4px).
189 pub const SM: &str = "4px";
190 /// Default rounding (8px).
191 pub const MD: &str = "8px";
192 /// Prominent rounding (12px).
193 pub const LG: &str = "12px";
194 /// Large rounding (16px).
195 pub const XL: &str = "16px";
196 /// Fully rounded (pill shape).
197 pub const FULL: &str = "9999px";
198}
199
200// =============================================================================
201// CSS VARIABLE INJECTION
202// =============================================================================
203
204/// Returns a CSS block that defines all theme variables as CSS custom properties.
205/// Include this in your root component to make variables available everywhere.
206pub fn css_variables() -> &'static str {
207 r#"
208 :root {
209 /* Primary colors - Modern tech aesthetic */
210 --color-primary-blue: #00d4ff;
211 --color-primary-purple: #818cf8;
212 --color-accent-blue: #22d3ee;
213 --color-accent-purple: #a78bfa;
214
215 /* Semantic colors */
216 --color-success: #22c55e;
217 --color-warning: #f59e0b;
218 --color-error: #ef4444;
219 --color-info: #00d4ff;
220
221 /* Text colors - MUCH lighter for readability */
222 --text-primary: #f5f5f5;
223 --text-secondary: #d0d0d0;
224 --text-tertiary: #b8b8b8;
225 --text-muted: #c0c0c0;
226 --text-placeholder: #a0a0a0;
227
228 /* Font sizes - minimum 14px for readability */
229 --font-display-xl: 66px;
230 --font-display-lg: 50px;
231 --font-display-md: 34px;
232 --font-heading-lg: 26px;
233 --font-heading-md: 22px;
234 --font-heading-sm: 20px;
235 --font-body-lg: 18px;
236 --font-body-md: 16px;
237 --font-body-sm: 15px;
238 --font-caption-lg: 15px;
239 --font-caption-md: 14px;
240 --font-caption-sm: 14px;
241
242 /* Font families */
243 --font-mono: 'SF Mono', 'Fira Code', 'Consolas', monospace;
244 --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
245
246 /* Spacing */
247 --spacing-xs: 4px;
248 --spacing-sm: 8px;
249 --spacing-md: 12px;
250 --spacing-lg: 16px;
251 --spacing-xl: 24px;
252 --spacing-xxl: 32px;
253
254 /* Border radius */
255 --radius-sm: 4px;
256 --radius-md: 8px;
257 --radius-lg: 12px;
258 --radius-xl: 16px;
259 --radius-full: 9999px;
260
261 /* Theme defaults (Mountain - Cutting-edge tech) */
262 --bg-gradient-start: #09090b;
263 --bg-gradient-mid: #0c0c10;
264 --bg-gradient-end: #09090b;
265 --accent-primary: #00d4ff;
266 --accent-secondary: #818cf8;
267 --accent-tertiary: #f0f0f0;
268 --accent-primary-rgb: 0, 212, 255;
269 --accent-secondary-rgb: 129, 140, 248;
270 }
271 "#
272}