# Changes & Rationale This document explains how the codebase was improved and why. Each item notes the original behavior, the change, and the reasoning. ## 1. Three-tier design-token architecture **Before:** Tokens were split across `streem_theme/colors.rs`, `streem_theme/shapes.rs`, `streem_theme/typography.rs` (writing into `mod.widgets.*`), while the actual themes lived in `streem_theme/mod.rs` (`mod.streem_theme.*`). The token files were also **not declared as Rust modules anywhere**, so they were effectively dead code that never ran. **After:** A clean 3-tier system: 1. `streem_design/{palette,shapes,typography}.rs` — tier-1 primitives. 2. `streem_theme/mod.rs` — tier-2 semantic themes that bind roles to primitives. 3. Widgets — read only the active theme (`s_themes`) / language (`s_i18n`). **Why:** This is the standard, scalable token model. Changing one palette entry re-brands everything; widgets never reference raw values. > **Registration note:** the tier-1 modules use `script_eval!` (runtime > mutation of the `mod` object), *not* the `script_mod!` macro form. The > `script_mod!` form returns a value to be applied to a component and does not > eagerly install a fresh top-level namespace like `mod.streem_design.*`, which > is exactly why the original `colors.rs`/`shapes.rs`/`typography.rs` (written > with `script_mod!` but never wired up) produced "`streem_design` not found" > errors. `script_eval!` installs the namespace immediately, matching the > working `streem_theme` / `streem_i18n` pattern. Inside `script_eval!` there is > no prelude `use`, so fonts are referenced by their fully-qualified path > (`mod.theme.font_bold`) rather than the bare `theme.font_bold` alias. ## 2. App-owned namespace (`mod.streem_design.*`) **Before:** Tokens were written into `mod.widgets.*`. **After:** All app tokens live under `mod.streem_design.*`. **Why:** `mod.widgets.*` is the framework's widget namespace; writing app tokens there is confusing and risks collisions. An app-owned namespace makes ownership explicit. ## 3. Themes reference palette primitives (single source of truth) **Before:** `streem_theme/mod.rs` inlined hex literals (`color_bg: #FFF7ED`, `color_primary: #D97706`, …), duplicating values and divorcing themes from any shared palette. **After:** Each theme role points at a palette token (`color_primary: mod.streem_design.palette.amber_600`). **Why:** One palette edit now propagates to every theme that uses it; the palette becomes the single source of truth. ## 4. Fixed the unused `color_text` role **Before:** Both themes defined `color_text`, but the UI never used it — body text relied on widget defaults (white), which is invisible on light surfaces. **After:** Semantic roles (`color_text`, `color_text_secondary`, `color_text_on_primary`) are explicitly applied to the title, subtitle, status, and section labels. **Why:** Per the Splash manual, default text color is white; light themes must set dark text explicitly or it disappears (white-on-white). ## 5. Live, data-driven status label **Before:** The DSL hard-coded `text: "Current: light | reapply: 0"`, a string that could drift out of sync with actual state. **After:** The label starts neutral and is always written from Rust state via `refresh_status` (`Current: {theme} / {lang} | reapply: {n}`), called on startup, on every toggle, and on live-edit. **Why:** A single source of truth prevents the displayed status from lying. ## 6. Generic theme cycling (no rigid 2-state enum) **Before:** A `ThemeState { Light, Dark }` enum with `toggled()` hard-coded the two-theme assumption. **After:** The host tracks `theme_idx` / `lang_idx` into ordered name lists (`THEMES`, `LANGS`) that mirror `theme_names` / `lang_names` in script. Toggling advances the index modulo the list length. **Why:** Adding a third theme (or third language) now requires no host changes to the cycling logic — just extend the lists. ## 7. Runtime language switching **Before:** i18n existed but was never wired to the UI, and it defaulted to Swahili (`s_i18n = sw`), which looked like a leftover. **After:** A **Language** button cycles `en`/`sw`; the active language is selected alongside the theme in the single `reapply` reload path. Default is now English. **Why:** Demonstrates that the same swap-and-reload mechanism localizes the UI, not just re-colors it. ## 8. Single reload path **Before:** `apply_theme` and `reload_ui_from_rust_state` overlapped and both re-applied the theme; the flow was easy to get out of sync. **After:** One `reapply(cx)` selects the active theme+language in the VM, reloads the script tree, refreshes the status label, and redraws. `handle_*` methods call it once when something changes. **Why:** Less duplication, clearer control flow, no double application. ## 9. Hardened `Event::LiveEdit` **Before:** On `LiveEdit`, the app called `apply_theme` (which re-evaluated the theme but could leave i18n/state inconsistent after a hot reload). **After:** On `LiveEdit`, the app re-selects the active theme *and* language in the VM and refreshes the status, so a hot reload preserves the user's current selection instead of reverting to script defaults. **Why:** Hot-reloading code shouldn't silently reset the user's theme/language. ## 10. Expanded, polished UI consuming the tokens **Before:** A minimal toggle + two markup cards with magic-number padding and inline `font_size` values. **After:** A header (title/subtitle), a control bar (themed buttons + live status), and two bordered surface cards — all driven by the spacing scale, typography styles, semantic colors, and `new_batch: true` on text-bearing backgrounds (per the Splash batching guidance, so text never hides behind its own background). **Why:** Shows the design system actually being consumed end-to-end and follows the documented layout/batching best practices. ## 11. Better tests **Before:** One test that checked the enum toggles back and forth. **After:** Tests cover full theme/language cycling and verify the modulo guards never index out of range. ## 12. Build ergonomics * `Cargo.toml` documents the expected sibling-of-Makepad layout for the path dependency and provides a commented, branch-pinned git fallback. * Added a `markup` feature (default on) for the Markdown/Html widgets. * Added `.gitignore` for `target/`.