Skip to main content

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}