$npx -y skills add ZhangHanDong/makepad-skills --skill makepad-2.0-themeCRITICAL: Use for Makepad 2.0 theme system. Triggers on: makepad theme, theme variable, theme color, theme font, theme spacing, dark mode, light mode, theme switching, mod.themes, theme_mod, theme.color_, theme.font_, theme.space_, theme.mspace_, 主题, 颜色, 字体, 暗色模式, 亮色模式, 主题切换, 样式
| 1 | # Makepad 2.0 Theme System |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | The Makepad 2.0 theme system provides a comprehensive set of design tokens accessed |
| 6 | through `theme.*` variables in Splash scripts. It delivers consistent styling for |
| 7 | colors, typography, spacing, and widget states across your entire application. |
| 8 | |
| 9 | Three built-in themes are available: |
| 10 | - `mod.themes.dark` -- dark desktop theme (default) |
| 11 | - `mod.themes.light` -- light desktop theme |
| 12 | - `mod.themes.skeleton` -- minimal skeleton theme with hardcoded values |
| 13 | |
| 14 | **Golden rule**: Always use `theme.*` variables instead of hardcoded values for any |
| 15 | color, font size, or spacing in production UIs. This ensures your app automatically |
| 16 | supports theme switching and maintains visual consistency. |
| 17 | |
| 18 | ## Theme Setup in App::run |
| 19 | |
| 20 | The theme must be loaded **before** widgets are loaded. The standard pattern is: |
| 21 | |
| 22 | ```rust |
| 23 | impl App { |
| 24 | fn run(vm: &mut ScriptVm) -> Self { |
| 25 | // Step 1: Load theme definitions (dark, light, skeleton) |
| 26 | crate::makepad_widgets::theme_mod(vm); |
| 27 | |
| 28 | // Step 2: Select active theme (MUST come before widgets_mod) |
| 29 | script_eval!(vm, { |
| 30 | mod.theme = mod.themes.light // or mod.themes.dark |
| 31 | }); |
| 32 | |
| 33 | // Step 3: Load widget definitions (they reference mod.theme) |
| 34 | crate::makepad_widgets::widgets_mod(vm); |
| 35 | |
| 36 | // Step 4: Load your app's script_mod |
| 37 | App::from_script_mod(vm, self::script_mod) |
| 38 | } |
| 39 | } |
| 40 | ``` |
| 41 | |
| 42 | If you skip steps 1-2, the default theme is dark (set inside `theme_mod`). |
| 43 | The counter example uses the simplified one-liner `crate::makepad_widgets::script_mod(vm)` |
| 44 | which bundles steps 1-3 with the default dark theme. |
| 45 | |
| 46 | ### How It Works Internally |
| 47 | |
| 48 | `theme_mod()` does the following: |
| 49 | 1. Calls `makepad_draw::script_mod(vm)` to load drawing primitives |
| 50 | 2. Creates the `mod.themes` module |
| 51 | 3. Loads `theme_desktop_dark`, `theme_desktop_light`, and `theme_desktop_skeleton` |
| 52 | 4. Sets `mod.theme = mod.themes.dark` as the default |
| 53 | |
| 54 | Then `widgets_mod()` creates `mod.prelude.widgets_internal` with `theme: mod.theme`, |
| 55 | making `theme.*` available in all widget scripts that `use mod.prelude.widgets.*`. |
| 56 | |
| 57 | ## Theme Global Parameters |
| 58 | |
| 59 | Each theme defines tunable global parameters that control the overall feel: |
| 60 | |
| 61 | | Parameter | Purpose | Default (dark/light) | |
| 62 | |-----------|---------|---------------------| |
| 63 | | `color_contrast` | Controls color palette spread | 1.0 | |
| 64 | | `color_tint` | Tint applied to backgrounds | `#0000ff` | |
| 65 | | `color_tint_amount` | How much tint to apply (0-1) | 0.0 | |
| 66 | | `space_factor` | Base spacing multiplier | 6.0 | |
| 67 | | `corner_radius` | Base corner radius | 2.5 | |
| 68 | | `beveling` | Bevel intensity | 0.75 | |
| 69 | | `font_size_base` | Base font size in px | 10.0 | |
| 70 | | `font_size_contrast` | Font size step between levels | 2.5 | |
| 71 | |
| 72 | ## Theme Color Variables -- Primary |
| 73 | |
| 74 | These are the colors you will use most often in application code: |
| 75 | |
| 76 | | Variable | Purpose | Light Appearance | Dark Appearance | |
| 77 | |----------|---------|-----------------|-----------------| |
| 78 | | `theme.color_bg_app` | App background | Light gray (~#DDD) | Dark gray (~#333) | |
| 79 | | `theme.color_fg_app` | Foreground layer | Slightly darker | Slightly lighter | |
| 80 | | `theme.color_bg_container` | Card/container bg | Semi-transparent light | Semi-transparent dark | |
| 81 | | `theme.color_bg_even` | Alternating row (even) | Lighter | Darker | |
| 82 | | `theme.color_bg_odd` | Alternating row (odd) | Darker | Lighter | |
| 83 | | `theme.color_bg_highlight` | Highlight background | White-ish `#FFFFFF22` | White-ish low opacity | |
| 84 | | `theme.color_bg_highlight_inline` | Inline highlight | `color_d_1` | `color_d_3` | |
| 85 | | `theme.color_bg_unfocussed` | Unfocused highlight | 85% of bg_highlight | 85% of bg_highlight | |
| 86 | | `theme.color_app_caption_bar` | Caption bar bg | Transparent | Transparent | |
| 87 | | `theme.color_white` | Pure white | `#FFFFFF` | `#FFFFFF` | |
| 88 | | `theme.color_makepad` | Makepad brand | `#FF5C39` | `#FF5C39` | |
| 89 | |
| 90 | ## Theme Color Variables -- Text and Labels |
| 91 | |
| 92 | | Variable | Purpose | |
| 93 | |----------|---------| |
| 94 | | `theme.color_label_inner` | Primary text on inner elements (buttons, labels) | |
| 95 | | `theme.color_label_inner_hover` | Text on hover | |
| 96 | | `theme.color_label_inner_down` | Text when pressed | |
| 97 | | `theme.color_label_inner_focus` | Text when focused | |
| 98 | | `theme.color_label_inner_active` | Text when active/selected | |
| 99 | | `theme.color_label_inner_inactive` | Secondary/muted text | |
| 100 | | `theme.color_label_inner_disabled` | Disabled text | |
| 101 | | `theme.color_label_outer` | Primary text on outer elements (tabs, headers) | |
| 102 | | `theme.color_label_outer_off` | Outer text when off | |
| 103 | | `theme.color_label_outer_disabled` | Disabled outer text | |
| 104 | | `theme.color_text` | General text color | |
| 105 | | `theme.color_text_hover` | Text on hover | |
| 106 | | `theme.color |