docs(website): theming & navigation, complete (edge → main) #109

Merged
whitlocktech merged 10 commits from edge into main 2026-08-08 06:09:08 +00:00
Member

Docs cutover, pairing RunicGateway/website#126. Merges edge into main now that every phase is built.

website/THEMING_AND_NAV.md is the design of record plus its as-built record: each phase carries an "as landed" section explaining where the build differed from the design and why. BACKEND_DESIGN.md documents the settings keys, the validation posture and the HTML-shell lifecycle; api-route-inventory.json mirrors the route manifest.

The parts of this doc most worth reading later, because they are the decisions someone will otherwise re-litigate:

  • §2 — absence of a row is what selects the default. Reset deletes; it never stores a copy of the defaults, which would stop tracking them.
  • §4.5 / phases 3–4 — the design put presets in CSS with a data-theme attribute, and that could not work: SiteContext writes --accent as an inline style, which beats any attribute selector. The theme is server-resolved instead, so brand.accent (what the Android app and Discord bot theme from) is by construction the accent the site actually paints.
  • §7 — the nav override layer is presentation, never authorization, and it was amended in phase 10 rather than quietly contradicted: coded entries still cannot introduce a route or touch a gate, while an admin-added link is a same-origin path that advertises a route and never grants one. The amendment says why the property is structural rather than a check someone must remember.
  • Phases 6–8 as landed — the server could not store a nav row at all (it would have written "[object Object]" and read it back as absent), and the server deliberately does not validate that a route exists: the base NAV arrays are client constants, so shape is the server's question and membership the client's. Do not "fix" that.
  • Phase 9, cancelled — with the live finding that motivated it kept intact, since it is a real rough edge in the dark presets rather than only a blocker for a light one.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Opus 5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.
Docs cutover, pairing RunicGateway/website#126. Merges `edge` into `main` now that every phase is built. `website/THEMING_AND_NAV.md` is the design of record **plus its as-built record**: each phase carries an "as landed" section explaining where the build differed from the design and why. `BACKEND_DESIGN.md` documents the settings keys, the validation posture and the HTML-shell lifecycle; `api-route-inventory.json` mirrors the route manifest. **The parts of this doc most worth reading later, because they are the decisions someone will otherwise re-litigate:** - **§2 — absence of a row is what selects the default.** Reset deletes; it never stores a copy of the defaults, which would stop tracking them. - **§4.5 / phases 3–4 —** the design put presets in CSS with a `data-theme` attribute, and that could not work: `SiteContext` writes `--accent` as an *inline* style, which beats any attribute selector. The theme is server-resolved instead, so `brand.accent` (what the Android app and Discord bot theme from) is by construction the accent the site actually paints. - **§7 — the nav override layer is presentation, never authorization**, and it was **amended in phase 10** rather than quietly contradicted: coded entries still cannot introduce a route or touch a gate, while an admin-added link is a same-origin path that *advertises* a route and never *grants* one. The amendment says why the property is structural rather than a check someone must remember. - **Phases 6–8 as landed —** the server could not store a nav row at all (it would have written `"[object Object]"` and read it back as absent), and the server deliberately does **not** validate that a route exists: the base NAV arrays are client constants, so shape is the server's question and membership the client's. Do not "fix" that. - **Phase 9, cancelled —** with the live finding that motivated it kept intact, since it is a real rough edge in the dark presets rather than only a blocker for a light one. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Opus 5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 10 commits 2026-08-08 06:08:46 +00:00
Matches RunicGateway/website's phases 0-2 of THEMING_AND_NAV.md.

BACKEND_DESIGN.md:
- The new /settings router group and its one route, plus why it is a fifth
  group rather than a route on an existing one.
- DELETE /admin/settings/:key in the admin route table, with the allowlist and
  why reset deletes instead of writing.
- The five unseeded theming/nav keys under the settings schema: absence of the
  row is the "use the default" state, values are TEXT so consumers parse, and
  malformed reads as absent.
- Route count 215 -> 225.

THEMING_AND_NAV.md:
- Phases 0-2 marked landed, with an "as landed" section recording the three
  things the design left open: where /settings/nav lives, where
  parseJsonSetting lives, and the exact 23-declaration radius promotion.
- The nav merge util's ordering rules, settled by the implementation: an
  untouched item keeps its index as its sort key, an explicit order wins a tie
  against a coincidental index, equal explicit orders keep code order, and
  `group` is honored only when it names an existing section.
- All four PR pairs target `edge`; the feature reaches `main` as one merge.

api-route-inventory.json: resynced from server/routes.manifest.json. Picks up
the two new routes plus eight that were already missing from the mirror since
the Protocol 3.0 cutover (shard clilocs, market, points).

Co-Authored-By: Claude <noreply@anthropic.com>
Reviewed-on: #104
Records where the build diverged from the design and why.

- The presets do not live in theme.css as [data-theme] blocks. Section 6.2 is
  marked superseded and a "Phases 3-4 as landed" section explains the inline
  --accent precedence problem that forced server-side resolution.
- Section 4.5's accentInt fix is struck through: getPublic() never exposed
  accentInt, and Discord embeds are colored by a separate process reading env,
  so there was nothing per-request to recompute. Replaced with what was
  actually done -- the bot fetching the effective accent.
- Phase 9 re-scoped. Applying Fantasy on a live instance showed the section 4.8
  rgba literals carry a hue, not just a light/dark assumption, so the dark
  presets need that promotion too.
- BACKEND_DESIGN.md: the new /settings/theme/options route, the `theme` block
  on /public/settings, effective values in the brand block, theme_visual
  validation on PUT /admin/settings, route count 225 -> 226.
- api-route-inventory.json regenerated from the manifest.

Co-Authored-By: Claude <noreply@anthropic.com>
Reviewed-on: #105
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
Records Phase 5 of THEMING_AND_NAV.md as landed and documents the new route
and the shell lifecycle in BACKEND_DESIGN.md.

Where the build differed from the design: the upload is one admin-only call
that writes the settings row too (rather than the generic staff upload plus a
PUT, which would leave unreferenced files and let editors change the site's
identity); brand_assets needed a validator of its own because these are the
only settings values written straight into HTML as URLs; the shell cache
carries a TTL as well as explicit invalidation because it is per process; and
the logo went into all six MoonDot surfaces rather than three.

Also notes what was deliberately left alone: the shell's title and description
still come from BRAND_NAME rather than the admin-set site_title, and fixing
that would change the served shell for instances with no brand_assets row —
which is exactly what the phase's acceptance criterion forbids.

Co-Authored-By: Claude <noreply@anthropic.com>
Reviewed-on: #106
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
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>
Reviewed-on: #107
Records the capability asked for before the edge -> main cutover: dropdown
sections in the public header, with the coded entries organised into them and
admin-authored links alongside.

§7 is amended rather than quietly contradicted. It said the override layer
"cannot introduce a `to` that is not already in the hardcoded NAV array"; that
remains true of every CODED entry, and the restated constraint spells out what an
added link may be — a same-origin path, carrying no gate of its own, advertising
a route rather than granting one — plus why the property is structural: coded
entries live in a map keyed by routes the base array declares, and everything
that can name an arbitrary path lives in `links`, where the rule is applied.

§6.4 gains the { items, sections, links } wrapper, including the two properties
worth knowing: a bare map still reads as the items map, and a nav with no
sections still stores one.

§9 gains three acceptance criteria — the empty dropdown does not render, an added
link cannot leave the origin, and deleting a section returns its entries to the
top level rather than removing them.

"Phase 10 as landed" records why the Public tab needed its own tree editor, why
moving between containers stayed a dropdown rather than a cross-container drag,
why the menu opens on click and its trigger is not a link, and the palette-vs-full-nav
bug this surfaced in the phase 6-8 save path.

Co-Authored-By: Claude <noreply@anthropic.com>
Reviewed-on: #108
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
whitlocktech merged commit 518f1e0449 into main 2026-08-08 06:09:08 +00:00
whitlocktech deleted branch edge 2026-08-08 06:09:08 +00:00
Sign in to join this conversation.
No description provided.