Files
Alex BandClaude Opus 5.5 0f394fc8dd feat(site): themeable chrome, header logo and home link, instance discovery (#9)
* feat(site): themeable chrome, header logo and home link, instance discovery

Theming: every colour, font and header style the page chrome uses is now a
token at the top of public/style.css. site.theme_css in config.yaml is
copied to site-theme.css at container start, and both pages load it last,
so a theme is just a stylesheet that redefines tokens. Data colours
(status, planned/real markers, packet outcomes, coverage ramp) stay fixed:
the map draws them from JS and the legend has to keep matching it. With no
theme configured the default look is pixel-identical to before.

Branding: site.logo (local image, copied in, or an http(s) URL) shows in
the header on the map and analytics pages; site.home_url links the logo
and title back to the deployment's own site. document.title now follows
site.name instead of a hardcoded "ScotMesh Repeater Coverage". A missing
theme or logo file is logged and the site starts with the built-in look.

Discovery: <meta name="generator" content="HopReach"> on both pages, and
/.well-known/hopreach.json (name, version, backend, map centre) written by
-prepare and served CORS-open, so other instances can be found.

Also:
- #plan-panel number inputs were never styled (the shared rule covered
  #sim-panel only), so they rendered as white browser defaults.
- npm test was failing on main: check_module_refs didn't know the
  HopReachCartoTiles global added in #6. CI never ran npm test, so it went
  unnoticed; the frontend job now runs it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(site): an empty site.subtitle drops the subtitle line

With subtitle: "" the subtitle element is hidden, so the header is just the
logo and the title, centred on each other — e.g. a network wordmark logo
followed by "Repeater Coverage". A config test pins that an explicit empty
value wins over the built-in default subtitle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(map): line up the header subtitle and the right-hand map controls

The subtitle carried a 0.5rem left margin, leftover from when it sat
inline beside the title, so it started 8px right of the title it sits
under. The boxes down the map's right edge (Map display, Neighbours
observed, Map detail, region scope filter, legend) were each sized to
their own content, so their left edges stepped in and out. They now share
a 220px minimum width - the legend's own max-width, and enough for Map
display expanded - so they form one column collapsed or expanded. Scoped
to .leaflet-right, so the phone Map options sheet is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(site): address review of the theming PR

- Discovery reported the wrong backend: it read source.type raw, skipping
  config.Resolve's deprecated beacon.enabled alias and case handling, so
  a beacon.enabled deployment advertised "corescope". It now uses Resolve;
  an unknown type is omitted rather than guessed.
- checkHomeURL warned about relative paths ("/", "../") that the page
  links to fine. It now mirrors site-brand.js's safeUrl, and says so
  specifically when a value looks like a domain missing https://.
- installLogo cleared site-logo.* before reading the source, so a source
  that was itself one of those files was deleted. It reads first now.
- A plain-http logo URL now logs a mixed-content warning.
- Every color-mix() declaration is preceded by its rgba() equivalent at
  the default token value, so browsers without color-mix (Safari/iOS
  < 16.2, Chrome < 111) render as before instead of dropping the tint.
- Static <h1> placeholder matches the neutral <title>; the dead
  `header > div:first-child` phone selector is gone and the split
  .site-brand rule is merged.
- buildJSConfig's test moves to prepare_test.go (Rule 2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 04:07:03 +01:00
..