7 Commits
Author SHA1 Message Date
agessaman 3657bea8ec style(web_viewer): one color per packet type and role, and 20 channel colors that aren't status lamps
The dashboard's payload mix colored its bars by rank, so a packet type's color changed whenever the traffic order did, and disagreed with the multibyte chart further down, which colors the same types by a fixed slot. The sixth rank was also #198754, the status green. Payload types now take their fixed slot from the chart's SERIES_PALETTE, per theme, so each type has one color everywhere on the page. The role mix gives each role a fixed color matching the Mesh page's node fills: repeaters Signal Blue, room servers Route Teal, then companion orange, sensor violet, bot pink, gateway cyan. Unknown and Other stay neutral, any other role takes a spare, and none of these colors is a lamp.

Real-time hashed channel names onto the whole hue wheel, so a channel could come out status green or alarm red; Public was green. Channel dots now draw from 20 colors per theme, ten hues kept clear of the lamp red, amber and green at two lightness steps, each holding 3:1 on the card (4.2:1 light, 5.2:1 dark). A channel starts at its hashed slot, so its color stays the same between visits. If another channel on the page already holds that slot it steps 7 slots on, a clearly different hue, so up to 20 channels never share a color; with a plain hash, two of three channels on the test mesh collided.

DESIGN.md's data-palette section describes both.
2026-10-24 14:52:30 -07:00
agessaman f98caf7e56 style(web_viewer): give the Mesh page one palette that follows its map theme
Every color on the Mesh page now comes from `--mesh-*` tokens declared at the top of mesh.html. The map and graph have their own light/dark toggle, separate from the site theme, so the tokens switch on `.mesh-dark` and the JS reads them back through `meshColor()`. The viridis heat colors are unchanged.

Edges colored by recency used the status lamps (green, amber, orange, red) with no legend, so the default 72-hour view was mostly amber lines that read as warnings. They now fade one magenta-rose hue with age, under a new "Last heard" legend that hides while a selection recolors edges by direction. Unknown ages are solid gray, since dashes already mean single-byte evidence. Opacity steps more gently because the color carries the fade.

Room servers move from lamp green to Route Teal. A selected node or traced path is ringed or drawn in ink instead of amber, and keeps its own fill. Direction from a selected node uses the dashboard's series blue (incoming), orange (outgoing) and violet (both ways). The stat chips color each value like what it counts on the map; Avg km is plain.

Legends, popups, tooltips, zoom controls and the fullscreen button use the tokens, and popup labels move from #888 (3.5:1) to the muted panel color. Switching the map theme in graph view recolors the graph in place instead of rerunning its layout.

DESIGN.md documents the palette. Checked at 1400px and 390px in both themes, with a selection and in heat mode, with no console errors; 366 web viewer tests pass.
2026-10-24 12:41:05 -07:00
agessaman e0b7eca4fd style(web_viewer): retire legacy blue and green, quiet the packet stream
The pre-Bootstrap-5 #007bff and #28a745 (and their rgba forms) still sat on the navbar brand, status lamps, dark form focus, the conversation rail, the Contacts focus ring, the login page's brand tokens, and Realtime's hex path and newest-row glow. They now use Signal Blue (#0d6efd) and Lamp Green (#198754), which also brings the hex path's white text from 3.1:1 to 4.5:1. The brand stays above 3:1 on the rail as large bold text. The unused .log-entry, .command-entry and .packet-entry rules in base.html are removed.

Realtime packet rows carried an 11-color stripe down the left of each rounded card, repeating what the colored type badge in the row already says. The stripes are gone, so the stream reads like the dashboard's cards.

DESIGN.md adds the 2px (hair) and 5px (meter) radii that legend swatches, focus rings and meters already use, drops the drift notes these changes resolve, and records the touch-target sizing from the adapt pass.
2026-10-17 18:14:04 -07:00
agessaman 4d9f758eff perf(web_viewer): load page libraries where used and vendor the map stack
Every page loaded Chart.js (~200KB), Moment and js-sha256 from a CDN whether it used them or not. Chart.js now loads only on the dashboard, Contacts and Multibyte, and js-sha256 only on Realtime, through a page_libs block in base.html. Moment is gone: its one call wrote to a #last-update element that no page renders, and that formatting is now done natively. The remaining base scripts stay at the end of <body>, so they don't block first paint.

The Mesh page loaded Leaflet 1.9.4, MapLibre GL 5.6.0, maplibre-gl-leaflet 0.1.4 and vis-network 9.1.9 from unpkg, and the login page loaded DM Sans and Outfit from Google Fonts, so neither worked on a LAN without internet. They are now vendored under static/vendor/ and static/fonts/ with their licenses and a README recording versions and sources (source-map comments stripped, since the maps aren't vendored). With nothing left on unpkg or Google Fonts, the CSP drops those hosts; the characterization golden is regenerated for that. package-data gains a fourth directory level for Leaflet's images.

Bootstrap, Font Awesome, Socket.IO, Chart.js and js-sha256 still come from CDNs; PRODUCT.md records that as the remaining offline gap.
2026-10-17 18:10:02 -07:00
agessaman c514dd5361 fix(web_viewer): hold text at the 0.7rem floor and use one monospace stack
Realtime message times were 9.3px (0.58rem), Realtime meta chips and phone Mesh stat labels 9.9px, Mesh, Plugins and Contacts badges about 10.5px, and the Contacts path count compounded to 10.5px as a <small> inside a badge. All now sit at the 0.7rem floor DESIGN.md sets, and the path count inherits the badge size in a lighter weight. Phone layouts still fit at 390px.

Monospace was five different stacks, three of them ending in 'Courier New'. base.html now defines --font-mono (the ui-monospace stack from DESIGN.md) and points Bootstrap's --bs-font-monospace at it, and logs, realtime, mesh, contacts, greeter, config and the legacy .log-entry all read it.
2026-10-17 17:51:23 -07:00
agessaman ebdc44cd90 fix(web_viewer): status and accent text passes contrast in both themes
Bootstrap's text-success, text-warning, text-info and text-danger are fill tones, so used as text they failed contrast (amber on white was 1.6:1, info 2.0:1), and nothing adjusted them for dark mode. base.html now defines per-theme status text tokens that pass 4.5:1 on every surface tier, and the text utilities, text-muted, form-text, code, links and the outline buttons resolve through them. Info and warning badges carry dark text. Ink Muted moves a step darker so it holds on paper-sunk.

The dark message bubbles on Realtime were solid navy, forest green and purple, which overpowered the page and dropped the sender names to 1.7:1. They are now low-alpha tints of the signal and lamp hues over the card, like the dashboard delta chips, and the error bubble is red in both themes instead of purple in dark.

Also: the light log levels and level toggles move to tones that pass on the log well, the dark ERROR toggle uses dark text, Realtime drops its local orange text-warning and its opacity on message times, and the four copies of the dark .table td * rule no longer force body text color onto badges and buttons. DESIGN.md records the tokens and the rule that a fill hue never goes on text directly.
2026-10-17 17:46:51 -07:00
agessaman d0a5c1218f docs: add PRODUCT.md and DESIGN.md for the web viewer
PRODUCT.md records who the web viewer serves and its four jobs; DESIGN.md records the design system the dashboard follows, so the remaining pages can be brought in line with it.
2026-10-17 16:53:23 -07:00