docs(website): theming phases 6-8 as built, and phase 9 cancelled
Marks the nav wiring and the builder UI landed, and records the five places the build differed from the design: - The server had no way to store a nav row. The design scoped 6-8 as client work, but updateSettings would have written a nav object as "[object Object]" — a save that 200s and does nothing, for ever. - The server deliberately cannot check that a `to` exists: the base NAV arrays are client constants, and a server-side copy would be a second source of truth for navigation. Shape is the server's question, membership the client's. - `hidden: false` is accepted and never stored, so hiding stays subtractive. - The nav editor cannot be hidden, enforced in three places. - Orders are written only when something actually moved, compared against the base restricted to the rows the editing admin can see. Phase 9 (hue-carrying rgba literals + Parchment) is cancelled rather than deferred. The finding that motivated it is kept as the record: those literals carry a hue, so they are a rough edge in the three dark presets and not only a blocker for a hypothetical light one. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -538,15 +538,16 @@ today until the admin acts.
|
||||
| **3 — Theme engine** ✅ | Three presets, the combined Google Fonts link, `SiteContext` extension, and the effective-value resolution in `getPublic().brand` (§4.5) |
|
||||
| **4 — Admin theme UI** ✅ | `/admin/appearance` view + route in `App.jsx` + `NAV`/`TITLES` entries in `AdminLayout.jsx` |
|
||||
| **5 — Brand assets** ✅ | Cached-shell rewrite in `app.js` (§4.3); upload endpoint on the existing multer config; `<img>` logo slot beside `MoonDot` in the shells; `heroImage` chain extension |
|
||||
| **6 — Public nav wiring** | `SiteHeader.jsx` → `nav_public`. Lowest risk of the three: no roles, no groups |
|
||||
| **7 — Nav builder UI** | `NavEditor.jsx` with `@dnd-kit` (new dependency), **Public tab only** |
|
||||
| **8 — Admin + Player nav** | Wire the remaining two layouts, add the remaining two tabs, once the public pattern is validated in use |
|
||||
| **9 — Palette-following literals + Parchment (optional)** | Promote the hue-carrying `rgba()` literals of §4.8 so they follow the palette (the **dark** presets need this too — see "Phases 3–4 as landed"), then the light-mode port with its own contrast pass across every component |
|
||||
| **6 — Public nav wiring** ✅ | `SiteHeader.jsx` → `nav_public`. Lowest risk of the three: no roles, no groups |
|
||||
| **7 — Nav builder UI** ✅ | `NavEditor.jsx` with `@dnd-kit` (new dependency), **Public tab only** |
|
||||
| **8 — Admin + Player nav** ✅ | Wire the remaining two layouts, add the remaining two tabs, once the public pattern is validated in use |
|
||||
| **9 — Palette-following literals + Parchment** ❌ **cancelled** | Was: promote the hue-carrying `rgba()` literals of §4.8 so they follow the palette, then the light-mode port. Not scheduled — see "Phase 9, cancelled" below |
|
||||
|
||||
Phases 0–2 are one PR pair (website + docs), 3–4 a second, 5 a third, 6–8 a
|
||||
fourth. **All four PR pairs target `edge`, not `main`** — the feature reaches
|
||||
`main` as one `edge` → `main` merge once every phase is in, so no release ever
|
||||
carries a half-wired theme engine.
|
||||
carries a half-wired theme engine. Phase 8 is the last one, so that merge is
|
||||
what closes the feature.
|
||||
|
||||
### Phases 0–2 as landed
|
||||
|
||||
@@ -756,6 +757,75 @@ admin panel still has the env name in its tab and its link previews. Fixing it
|
||||
would change the served shell for instances with no `brand_assets` row, which is
|
||||
exactly what §9 says must not change in this phase. It wants its own change.
|
||||
|
||||
### Phases 6–8 as landed
|
||||
|
||||
The nav half, wired end to end: the public header, the admin sidebar and the
|
||||
player portal all read their override row, and `/admin/navigation` writes them.
|
||||
Five things the design did not settle.
|
||||
|
||||
**1. The server had no way to store a nav row, and would have stored garbage.**
|
||||
§8 described phases 6–8 as client work, and for the *merge* that is right. But
|
||||
`updateSettings` validates and stringifies `theme_visual` and `brand_assets` and
|
||||
lets everything else through to `settingsDb.set` — so a `nav_public` object would
|
||||
have been written as the string `"[object Object]"`, which `parseJsonSetting`
|
||||
then reads as absent. The save would have returned 200 and done nothing, for
|
||||
ever. `server/src/utils/navOverrides.js` mirrors `utils/brandAssets.js`:
|
||||
`validateNavOverrides` is strict on write and names the offending key,
|
||||
`resolveNavOverrides` is forgiving and drops fields that would do nothing.
|
||||
|
||||
**2. The server cannot check that a `to` exists, and should not try.** The three
|
||||
base `NAV` arrays are client constants. Shipping a copy to the server would
|
||||
create a second source of truth for navigation that drifts the first time a route
|
||||
is added, and it would buy nothing: `applyNavOverrides` already drops an entry
|
||||
whose `to` the base array does not declare, which is the right place for it — a
|
||||
route deleted in code stops mattering immediately, with no migration. **The
|
||||
server validates shape; the client owns membership.** So the write path accepts
|
||||
any app-internal path as a key (absolute, no scheme, no `//host`, no whitespace)
|
||||
and rejects everything else, and it rejects any field that is not one of the
|
||||
four — a `roles` or `to` in the body is a 400, not something quietly stored.
|
||||
|
||||
**3. `hidden: false` is accepted and never stored.** The editor sends it while a
|
||||
row is being edited, so rejecting it would be hostile; storing it would leave a
|
||||
row that reads like an instruction to *force* something visible, which this layer
|
||||
must never be able to express. It is dropped on the way in, and hiding stays
|
||||
subtractive.
|
||||
|
||||
**4. The nav editor cannot be hidden, and that is enforced three times.** An
|
||||
admin who hid `/admin/navigation` would lose the only screen that can un-hide it.
|
||||
The row's eye toggle is disabled with a note saying why; `resolveNavOverrides`
|
||||
drops `hidden` on that one `to` for `nav_admin`; and `AdminLayout` strips it
|
||||
again before merging, which is what also covers a row edited straight in the
|
||||
database. Typing the URL still works regardless — the guard is about not
|
||||
stranding an admin who never learned it.
|
||||
|
||||
**5. Orders are written only when something actually moved.** §7.1 says the
|
||||
editor writes an order for every item "the way drag-and-drop does", and it does —
|
||||
but only for a nav whose sequence differs from the code's. An admin who renames
|
||||
one item stores exactly one field, and a route added to `NAV` later still lands
|
||||
where the code puts it. The comparison is against the base **restricted to the
|
||||
rows that admin can see**, so a role- or feature-gated item missing from their
|
||||
palette is not mistaken for a reorder. An override for such an item is carried
|
||||
through their save untouched rather than quietly reset.
|
||||
|
||||
Two smaller notes. The section dropdown offers "(no section)" only to rows coded
|
||||
into an untitled group (Dashboard, Account): for anything else it is a move an
|
||||
override cannot express (§6.4 allows an existing titled section or nothing), so
|
||||
offering it would silently do nothing. And `useNavOverrides` keeps one
|
||||
module-level copy of the two authenticated rows, which is what lets a save in the
|
||||
editor update the sidebar the admin is looking at without a reload — and stops
|
||||
the second layout to mount from flashing the coded nav first.
|
||||
|
||||
### Phase 9, cancelled
|
||||
|
||||
The §4.8 `rgba()` literal promotion and the Parchment light-mode port are **not
|
||||
scheduled**. The finding that motivated them stands and is worth keeping: those
|
||||
literals carry a *hue*, not merely a light/dark assumption — `.btn-ghost` is
|
||||
`rgba(11,22,48,0.45)`, so the portal quick-links read blue on Fantasy's warm
|
||||
page. It is a real rough edge in the three dark presets, not only a blocker for a
|
||||
hypothetical light one. It is simply not worth the contrast pass across every
|
||||
component right now. Anyone picking it up should start from the census in §4.8
|
||||
and the live observation in "Phases 3–4 as landed".
|
||||
|
||||
### 8.1 Admin builder UI notes
|
||||
|
||||
- Tabbed control for the three navs; drag-and-drop reorderable list.
|
||||
|
||||
Reference in New Issue
Block a user