Admin: tool registry, grouped nav, and an /admin/ hub
This commit is contained in:
1 parent
7fc2b02e6a
commit
7040d4f078
9 files changed
+412
-7
No files matched your search
@@ -0,0 +1,105 @@
|
||||
# Admin Navigation Tidy-up
|
||||
|
||||
**Date:** 2026-10-12
|
||||
**Project:** newbury-exhibit-v3
|
||||
**Status:** written and checked offline; not yet opened on the deployed server
|
||||
**Tags:** admin, navigation, ux, auth
|
||||
|
||||
## Context
|
||||
|
||||
The admin section had grown to eleven pages behind a nav bar that was a flat,
|
||||
hand-maintained array of nine lowercase filenames. Asked to make it easier to
|
||||
navigate; reading it first turned up three things worse than untidiness.
|
||||
|
||||
## What was actually wrong
|
||||
|
||||
- **`testsheet.html` was unreachable.** It existed, it worked, it was in no
|
||||
nav list. The only way in was typing the URL.
|
||||
- **`calibrate.html` was listed in the nav but never rendered it** — it imports
|
||||
nothing from `admin.js`, so the link led to a page with no way back.
|
||||
- **`calibrate.html` never called `requireAuth()`.** Every other admin page
|
||||
does. In `final` mode it was the one admin page openable without the
|
||||
password. That is a hole, not a nav problem, and it was only visible because
|
||||
the nav work meant reading every page's imports.
|
||||
- **`/admin/` had no `index.html`**, so the bare path 404s and there is no
|
||||
landing point.
|
||||
- **Labels were filenames**: `landing`, `plan`, `print`, `preview` say nothing
|
||||
about what the page does, and the four physical-setup tools sat
|
||||
interleaved with the content editors.
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- **One registry, two consumers.** `TOOLS` in `admin.js` carries id, display
|
||||
name, group and a one-line blurb. `nav()` and the new hub both generate from
|
||||
it. The old bug class — a page existing in the folder but not in the bar —
|
||||
needs someone to forget the registry rather than forget one of two lists.
|
||||
|
||||
- **`tools/check-admin-nav.mjs` closes the loop the registry cannot.** The
|
||||
registry guarantees the bar and the hub agree with each other; it cannot
|
||||
notice a page nobody registered. The check walks `public/admin/*.html` and
|
||||
fails on anything unregistered, plus asserts `nav()` marks exactly one link
|
||||
active and still roots at `<header>`.
|
||||
|
||||
*Rejected:* a rule that a tool's label must differ from its filename. It
|
||||
fired on Layout, Characters, Playlist and Calibrate, which are all correctly
|
||||
named. The labels that were genuinely bad were bad because they did not
|
||||
describe the page, which no mechanical rule can tell.
|
||||
|
||||
- **Four groups: World, Viewer, Setup, Diagnostics.** World is what is in the
|
||||
exhibit (layout, characters, playlist), Viewer is what visitors get (landing
|
||||
page, virtual viewport), Setup is the physical work (crests, plan, A3 rig,
|
||||
calibrate), Diagnostics is the error log. The group label doubles as the
|
||||
separator in the bar, so the grouping survives wrapping onto a second row on
|
||||
a phone rather than becoming a run of orphaned pipes.
|
||||
|
||||
- **`nav()`'s root stays `<header>`.** `print.html` hides `header` on print and
|
||||
`plan.html` hides its `#hdr` wrapper; changing the element would have
|
||||
silently printed the nav bar onto the crest sheets.
|
||||
|
||||
- **Additive CSS only.** Existing selectors in `styles` are untouched except
|
||||
for `flex-wrap` on `header`; ten pages inject `styles` plus their own rules
|
||||
and several style `h1` indirectly through it. New chrome is namespaced under
|
||||
`.anav`, `.hub`, `.card`, `.chip`.
|
||||
|
||||
- **Two pages cannot host the bar.** `calibrate.html` is a full-bleed camera
|
||||
view and `testsheet.html` must print edge to edge. Both carry
|
||||
`chrome: false`. Calibrate gets a floating pill (`backLink()`, styled from
|
||||
`BACK_CSS`, exported separately so the page need not pull in the body and
|
||||
background rules that would wreck it). Testsheet gets an inline link in its
|
||||
existing toolbar — a floating pill would have landed on top of the Print A3
|
||||
button.
|
||||
|
||||
- **Hub status chips never block.** Each endpoint is fetched in parallel and a
|
||||
failure drops its chip rather than the page. The hub's job is to get you
|
||||
somewhere else quickly; it must not sit spinning because the error log is
|
||||
unhappy.
|
||||
|
||||
## Technical Details
|
||||
|
||||
`public/admin/admin.js` — added `GROUPS`, `TOOLS`, `toolById`, `href`,
|
||||
`BACK_CSS`, `backLink()`; rewrote `nav()`; extended `styles` additively.
|
||||
`api()` and `requireAuth()` unchanged.
|
||||
|
||||
`public/admin/index.html` — new. Mode banner (dev vs final), then grouped
|
||||
cards. Chips: crest and spawn counts from `/api/scene`, tracks/residents/
|
||||
windows from `/api/playlist`, built models from `/api/characters`, roster size
|
||||
from `/api/ghosts`, error count from `/api/client-errors`.
|
||||
|
||||
`public/admin/calibrate.html` — added `requireAuth()` and `backLink()`.
|
||||
`public/admin/testsheet.html` — added an inline `← Admin` link to `.bar`.
|
||||
|
||||
## Open Questions / Next Steps
|
||||
|
||||
- **Nothing here has been opened against a running server.** The checks are
|
||||
static: registry/folder agreement, `nav()` output, HTML tag balance, module
|
||||
syntax. Worth confirming the hub's chips match reality on first load, since
|
||||
the exact shape of `/api/characters` and `/api/ghosts` (array vs wrapper
|
||||
object) is handled defensively rather than known.
|
||||
- `calibrate.html` gaining `requireAuth()` means it now redirects to the login
|
||||
screen in final mode. Expected, but it is a behaviour change on a page that
|
||||
used to open straight to the camera.
|
||||
- The hub is a plain page; a tablet propped next to the table would want the
|
||||
virtual viewport, not this. Possibly worth a "kiosk" entry later.
|
||||
- Still outstanding from 2026-10-07: on-device validation of the sub-pixel and
|
||||
ROI work, re-tuning the 1€ filter and `MAX_REPROJ_PX` if `reproj` has
|
||||
dropped, and carrying a raised crest into the real town layout.
|
||||
Reference in new issue
Block a user