From 4fef7e44ed1e0b3efecf213560a6c420c2a930db Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 27 Oct 2026 23:23:34 +0100 Subject: [PATCH 1/5] refactor: boot module replaces ready, PSA/merch/no-CSS become state + components (L6) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01NZNRfGDYsGYMUTp2zYUTrv --- docs/specs/solid-monkeytype/roadmap.md | 10 +- .../components/core/NoCssDetails.spec.tsx | 51 +++++++++ frontend/__tests__/root/boot.spec.ts | 48 ++++++++ frontend/src/html/warnings.html | 106 +++++++++--------- frontend/src/ts/{ready.ts => boot.ts} | 21 ++-- frontend/src/ts/components/core/App.tsx | 15 ++- .../src/ts/components/core/NoCssDetails.tsx | 93 +++++++++++++++ frontend/src/ts/elements/no-css.ts | 97 ---------------- frontend/src/ts/elements/psa.tsx | 13 ++- frontend/src/ts/index.tsx | 6 +- frontend/src/ts/states/connection.ts | 5 +- frontend/src/ts/states/core.ts | 2 +- 12 files changed, 293 insertions(+), 174 deletions(-) create mode 100644 frontend/__tests__/components/core/NoCssDetails.spec.tsx create mode 100644 frontend/__tests__/root/boot.spec.ts rename frontend/src/ts/{ready.ts => boot.ts} (75%) create mode 100644 frontend/src/ts/components/core/NoCssDetails.tsx delete mode 100644 frontend/src/ts/elements/no-css.ts diff --git a/docs/specs/solid-monkeytype/roadmap.md b/docs/specs/solid-monkeytype/roadmap.md index 0d9d88404a8d..89456e8f9fa8 100644 --- a/docs/specs/solid-monkeytype/roadmap.md +++ b/docs/specs/solid-monkeytype/roadmap.md @@ -110,7 +110,7 @@ Serial; each step needs the previous one. Verify each in the browser (`__mt.chec |---|---|---|---|---|---| | [ ] | U1 | L · PR | Single-row user collection with `getUser()` and named writes (direct writes for server-side effects, optimistic actions for user changes, incl. quote ratings); convert **all writers** (result save, xp, badges, inbox count, lb memory, streak offset, quote rate, favourite quotes, edit profile, update name, unlink Discord, Discord OAuth, auth); delete the reactive mirror; `DB.getSnapshot()` becomes a read-only shim over the row | none | Writers must move in the same PR: there's no mutable object left | | [ ] | U2 | M · PR | Activity calendar: plain activity data in the user row; the calendar becomes a Solid component; delete the imperative test-activity modules | U1 (data shape) | Can share a PR with U1 | -| [ ] | U3 | M · PR | Remove the snapshot-updated auth event (PSA, last-signed-out-result modal read `getUser()`); auth becomes a signal the router reads, with the user-data load as state (loading/loaded/failed) plus `reloadUserData()` replacing the event's promise; delete the auth bus | U1 | | +| [ ] | U3 | M · PR | Remove the snapshot-updated auth event (PSA, last-signed-out-result modal read `getUser()`); PSA's `authEvent` subscription (`Psa.init`, started by boot) follows the auth signal; auth becomes a signal the router reads, with the user-data load as state (loading/loaded/failed) plus `reloadUserData()` replacing the event's promise; delete the auth bus | U1 | | | [ ] | U4 | S · commit per area | Readers move from the `DB.getSnapshot()` shim to `getUser()`, by area; the last PR deletes the shim and the snapshot code in `db.ts` | U1 | Parallel by area | | [ ] | U5 | M · PR | Tags, presets and custom themes get the `getUser()` pattern: plain getters backed by a module-level reactive mirror, replacing their live-query hooks (keep `gcTime: Infinity`). Rewrite the non-test `__nonReactive` callers as Solid code reading the getters: commandline tag/preset lists, the custom-themes check in config metadata, the tag PB helpers in `db.ts` (or they go with U4) | none | Test-page callers go with T6a/T6c | | [ ] | U6 | S · commit | Delete `__nonReactive` from every module once no caller is left | U5, T6a, T6c | Pure deletion: a caller still left means a step missed it | @@ -130,10 +130,10 @@ Serial; each step needs the previous one. Verify each in the browser (`__mt.chec |---|---|---|---|---| | [x] | L1 | M · PR | Focus mode becomes a signal; layout binds focus state; cursor hiding goes to CSS; one component owns the mouse-move exit. Done in [#8519](https://github.com/monkeytypegame/monkeytype/pull/8519): `isFocusMode`/`setFocusMode` (rAF-deferred) in states/test; `data-focused` on app, header, footer, banners; `FocusModeExit`; caret blink follows the signal; `test/focus.ts` deleted | none (before T5) | | [x] | L2 | L · PR | Funbox component owns funbox document state (body state, stylesheet link, CRT scanline); funbox functions stop touching the DOM and become engine plugin hooks, getting input as arguments instead of importing the EventLog; display tweaks via `data-ui-*` / funbox CSS. Done in [#8522](https://github.com/monkeytypegame/monkeytype/pull/8522): `components/core/Funbox.tsx` in App derives `fb-*`/`ignore-reduced-motion` and per-funbox links from `getAppliedFunboxes()` (set by `activate()` after validation, cleared by `clear()`), crt (`crtmode`, `#scanline`, global link) from `config.funbox` unless screenshotting; selectors unchanged; body classes via the `useBodyClasses` hook (Theme's `darkMode` and DevOptionsModal's debug classes moved too). `applyGlobalCSS`/`clearGlobal` and funbox's config-event subscriber deleted; crt loses `hasCssFile` (was loaded twice). Safari ≤16.5 crt check → `getFunboxUnsupportedReason` (metadata `isBlocked`, `toggleFunbox` setter, `activate()`). `handleKeydown`/`handleSpace` get a `FunboxInput` (`current()`, `forWord(i)`) from input instead of importing `events/data`. Hook shape left for T6a | none (before T5) | -| [ ] | L3 | M · PR | Monkey power as a component owning its canvas, positioned from the caret | T3 | +| [ ] | L3 | M · PR | Monkey power as a component owning its canvas, positioned from the caret; replaces App's `MonkeyPower.init` on mount (L6 stopgap) | T3 | | [ ] | L4 | M · PR | Result word highlight becomes part of words history, driven by a highlighted-range signal from the chart | none | -| [ ] | L5 | M · PR | Screenshot-mode signal; elements hide through state; capture uses the result ref | none | -| [ ] | L6 | M · PR | Boot cleanup: the ready module goes into App lifecycle / a boot module; PSA, merch banner and no-CSS detection become state plus components | none | +| [ ] | L5 | M · PR | Screenshot-mode signal; elements hide through state (incl. the static `#nocss` box); capture uses the result ref | none | +| [x] | L6 | M · PR | Boot cleanup: the ready module goes into App lifecycle / a boot module; PSA, merch banner and no-CSS detection become state plus components. Done: DOM-free `boot.ts` (called after render) awaits config then auth, sets app ready, shows merch banner, syncs server config, registers the service worker, and starts connection listeners (`initConnection`, was `onDOMReady`) and PSA (`Psa.init`, still on the auth bus until U3); App owns the body transition (effect on app ready) and calls `MonkeyPower.init` on mount until L3; `NoCssDetails` portals into empty mount points of the static `#nocss` box (`