diff --git a/docs/architecture.md b/docs/architecture.md index ba685d4..94dfe8e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -315,15 +315,23 @@ A fifth theming axis, and the only one that is a **class** (`.win7` on ``) rather than a `data-*` attribute — `7.css/dist/7.scoped.css` is precompiled against a literal `.win7`, so the name is not ours to pick. Default `modern` = class absent, matching the delete-when-default rule. -`SettingsService.applySkin` owns the class once the page is live; -`buildPreload` writes it for the first paint. +`buildPreload` is the **only** writer of that class, ever — there is +deliberately no `SettingsService.applySkin`. -Unlike the other four axes, this one is not only CSS: it selects a whole -component tree (see "UI layout"). So a skin change is **two-phase** — -`applySkin` flips the CSS immediately, but the tree and the native frame are -both fixed at window construction (`main.ts` reads the preload-baked -`__APP_SKIN`; `titleBarStyle`/`transparent` are `BrowserWindow` constructor -options). The options row carries the reopen hint as its tooltip. +**Unlike the other four axes, this one is launch-time only.** It selects a +whole component tree (see "UI layout") as well as CSS, and neither half can +change on a live window: the tree is bootstrapped once from the preload-baked +`__APP_SKIN`, and `titleBarStyle`/`transparent` are `BrowserWindow` constructor +options with no setters. Clicking a skin therefore only persists it; the +options row shows the saved value as pending (`skinPending()` compares +`settings.skin()` against `APP_SKIN`) and the running UI is untouched until the +next app start. + +The bun side pins this: `initSessionSkin` freezes the skin at startup, before +any window exists, and both `buildPreload` and `chromeOptions` read that pinned +value rather than the live settings snapshot. Otherwise an editor or manager +opened after a pending change would boot the *new* tree and frame while the +main window still ran the old one. **Stylesheet split.** `ui/src/styles.css` holds only what BOTH skins consume — the `@layer` statement, the Tailwind import, OKLCH tokens, `@theme inline`, @@ -427,9 +435,9 @@ without decorations (custom titlebar)" (verified on GNOME/Wayland), so the frameless Aero chrome is not a mac/win-only feature. The webview then draws the whole frame via `ui/src/app/skins/7like/title-bar/title-bar.ts` (7.css's `.title-bar` > `.title-bar-text` + `.title-bar-controls`, buttons keyed by `aria-label`), -mounted by all three window roots. Because `titleBarStyle` is fixed at -construction, **a skin change only reaches the frame on the next window open**; -the CSS half flips live, and the options row says so. `IS_WIN7_CHROME` in +mounted by all three of that skin's window roots. Because `titleBarStyle` is +fixed at construction, **a skin change only reaches the frame on the next app +start** — and nothing about the skin flips live, deliberately. `IS_WIN7_CHROME` in `platform.ts` reads the preload-baked `__APP_SKIN` (settings resolve too late for layout) and forces `IS_MAC_CHROME` false, since there are no traffic lights to reserve `pl-24` for. diff --git a/docs/gotchas.md b/docs/gotchas.md index a7289f1..74a2b20 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -201,10 +201,30 @@ touching the adjacent code. The win7 skin adds a **fourth value to keep in sync**: `buildPreload` also bakes the `.win7` class, and index.html carries a matching `html.win7` arm for all four theme states. Miss it and every win7 window flashes white. -- **`titleBarStyle` is construction-time only.** Switching skin cannot - re-frame a live window; `chromeOptions` is read once per `new - BrowserWindow`. The options row tells the user to reopen. Don't "fix" this - by recreating the main window — that would drop every session and tab. +- **The skin is a LAUNCH-TIME choice. Never apply one to a running window.** + This shipped broken once: `SettingsService.applySkin` toggled the `.win7` + class the moment the setting changed, which was harmless when there was one + component tree and became a broken window as soon as there were two — 7.css + painted onto shadlike markup that has no `.window.glass`, no `.title-bar`, no + `menu[role=tablist]` and no `