docs(website): add theming & nav build contract #103
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/theming-and-nav-plan"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What & why
Adds
docs/website/THEMING_AND_NAV.md— the design of record for admin-configurable theming, brand assets and navigation, plus its index row inREADME.md.This takes the draft spec (Spec: Admin-Configurable Theming & Navigation), audits it against the current
website/tree, and turns it into a build contract in the same shape asHERO_EDITOR.md: locked decisions → corrections to current-code reality → phased build → acceptance criteria. Docs only — nowebsite/code is touched. PerCLAUDE.md, implementation waits on approval of this document.Blocking gaps found in the draft spec
These would each have stopped implementation partway:
settings.db.jsexposesget/getAll/set/seedDefaultonly, and the admin API isPUT /admin/settingstaking a key/value object. Every "Reset to defaults" in the feature — an acceptance criterion in the draft — depends on deleting a row. NeedssettingsDb.remove()+DELETE /admin/settings/:key.nav_admin/nav_player"fetched by the authenticatedAdminLayout/PlayerPortalLayout", butGET /admin/settingsis gatedrequireRole('admin')while those layouts render for editors, moderators and players. Needs a newGET /settings/navbehindisLoggedIn.renderIndexHtmlruns once at boot, not per request (app.js:207). Overriding the templated logo/favicon is a lifecycle change (cached shell + invalidation), not theawaitthe draft implies.TEXT, not objects. JSON keys are stored stringified and parsed client-side; the draft'ssettings.brand_assets?.heroreads as if they arrive parsed.getPublic().brandis a cross-repo contract.publicBrand.test.jslocks its field list and the Android app seeds its whole Material theme frombrand.accent;brand.accentIntcolors Discord embeds. New keys would have left the phone app and the bot on the old accent.Decisions locked in this doc
getPublic().brand(override → env), so Android and Discord track admin theming with no client change.accentIntrecomputes per request.spacingUnitandborderWeightare cut, not deferred —theme.csshas zerocalc()spacings and 39 hand-written1pxborders (several semantic), so they are ~40-declaration refactors, not variable promotions.--radius-card: 8pxwould have restyled.card/.panel(10px) and.panel-flat(12px) on every existing instance, contradicting its own byte-for-byte criterion.rgba()literals plus hero overlays in five files ported, which no[data-theme]block reaches.css2?request. Arial maps onto today's--sansso it costs no webfont; IM Fell English has no bold and will faux-bold at 600–700.MIME_EXThas no.icoentry, and deriving the stored extension from that map is precisely what makes the upload path safe.Smaller notes captured
The hero already has a third override layer (
hero_layout.background.image_urlbeatsbrand.hero); the footer "powered by" badge must not followbrand_assets.logo; nav renames don't reach the portal hero's quick-links; the nav editor must refuse to hide its own entry; CSP already allows both Google Fonts hosts so no policy change is needed.How it was tested
Docs only — nothing to build or run. Every claim about current behavior was verified by reading the source, and the doc cites
file:linefor each. Spot checks behind the numbers:theme.css: 14×8px, 4×999px, 4×10px, 1×12px, 1×7px, 1×6px.1pxborders; 5calc()uses, all page-shell widths; 28rgba()literals.brand.logohas zero client consumers; the header/sidebar logo slot isMoonDot.jsx, a CSS span.getPublic()(settings.model.js:130-141) already emitsaccent/logo/hero/favicon, andpublicBrand.test.js:30asserts on all four.BrandDto+MainActivity.kt:72confirm the app themes frombrand.accent.Checklist
AI-assisted contributions (required)
Claude Code (Opus 5). I have reviewed and understandevery change, and take responsibility for it. AI-authored commits are
marked with a
Co-Authored-By/Assisted-Bytrailer.License
(GNU GPL v3.0 or later), and I have the right to contribute it.
Corrects the design doc against the current codebase and locks the open decisions, in the same shape as HERO_EDITOR.md (locked decisions -> corrections to reality -> phased build). Blocking gaps found in the design doc: - no delete path exists for a settings row, which every "reset to defaults" in the feature depends on - editors/moderators/players have no endpoint to read their own nav overrides (GET /admin/settings is admin-only) - renderIndexHtml runs once at boot, not per request - settings values are JSON strings, not objects - getPublic().brand is a cross-repo contract the Android app and Discord embeds theme from; new keys would silently bypass it Locked: effective values resolved server-side into getPublic().brand; radius + shadow tokens only (spacing/border cut); radius tokens seeded at today's real values so the promotion is a no-op; three dark presets in v1 with Parchment deferred; 12-option font shortlist across 8 web families in one request; PNG-only favicons. Co-Authored-By: Claude <noreply@anthropic.com>