mcpField
M
makepad-2.0-theme

makepad-2.0-theme

github.com/zhanghandongデザイン・UI75252 回インストール29 週間前に更新
リポジトリ

makepad-2.0-theme について

Splash スクリプトの `theme.*` 変数から利用できる、Makepad 2.0 アプリ向けのデザイントークンシステムです。ダーク、ライト、スケルトンのテーマと、色・タイポグラフィ・間隔・ウィジェット状態のトークンを備えています。

主な機能

  1. 01ダーク、ライト、スケルトンのテーマ
  2. 02色とウィジェット状態のトークン
  3. 03フォントスタイルとサイズ変数
  4. 04間隔と寸法のプリセット
  5. 05調整可能なテーマ共通パラメーター

活用シーン

  1. 01アプリ全体の色、フォント、間隔の統一
  2. 02アプリのダークテーマとライトテーマの切り替え

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zhanghandong/makepad-skills --skill makepad-2.0-theme

インストール後、Claude Code で/makepad-2.0-themeを入力して読み込まれたか確認します。

同梱ファイルreferences/theme-variables.md

詳細

Makepad 2.0 テーマシステム

概要

Makepad 2.0 のテーマシステムでは、Splash スクリプト内の theme.* 変数から利用できる、包括的なデザイントークン一式を提供します。アプリケーション全体で、色、タイポグラフィ、余白、ウィジェットの状態に一貫性のあるスタイルを適用できます。

組み込みテーマは 3 種類あります。

  • mod.themes.dark -- ダークデスクトップテーマ(デフォルト)
  • mod.themes.light -- ライトデスクトップテーマ
  • mod.themes.skeleton -- 値がハードコードされた最小限のスケルトンテーマ

最も重要なルール:本番環境の UI で色、フォントサイズ、余白を指定する際は、ハードコードされた値ではなく、必ず theme.* 変数を使用してください。これにより、アプリでテーマを自動的に切り替えられるようになり、視覚的な一貫性も保たれます。

App::run でのテーマ設定

ウィジェットを読み込む前にテーマを読み込む必要があります。標準的なパターンは次のとおりです。

impl App {
    fn run(vm: &mut ScriptVm) -> Self {
        // Step 1: Load theme definitions (dark, light, skeleton)
        crate::makepad_widgets::theme_mod(vm);

        // Step 2: Select active theme (MUST come before widgets_mod)
        script_eval!(vm, {
            mod.theme = mod.themes.light  // or mod.themes.dark
        });

        // Step 3: Load widget definitions (they reference mod.theme)
        crate::makepad_widgets::widgets_mod(vm);

        // Step 4: Load your app's script_mod
        App::from_script_mod(vm, self::script_mod)
    }
}

手順 1~2 を省略すると、デフォルトのテーマはダークになります(theme_mod 内で設定されています)。 カウンターの例では、手順 1~3 とデフォルトのダークテーマをまとめた簡略版の 1 行 crate::makepad_widgets::script_mod(vm) を使用しています。

内部での仕組み

theme_mod() は次の処理を行います。

  1. makepad_draw::script_mod(vm) を呼び出して、描画プリミティブを読み込みます
  2. mod.themes モジュールを作成します
  3. theme_desktop_dark、theme_desktop_light、theme_desktop_skeleton を読み込みます
  4. デフォルトとして mod.theme = mod.themes.dark を設定します

続いて widgets_mod() が theme: mod.theme を含む mod.prelude.widgets_internal を作成し、use mod.prelude.widgets.* を使用するすべてのウィジェットスクリプトで theme.* を利用できるようにします。

テーマのグローバルパラメーター

各テーマでは、全体的な印象を調整するグローバルパラメーターを定義します。

ParameterPurposeDefault (dark/light)
color_contrastカラーパレットの広がりを調整します1.0
color_tint背景に適用する色合い#0000ff
color_tint_amount色合いの適用量(0~1)0.0
space_factor基本となる余白の倍率6.0
corner_radius基本となる角の半径2.5
beveling面取りの強さ0.75
font_size_base基本フォントサイズ(px)10.0
font_size_contrastサイズ段階間のフォントサイズの差2.5

テーマの色変数 -- プライマリ

アプリケーションコードで最もよく使用する色です。

VariablePurposeLight AppearanceDark Appearance
theme.color_bg_appアプリの背景ライトグレー(約 #DDD)ダークグレー(約 #333)
theme.color_fg_app前景レイヤーやや暗めやや明るめ
theme.color_bg_containerカード/コンテナーの背景半透明の明色半透明の暗色
theme.color_bg_even偶数行の背景より明るいより暗い
theme.color_bg_odd奇数行の背景より暗いより明るい
theme.color_bg_highlightハイライトの背景白に近い #FFFFFF22不透明度の低い白に近い色
theme.color_bg_highlight_inlineインラインのハイライトcolor_d_1color_d_3
theme.color_bg_unfocussedフォーカスのないハイライトbg_highlight の 85%bg_highlight の 85%
theme.color_app_caption_barキャプションバーの背景透明透明
theme.color_white純白#FFFFFF#FFFFFF
theme.color_makepadMakepad ブランドカラー#FF5C39#FF5C39

テーマカラー変数 -- テキストとラベル

変数用途
theme.color_label_inner内側の要素(ボタン、ラベル)の主要テキスト
theme.color_label_inner_hoverホバー時のテキスト
theme.color_label_inner_down押下時のテキスト
theme.color_label_inner_focusフォーカス時のテキスト
theme.color_label_inner_activeアクティブ/選択時のテキスト
theme.color_label_inner_inactiveセカンダリ/控えめなテキスト
theme.color_label_inner_disabled無効時のテキスト
theme.color_label_outer外側の要素(タブ、ヘッダー)の主要テキスト
theme.color_label_outer_offオフ時の外側テキスト
theme.color_label_outer_disabled無効時の外側テキスト
theme.color_text一般的なテキストの色
theme.color_text_hoverホバー時のテキスト
theme.color_text_focusフォーカス時のテキスト
theme.color_text_disabled無効時のテキスト
theme.color_text_placeholderプレースホルダーテキスト
theme.color_text_metaメタデータのテキスト
theme.color_text_cursorテキストカーソルの色

テーマカラー変数 -- ウィジェットの状態

アウトセットカラー(ボタン、隆起した要素):

変数用途
theme.color_outsetデフォルトのボタン背景
theme.color_outset_hoverホバー時のボタン
theme.color_outset_down押下時のボタン
theme.color_outset_activeアクティブなトグル状態
theme.color_outset_focusフォーカスされたボタン
theme.color_outset_disabled無効なボタン
theme.color_outset_inactive非アクティブなボタン

インセットカラー(テキスト入力、チェックボックス、ラジオボタン):

変数用途
theme.color_insetデフォルトの入力背景
theme.color_inset_hoverホバー時の入力
theme.color_inset_focusフォーカス時の入力
theme.color_inset_disabled無効な入力
theme.color_inset_empty空の入力

選択とハイライト:

変数用途
theme.color_selection_focusテキスト選択のハイライト
theme.color_selection_hoverホバー時の選択
theme.color_highlight一般的なアクセント/ハイライト
theme.color_cursorカーソルの色
theme.color_cursor_focusフォーカス時のカーソル

テーマカラー変数 -- セマンティック/ステータス

変数用途値
theme.color_errorエラー状態赤(#C00)
theme.color_warning警告状態オレンジ(#FA0)
theme.color_high重大度:高赤(#C00)
theme.color_mid重大度:中オレンジ(#FA0)
theme.color_low重大度:低黄緑(#8A0)
theme.color_panicパニック/重大マゼンタ(#f0f)

テーマカラー変数 -- ベベルシステム

テーマには、3D風のウィジェット効果を実現する多層ベベルシステムがあります。

グループ変数用途
color_bevel*_hover、_focus、_active、_down、_disabledフラットベベル
color_bevel_inset_1*同じ接尾辞内側の影(レイヤー1)
color_bevel_inset_2*同じ接尾辞内側のハイライト(レイヤー2)
color_bevel_outset_1*同じ接尾辞外側のハイライト(レイヤー1)
color_bevel_outset_2*同じ接尾辞外側の影(レイヤー2)

テーマカラー変数 -- その他のウィジェットカラー

変数グループ用途
theme.color_icon*アイコンの色(デフォルト、非アクティブ、アクティブ、無効)
theme.color_mark*チェックマーク/ラジオマークの色
theme.color_val*プログレスバーとスライダーの塗りつぶし色
theme.color_handle*スライダーハンドルの色
theme.color_shadow*影の効果
theme.color_drag_quadドラッグプレビューのオーバーレイ
theme.color_dock_tab_activeアクティブなドックタブの背景

テーマフォント変数

フォントサイズ

フォントサイズは、font_size_base と font_size_contrast から算出されます。

変数計算式デフォルト値
theme.font_size_1base + 8 * contrast30.0(最大の見出し)
theme.font_size_2base + 4 * contrast20.0(中サイズの見出し)
theme.font_size_3base + 2 * contrast15.0(小サイズの見出し)
theme.font_size_4base + 1 * contrast12.5(小見出し)
theme.font_size_pbase10.0(本文)
theme.font_size_code固定9.0(等幅コード)
フォントスタイル(TextStyle オブジェクト)
変数説明フォントファイル
theme.font_regular標準ウェイトの本文テキストIBMPlexSans-Text.ttf
theme.font_bold太字/セミボールドのテキストIBMPlexSans-SemiBold.ttf
theme.font_italicイタリック体のテキストIBMPlexSans-Italic.ttf
theme.font_bold_italic太字のイタリック体テキストIBMPlexSans-BoldItalic.ttf
theme.font_code等幅コード用フォントLiberationMono-Regular.ttf
theme.font_labelラベルテキスト(レガシー)IBMPlexSans-Text.ttf
theme.font_iconsアイコンフォント(FontAwesome)fa-solid-900.ttf

各フォントスタイルは、複数言語をサポートしています。

  • ラテン文字:IBM Plex Sans ファミリー
  • 中国語:LXGW WenKai ファミリー
  • 絵文字:Noto Color Emoji
行間定数
変数値用途
theme.font_wdgt_line_spacing1.2ウィジェットのテキスト
theme.font_hl_line_spacing1.05見出しのテキスト
theme.font_longform_line_spacing1.2長文テキスト

テーマの間隔変数

基本の間隔

間隔は space_factor(デフォルトは 6.0)から算出されます。

変数計算式デフォルト値
theme.space_10.5 * space_factor3.0(極小)
theme.space_21.0 * space_factor6.0(小/標準)
theme.space_31.5 * space_factor9.0(中)
マージン/パディングのプリセット(Inset オブジェクト)

全辺のプリセット:

変数説明値
theme.mspace_1全辺の XS パディング各辺 3px
theme.mspace_2全辺の SM パディング各辺 6px
theme.mspace_3全辺の MD パディング各辺 9px

水平方向のみのプリセット:

変数説明値
theme.mspace_h_1水平方向の XS パディング左/右:3px、上/下:0
theme.mspace_h_2水平方向の SM パディング左/右:6px、上/下:0
theme.mspace_h_3水平方向の MD パディング左/右:9px、上/下:0

垂直方向のみのプリセット:

変数説明値
theme.mspace_v_1垂直方向の XS パディング上/下:3px、左/右:0
theme.mspace_v_2垂直方向の SM パディング上/下:6px、左/右:0
theme.mspace_v_3垂直方向の MD パディング上/下:9px、左/右:0
寸法変数
変数用途デフォルト
theme.data_item_height標準データ行の高さ約23px
theme.data_icon_width標準アイコンの幅約16px
theme.data_icon_height標準アイコンの高さ約22px
theme.container_corner_radiusコンテナの角丸半径5.0
theme.textselection_corner_radiusテキスト選択範囲の角丸半径1.25
theme.tab_heightタブバーの高さ36.0

Splash でのテーマ変数の使用

色
// Background color
draw_bg.color: theme.color_bg_container

// Text color
draw_text.color: theme.color_label_inner

// Muted/secondary text
draw_text.color: theme.color_label_inner_inactive

// Color math -- multiply for opacity
draw_text.color: theme.color_label_inner_inactive * 0.8

// Semantic colors
draw_bg.color: theme.color_warning
draw_bg.color: theme.color_error
フォントサイズ
// Body text size
draw_text.text_style.font_size: theme.font_size_p

// Heading sizes
draw_text.text_style.font_size: theme.font_size_1   // Largest
draw_text.text_style.font_size: theme.font_size_2   // Medium
draw_text.text_style.font_size: theme.font_size_3   // Small
draw_text.text_style.font_size: theme.font_size_4   // Sub-heading

// Code font size
draw_text.text_style.font_size: theme.font_size_code
フォントスタイル
// Bold text with custom size (override with {} syntax)
draw_text.text_style: theme.font_bold{font_size: theme.font_size_2}

// Bold text keeping default size
draw_text.text_style: theme.font_bold{}

// Code font
draw_text.text_style: theme.font_code{}

// Override font size using +: merge syntax
draw_text +: {text_style +: {font_size: theme.font_size_3}}
間隔
// Uniform padding
padding: theme.mspace_2

// Padding with overrides
padding: theme.mspace_2{left: theme.space_3, right: theme.space_3}

// Horizontal-only padding with custom values
padding: theme.mspace_h_1{left: theme.space_2, right: theme.space_2}

// Spacing between children
spacing: theme.space_2

// Computed spacing
width: Fill height: 9. * theme.space_1
padding: theme.mspace_3{left: theme.space_3 * 2, right: theme.space_3 * 2}

色の構文リファレンス

Splash は、複数の色形式に対応しています(テーマ固有ではありませんが、重要です)。

構文例説明
#RGB#f00短縮形式の16進数(赤)
#RRGGBB#ff0000完全形式の16進数
#RRGGBBAA#ff000080アルファ値付きの16進数
#xRRGGBB#x2ecc71e で始まる16進数(接頭辞 #x)
#N#Dグレースケールの短縮表記
vec4(r,g,b,a)vec4(1.0, 0.0, 0.0, 1.0)RGBA 浮動小数点数(0.0-1.0)
theme.*theme.color_highlightテーマ変数

重要:16進数の色が文字 e で始まる場合は、科学表記との曖昧さを避けるために #x 接頭辞を使用してください。たとえば、#2ecc71 ではなく #x2ecc71 を使用します。

色の計算に対応しています:

// Multiply for opacity
theme.color_label_inner_inactive * 0.8

// Mix two colors
mix(theme.color_w, theme.color_b, 0.5)

実行時のテーマ切り替え

Rust のイベントハンドラー内で、動的にテーマを切り替えられます:

impl MatchEvent for App {
    fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
        if self.ui.button(cx, ids!(toggle_theme)).clicked(actions) {
            script_eval!(cx, {
                mod.theme = mod.themes.dark  // or mod.themes.light
            });
            // All widgets using theme.* will pick up new values
            // You may need to trigger a re-render
        }
    }
}

または、ウィジェットの読み込み前に(App::run 内で)切り替えて、テーマを固定できます:

fn run(vm: &mut ScriptVm) -> Self {
    crate::makepad_widgets::theme_mod(vm);
    script_eval!(vm, {
        mod.theme = mod.themes.light
    });
    crate::makepad_widgets::widgets_mod(vm);
    App::from_script_mod(vm, self::script_mod)
}

テーマ対応 UI の完全な例

この例では、テーマ変数のみを使ったテーマ対応のカードリストを示します:

script_mod! {
    use mod.prelude.widgets.*

    let CardItem = RoundedView{
        width: Fill height: Fit
        padding: theme.mspace_2{left: theme.space_3, right: theme.space_3}
        flow: Right spacing: theme.space_2
        align: Align{y: 0.5}
        draw_bg.color: theme.color_bg_container
        draw_bg.border_radius: theme.container_corner_radius

        icon := Label{
            width: 24 height: 24
            text: ""
        }
        content := View{
            width: Fill height: Fit
            flow: Down spacing: theme.space_1
            title := Label{
                text: "Title"
                draw_text.color: theme.color_label_inner
                draw_text.text_style: theme.font_bold{font_size: theme.font_size_4}
            }
            subtitle := Label{
                text: "Subtitle"
                draw_text.color: theme.color_label_inner_inactive
                draw_text.text_style.font_size: theme.font_size_p
            }
        }
        badge := RoundedView{
            width: Fit height: Fit
            padding: theme.mspace_h_1
            draw_bg.color: theme.color_bg_highlight_inline
            draw_bg.border_radius: 4.0
            badge_label := Label{
                text: "new"
                draw_text.color: theme.color_highlight
                draw_text.text_style.font_size: theme.font_size_code
                draw_text.text_style: theme.font_bold{}
            }
        }
    }

    startup() do #(App::script_component(vm)){
        ui: Root{
            main_window := Window{
                pass.clear_color: theme.color_bg_app
                window.inner_size: vec2(400, 600)
                body +: {
                    width: Fill height: Fill
                    flow: Down spacing: 0

                    // Header
                    SolidView{
                        width: Fill height: Fit
                        padding: theme.mspace_3
                        draw_bg.color: theme.color_app_caption_bar
                        Label{
                            text: "My Cards"
                            draw_text.color: theme.color_label_inner
                            draw_text.text_style: theme.font_bold{font_size: theme.font_size_2}
                        }
                    }

                    // Card list
                    ScrollYView{
                        width: Fill height: Fill
                        padding: theme.mspace_2
                        flow: Down spacing: theme.space_1
                        CardItem{title.text: "First Card" subtitle.text: "Description here"}
                        CardItem{title.text: "Second Card" subtitle.text: "Another card"}
                    }

                    // Footer
                    SolidView{
                        width: Fill height: Fit
                        padding: theme.mspace_2
                        draw_bg.color: theme.color_bg_container
                        Label{
                            text: "2 items"
                            draw_text.color: theme.color_label_inner_inactive
                            draw_text.text_style.font_size: theme.font_size_code
                        }
                    }
                }
            }
        }
    }
}

ベストプラクティス

  1. 本番アプリでは必ず色に theme.* を使用してください — theme.color_error がある場合は、#ff0000 をハードコードしないでください。これにより、テーマの切り替えとアクセシビリティに対応できます。

  2. 一貫したタイポグラフィのためにテーマフォントを使用してください — フォントファミリーを手動で指定するよりも、theme.font_bold{font_size: theme.font_size_2} を優先してください。

  3. 一貫したレイアウトのためにテーマの間隔を使用してください — theme.mspace_2 と theme.space_2 により、調和の取れたリズムを作れます。padding: Inset{top: 8, ...} のようなマジックナンバーは避けてください。

  4. {} 構文でオーバーライドしてください — テーマの値を置き換えずに拡張できます: theme.font_bold{font_size: 20} は太字フォントのファミリーを維持しつつ、サイズをオーバーライドします。 theme.mspace_2{left: theme.space_3} は上・右・下を維持しつつ、左をオーバーライドします。

  5. 部分的なオーバーライドには +: マージを使用してください — ネストされたプロパティを1つだけ変更したい場合に使います:draw_text +: {text_style +: {font_size: theme.font_size_3}}

  6. 適切なテキスト色の変数を選択してください:

    • theme.color_label_inner は主要な UI テキスト(ボタン、ラベル)に使用します
    • theme.color_label_inner_inactive はセカンダリまたは控えめなテキストに使用します
    • theme.color_text は一般的なコンテンツテキストに使用します
    • theme.color_text_placeholder はプレースホルダーテキストに使用します
  7. 状態に対応した色のバリエーションを使用してください — ホバー・フォーカス・押下時に変化するウィジェットには、対応する _hover、_focus、_down の接尾辞を持つ変数を使用してください。

  8. 掛け算で控えめな不透明度にしてください — theme.color_label_inner_inactive * 0.8 を使うと、新しい変数を追加せずに、より控えめな色を作れます。

  9. widgets_mod より前にテーマを選択してください — ウィジェットの定義に正しいテーマ値を反映するには、theme_mod() と widgets_mod() の呼び出しの間でテーマを設定する必要があります。

  10. シンプルなアプリでは、crate::makepad_widgets::script_mod(vm) を使用してください。これにより、デフォルトのダークテーマですべてを一度に読み込みます。

ソースファイル

  • ダークテーマ:widgets/src/theme_desktop_dark.rs
  • ライトテーマ:widgets/src/theme_desktop_light.rs
  • テーマのひな形:widgets/src/theme_desktop_skeleton.rs
  • テーマローダー:widgets/src/lib.rs(theme_mod 関数と widgets_mod 関数)
  • 使用例:examples/todo/src/app.rs(テーマ変数を全面的に使用したライトテーマ)
  • 使用例:examples/counter/src/app.rs(デフォルトのダークテーマ)

コメント