nigig-org/crates/apps/theming
nigig-ci 34fecf1924 build: pin every git dependency to a full 40-character SHA (Phase 0.2)
The repo has a CI gate requiring full-length revs, added deliberately in
5e71457 with a comment explaining that an abbreviated rev resolves only
while no other object shares its prefix -- a property of the repository's
current object count, not a guarantee. Git's abbreviation length grows as
a repo grows, so a short pin silently becomes ambiguous, and an attacker
able to push to the fork can try to manufacture a colliding prefix.

That gate has been failing. 42 declarations across 34 crates used
abbreviated revs:

    41x  rev = "ecf5a572"    (the current makepad pin)
     1x  rev = "5efe6e24c"   (map/tests/makepad_test_app, left behind
                              by the ce0eaae bump)

Resolved both against the remote and rewrote them:

    ecf5a572  -> ecf5a572ab62a1c1598909971f602f99083671cc
    5efe6e24c -> 5efe6e24c9f732e9f11b783757f196f4f1c402b2

Verified this changes the LABEL and not the dependency: Cargo.lock holds
exactly one makepad commit id and zero references to the old one, so
nothing was silently upgraded. The stray makepad_test_app pin did move to
the current rev, which is the intent -- it pointed at a stale branch head.

Cargo.lock also picks up unrelated churn (brotli et al in,
makepad-android-state/jni-sys out). That staleness is PRE-EXISTING, not
caused by this change: confirmed by stashing every edit and running
`cargo metadata` on a pristine tree, which produces the identical diff.

Gate now passes:
  $ grep -rn 'rev = ' --include=Cargo.toml . | grep -vE 'rev = "[0-9a-f]{40}"'
  (no output)
2026-08-16 18:35:39 +00:00
..
.github/workflows Initial commit 2026-07-26 19:38:26 +03:00
resources Initial commit 2026-07-26 19:38:26 +03:00
splash Initial commit 2026-07-26 19:38:26 +03:00
src Initial commit 2026-07-26 19:38:26 +03:00
.gitignore Initial commit 2026-07-26 19:38:26 +03:00
AGENTS.md Initial commit 2026-07-26 19:38:26 +03:00
Cargo.toml build: pin every git dependency to a full 40-character SHA (Phase 0.2) 2026-08-16 18:35:39 +00:00
CHANGES.md Initial commit 2026-07-26 19:38:26 +03:00
Justfile Initial commit 2026-07-26 19:38:26 +03:00
LICENSE Initial commit 2026-07-26 19:38:26 +03:00
README.md Initial commit 2026-07-26 19:38:26 +03:00

theming

A small Makepad example that demonstrates runtime theme and language swapping using the new script_mod! / Splash DSL (Makepad 2.0).

Click Toggle theme to cycle light/dark; click Language to cycle English/Kiswahili. The whole UI re-skins and re-localizes at runtime by swapping the active design token set and reloading the script tree — no per-widget edits required.


Token architecture (3 tiers)

This example follows a layered design-token system so that a single change propagates predictably across the whole UI:

Tier 1 — Primitives           Tier 2 — Semantic            Tier 3 — Widgets
(raw values, no meaning)      (roles bound per theme)      (read active theme)

mod.streem_design.palette  →  mod.streem_theme.light    →  draw_bg.color: color_bg
mod.streem_design.shapes   →  mod.streem_theme.dark      ↘ draw_text.text_style: h1
mod.streem_design.typography  mod.streem_theme.s_themes  ←  (the active theme)
  • Tier 1 — streem_design/
    • palette.rs — the only place raw hex colors live (amber_600, gray_900…).
    • shapes.rs — radii, control heights, a spacing scale, border widths.
    • typography.rs — named text styles (h1, body1, overline…).
  • Tier 2 — streem_theme/
    • mod.rslight / dark themes that map roles (color_bg, color_primary, color_text, status colors…) onto palette primitives. Widgets read everything through mod.streem_theme.s_themes.*.
  • Localization — streem_i18n/
    • mod.rsen / sw string tables; the active language is mod.streem_i18n.s_i18n (same swap pattern as themes).
  • Host — src/main.rs
    • Tracks the selected theme/language indices, points s_themes / s_i18n at the selection, reloads the script tree, and drives a live status label.

Why this matters: because semantic themes reference palette tokens, you can re-brand the entire app by editing one entry in palette.rs. Because widgets only ever read s_themes/s_i18n, the host can re-skin/re-localize the tree generically.


Project layout

theming/
├── Cargo.toml
└── src/
    ├── main.rs                  # host App: toggles + reload path
    ├── streem_design/
    │   ├── mod.rs               # registers tier-1 modules
    │   ├── palette.rs           # tier 1: raw colors
    │   ├── shapes.rs            # tier 1: radii / spacing / sizes
    │   └── typography.rs        # tier 1: text styles
    ├── streem_theme/
    │   └── mod.rs               # tier 2: semantic light/dark themes
    └── streem_i18n/
        └── mod.rs               # localized strings (en/sw)

Building & running

Studio-first workflow. Per the project runbook, UI programs should be launched and inspected through the Makepad Studio remote protocol via a runnable item, not via raw cargo run. Use the shell only for non-UI tasks (cargo check, cargo test, file/search ops), and prefer --release for any performance-sensitive run.

Dependency setup

Cargo.toml uses a local path dependency on makepad-widgets, which assumes this crate sits as a sibling of your Makepad checkout:

makepad/            # your makepad checkout (the new DSL lives on `dev`)
  widgets/
<projects>/
  theming/          # this crate  →  path = "../../../../makepad/widgets"

Adjust the number of ../ segments in Cargo.toml to match where you place this crate. If you are not inside a Makepad checkout, uncomment the git dependency in Cargo.toml instead (pinned to branch = "dev").

Non-UI checks (shell is fine)

cargo check          # type-check
cargo test           # runs the unit tests in src/main.rs
cargo build --release

Running the UI (via Studio)

  1. Start the Studio remote bridge once.
  2. Add theming to the Cargo workspace and makepad.splash so Studio exposes it as a runnable item.
  3. Launch it with RunItem (the runnable item name shown in Studio).
  4. After editing UI/runtime code, ClearBuild the old build and re-run before trusting screenshots or widget dumps.

What changed vs. the original

See CHANGES.md for the full list. Highlights:

  • Introduced the 3-tier token system and an app-owned mod.streem_design.* namespace (was mod.widgets.*, which collides conceptually with the framework's own widget namespace).
  • Themes now reference palette primitives instead of inlining hex.
  • Fixed the unused color_text role and removed dead/duplicated token files.
  • Status text is now driven entirely by live Rust state (no baked-in "light | reapply: 0" string in the DSL).
  • Added a generic, index-based theme/language cycle (replacing the rigid 2-state enum) plus runtime language switching wired through one reload path.
  • Hardened Event::LiveEdit so a hot-reload re-applies the active selection instead of silently reverting to script defaults.