nigig-org/crates/apps/theming/README.md
2026-07-26 19:38:26 +03:00

129 lines
4.9 KiB
Markdown

# 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.rs``light` / `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.rs``en` / `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)
```bash
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`](./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.