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

153 lines
6.2 KiB
Markdown

# 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/`.