feat(quick-261016-0fm): manual theme switch on the rail

- the rail's top button cycles system, light and dark and names the
  current choice; light and dark ignore prefers-color-scheme
- usePreferences applies the cached theme before the first await of boot,
  saves the choice through PUT /account/preferences and reverts with a
  toast when the save fails; me() applies the stored preference
This commit is contained in:
Jakub Zych
2026-10-16 09:54:02 +02:00
parent 047858ae84
commit 21b0d39de0
7 changed files with 181 additions and 17 deletions

View File

@@ -35,6 +35,8 @@ A form whose schema carries `preview` has a read-only record screen at `<control
The user menu in the top bar has a My account item that opens `<prefix>/account`. That screen edits the signed-in administrator's own first name, last name, email and subtitle, uploads and removes their avatar, shows the login read-only, changes the password when a new one is typed together with the current one, and manages personal API tokens (list, create with a show-once plaintext, revoke, show revoked). Server validation errors show on their fields, and a successful save updates the name and the avatar in the top bar without a reload. See [My account](users-and-permissions.md#my-account) and [API tokens](users-and-permissions.md#api-tokens).
The button at the top of the plugin rail switches the theme: each click moves from system (follow the browser's `prefers-color-scheme`) to light, to dark and back to system, and its icon and label name the current choice. The choice is saved for the signed-in administrator through `PUT <prefix>/api/v1/account/preferences` and comes back as `preferences.theme` in `GET .../auth/me`, so another browser shows the same theme after sign-in. The SPA also caches the last choice in `localStorage` (`summer-admin.theme`) and applies it before anything renders. When the save fails the previous theme returns with an error message. See [My account](users-and-permissions.md#my-account).
## Types from OpenAPI
The admin API is described by swag annotations in cabana. `scripts/check-admin-openapi.sh` generates the OpenAPI document (`admin/openapi/admin.json`) from them and the SPA's TypeScript types (`admin/src/api/schema.d.ts`) from the document, so the SPA's API client is checked against the server's shapes at compile time. Type overrides for swag live in the root `.swaggo` (it documents `json.RawMessage` as an untyped value, which swag cannot resolve on its own). `--check` fails when either committed file is out of date: