Closes #102.
The only operational surface was /healthz and a fold-out roster inside the owner's own reading page. This adds /admin: an owner-only page carrying the Reader roster and one row per Poll Lane.
- **Poller seam.** `latest.Poller` records each Lane's last pass (`Site`, `Due`, `Checked`, `LastRun`, `Gap`, `Clamped`, `Browser`) and answers `LaneStatus()`; the page reads that snapshot, never a table. A pass that returns before computing its figures (refusal backoff, sidecar down) carries the previous pass's figures forward rather than recording zeroes, and a Lane that has never reached a pace renders no gap at all. Refusal and sidecar reachability are derived at snapshot time.
- **Owner gate at registration.** Every route reaching past the acting Reader lives in `adminRoutes()` and is wrapped in `requireOwner` when it is registered, so a missing gate is visible in the route list rather than hidden in a handler. `web.AdminPatterns()` is what the gate test walks, so a new route cannot be added without being tested. A non-owner gets 404, never 403.
- **Nil poller is a first-class state.** `main.newRouter` takes the reporter as an interface and converts a nil `*Poller` to a nil interface; no poller and no completed pass both render "No data yet" with the reason spelled out, rather than confident zeroes.
- **Roster moved** off the reading page onto /admin, with the Sighting counters and a confirm-gated `Clear marks` control. #103 fills those counters, so on delivery they read zero for everyone - deliberate ordering.
- **One accent, `--patina`** (verdigris, both colour branches): the far side of the wheel from ember's crimson and clear of the archive blue. Ember still means new chapter only; revocation still wears --danger.
Verification: `go vet ./...` and `go test ./...` green (Docker-backed); admin page screenshotted at 1100px and 390px in both colour schemes. Reviewed on both axes (spec, standards); findings on the accent hue, zero-figure honesty and three tests that could not fail are fixed in 58014eb.
Reviewed-on: #107
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #107.
This commit is contained in:
+17
-4
@@ -10,7 +10,7 @@ Implemented in:
|
||||
|
||||
| Surface | Files |
|
||||
| --- | --- |
|
||||
| Web UI (login, list, card, empty, errors) | `backend/internal/web/static/style.css`, `backend/internal/web/templates/{app,card,list,login,chrome,icons}.html`, `backend/internal/web/static/filter.js` |
|
||||
| Web UI (login, list, card, empty, errors, admin) | `backend/internal/web/static/style.css`, `backend/internal/web/templates/{app,admin,lanes,readers,card,list,login,chrome,icons}.html`, `backend/internal/web/static/filter.js` |
|
||||
| Userscript panel (Shadow DOM) | `userscript/manga-bookmark.user.js` — `TEMPLATE` and `CSS` at the bottom of the IIFE |
|
||||
|
||||
## 1. The one idea
|
||||
@@ -73,6 +73,7 @@ Defined once in `backend/internal/web/static/style.css` `:root`, mirrored in the
|
||||
| `--moss` | `#7fae86` | `#3d6c46` | finished accent |
|
||||
| `--clay` | `#b5906f` | `#7c5533` | set-chapter accent |
|
||||
| `--trash` | `#977671` | `#8c6558` | remove, at rest — icons need 3:1, not 4.5:1 |
|
||||
| `--patina` | `#5fb3a6` | `#1f6f66` | admin page only — a Poll Lane needing attention, a Reader whose reports are blocked |
|
||||
| `--play-hot-line` | `#3a1d18` | `#f0cfc6` | desktop cell border, play when `.is-new` |
|
||||
| `--fav-line` | `#332b14` | `#e3d3a4` | desktop cell border, favourite when on |
|
||||
| `--asura` | `#7d93a5` | `#4f6b80` | site tag |
|
||||
@@ -81,9 +82,13 @@ Defined once in `backend/internal/web/static/style.css` `:root`, mirrored in the
|
||||
| `--kagane` | `#9a8aa5` | `#6f5f7d` | site tag |
|
||||
| `--hatch` / `--hatch-dim` | 135° 5px stripe | paper stripe | missing-cover slot |
|
||||
|
||||
`--slate`/`--moss`/`--clay`/`--brass` are held at the same weight deliberately:
|
||||
one accent per action, so a press says which lane it belongs to, with none of
|
||||
them competing with ember. Dark is the default (`color-scheme: dark light`);
|
||||
`--slate`/`--moss`/`--clay`/`--brass`/`--patina` are held at the same weight
|
||||
deliberately: one accent per meaning, so a press says which lane it belongs to,
|
||||
with none of them competing with ember. `--patina` is the admin page's only
|
||||
colour — a cool verdigris, the far side of the wheel from ember's crimson and
|
||||
clear of the archive blue: system health is neither a new chapter nor
|
||||
destruction, so it borrows neither `--ember` nor `--danger`.
|
||||
Dark is the default (`color-scheme: dark light`);
|
||||
light is a `@media (prefers-color-scheme: light)` override of the same names.
|
||||
**Any new colour must be added in both branches** — light is not a filter over
|
||||
dark, the hues are re-tuned.
|
||||
@@ -140,6 +145,14 @@ Recurring specs (copy these rather than inventing sizes):
|
||||
main#list article.card … | .empty
|
||||
```
|
||||
|
||||
The owner's admin page (`admin.html`) is the same sheet with two sections in
|
||||
place of the list — `.lanes` (Poll Lane rows) and `.readers` (the roster) —
|
||||
and no library switch: it belongs to neither library, so its topbar carries a
|
||||
plain `.ghost.back` link home. Both sections are eyebrow + hairline-separated
|
||||
rows, the shape the roster already had as a fold-out. `.lanes` refreshes itself
|
||||
every 30s via `hx-get="/ui/admin/lanes"` with `hx-swap="outerHTML"`; the roster
|
||||
re-renders only in answer to an action.
|
||||
|
||||
**Brand mark**: an inline `<svg class="mark">` (`viewBox="0 0 200 172"`),
|
||||
defined once in `chrome.html`'s `mark` template and reused by `app.html` and
|
||||
`login.html` so it takes the page's `--ink`/`currentColor`/`--ember` rather
|
||||
|
||||
Reference in New Issue
Block a user