Commit Graph
22 Commits
Author SHA1 Message Date
sjgandClaude Opus 5 5b7dd493d4 [feat](trx-frontend-http): draw APRS symbols from the sprite sheets
CI / lint (pull_request) Successful in 2m16s
CI / test (pull_request) Successful in 8m12s
CI / frontend (pull_request) Successful in 3m2s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m24s
CI / test (push) Successful in 7m28s
CI / frontend (push) Successful in 2m11s
CI / reuse (push) Successful in 3s
Resolve a table/code pair to a sprite cell in aprs-shared, and use it
from both the packet lists and the map markers, which had each been
printing the raw symbol character in a bordered box.

A table identifier of / or \ selects the primary or alternate sheet
directly.  Anything else is an overlay character, which the APRS spec
draws on top of the alternate symbol -- so those stack the overlay sheet
over the alternate one rather than picking a sheet.  Codes outside
0x21..0x7E have no cell and keep the old character box.

The sheet URLs stay in the stylesheet so a min-resolution query can swap
in the retina sheets; only the cell offset is computed and set inline.
Map markers share the helper through the plugin chunk, so the map stays
free of any remote symbol fetch.

Verified in a browser against the real stylesheet and sheets: /> is a
car, /_ a WX circle, /& an igate diamond, \n a red triangle, and the
overlays S> and 7# carry their character on the alternate symbol.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018huL1ELyr86yVqfAabtioA
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-03 19:55:50 +02:00
sjgandClaude Opus 5 56c363a517 [fix](trx-frontend-http): align the Statistics page and unblock the tab strip
Two faults, both mine, both visible in one screenshot of that page.

#tab-statistics was the only panel with padding of its own, so its title
and content sat 16px inside where every other page begins.  Remove it and
the page lines up with the header and with its siblings.

Removing the tab strip's `overflow-x` left it unable to shrink below its
content, so at around 1280px it ran under the controls: the Map tab sat
beneath the audio button and Tools beneath REC.  Clipping is safe again —
the menus it anchors are reparented to the body when they open — so the
strip can shrink, and the labels now give way to icons at 1360px rather
than 1180px, before it has to clip anything.

Measured at 1280px: 321px of clearance between the strip and the
controls, and the page title at the same left edge as the header.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 23:59:58 +02:00
sjgandClaude Opus 5 5ad91b4ab6 [fix](trx-frontend-http): stop doubling the space under the Statistics title
CI / lint (pull_request) Successful in 2m17s
CI / test (pull_request) Successful in 8m13s
CI / frontend (pull_request) Successful in 3m1s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m20s
CI / test (push) Successful in 7m33s
CI / frontend (push) Successful in 2m12s
CI / reuse (push) Successful in 3s
The page titles carry a bottom margin, which is what spaces them from the
content on the plain block panels.  #tab-statistics is not one: it is a
flex column with `gap: 1rem`, so the margin landed on top of that gap and
left 28px under the title where every other page had 12px.

Drop the margin on that panel and let its own gap do the spacing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 23:50:03 +02:00
sjgandClaude Opus 5 1843522b45 [feat](trx-frontend-http): give the Tools destinations page titles
CI / lint (pull_request) Successful in 2m21s
CI / test (pull_request) Successful in 8m13s
CI / frontend (pull_request) Successful in 2m59s
CI / reuse (pull_request) Successful in 2s
CI / lint (push) Successful in 2m21s
CI / test (push) Successful in 7m30s
CI / frontend (push) Successful in 2m10s
CI / reuse (push) Successful in 3s
Recorder stated its name; Statistics, Settings and About did not, so one
page in eight carried a title.  The class it used, section-heading, had
no rule behind it either, leaving even that title as a default h2.

Which way to unify follows from the navigation change.  The tab strip
highlights the destination you are on, so Radio, Bookmarks, Digital modes
and Map already say where you are and a title would repeat the strip
while costing vertical space the spectrum wants.  The four destinations
behind Tools get no such highlight — the strip looks the same on all of
them — so those are exactly the pages that have to name themselves.

Give the three that were missing a heading, and style section-heading so
all four match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 23:46:09 +02:00
sjgandClaude Opus 5 41ddecf5a7 [fix](trx-frontend-http): label the overflow tab Tools and hide its glyph
CI / test (pull_request) Successful in 8m17s
CI / lint (push) Successful in 2m18s
CI / lint (pull_request) Successful in 2m16s
CI / frontend (pull_request) Successful in 3m6s
CI / reuse (pull_request) Successful in 3s
CI / test (push) Successful in 7m25s
CI / frontend (push) Successful in 2m11s
CI / reuse (push) Successful in 3s
The button rendered as "•••More": the dots span carried no styling at
all, so the glyph sat flush against the label instead of behaving like
the icon it is.  Every other tab hides its icon while labels are shown
and swaps to it when they are not; the dots now follow the same rule, so
the button reads "Tools" beside the other labels and becomes the glyph
alone in the icon band.

"More" also said nothing about the destinations behind it.  The menu
holds Statistics, Recorder, Settings and About, so name it Tools and give
the button an aria-label that spells that out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 23:36:41 +02:00
sjgandClaude Opus 5 b4912f5879 [fix](trx-frontend-http): render the header menus above the page
CI / lint (push) Successful in 2m17s
CI / test (push) Successful in 7m23s
CI / lint (pull_request) Successful in 2m16s
CI / test (pull_request) Successful in 8m13s
CI / frontend (pull_request) Successful in 2m59s
CI / reuse (pull_request) Successful in 3s
CI / frontend (push) Successful in 2m10s
CI / reuse (push) Successful in 3s
Both header dropdowns were laid out inside the bar rather than over the
page.  The navigation menu opened as an 18px sliver positioned above its
own button, and the overflow menu did not appear at all.

Two causes.  The tab strip kept `overflow-x: auto` from when it scrolled,
which clips an absolutely positioned descendant — and the strip is what
the navigation menu anchors to.  The strip no longer scrolls, since the
occasional destinations moved behind More, so the property and the edge
fade that went with it are both gone.

Anchoring in fixed coordinates at open time addresses the general case:
an absolutely positioned menu is clipped by any scrolling ancestor and
trapped inside whatever stacking context its ancestors create, so it can
be squashed inside the bar or painted underneath page content.  Fixed
coordinates answer to the viewport, and the menu flips above its button
near the bottom edge.

Clearing `right` when setting `left` keeps the menus at their natural
width: the stylesheet pins them to the right of their anchor, and leaving
that in place stretched them across the bar — 845px for a four-item list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 19:18:47 +02:00
sjgandClaude Opus 5 27f2558193 [feat](trx-frontend-http): one navigation model at every width
CI / test (pull_request) Successful in 8m13s
CI / frontend (pull_request) Successful in 3m0s
CI / reuse (pull_request) Successful in 3s
CI / test (push) Successful in 7m25s
CI / lint (pull_request) Successful in 2m18s
CI / lint (push) Successful in 2m17s
CI / frontend (push) Successful in 2m9s
CI / reuse (push) Successful in 3s
Eight destinations sat flat in the tab strip with equal weight, competing
with the controls for the same row and then scrolling out of reach with
only a fade to say so.  They are not equal: Radio is where an operator
spends nearly all their time, Bookmarks, Digital modes and Map are
operating surfaces, and Statistics, Recorder, Settings and About are
occasional.

The mobile layout already grouped them exactly that way, behind its More
menu, so the application carried two navigation models.  Adopt the mobile
grouping at every width instead of adding a third: four operating tabs
plus More.  The strip no longer scrolls at any width, and the menu keeps
its bottom-sheet placement on mobile while anchoring under its button
elsewhere.

Drop the labels between 701 and 1180px so the tabs degrade to their icons
— which every tab already carries — before the strip could ever need to
hide a destination.

Rename Main to Radio: it is the receiver, not a generic first page, and
the name now says what the destination is rather than where it sits.

Freeing that width also let the style picker and theme toggle return to
the bar inline, leaving only the layout picker in the overflow menu.

Navigating to About in the browser smoke test now goes through More, as a
person would.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 19:12:14 +02:00
sjgandClaude Opus 5 3a9bf1b7ce [fix](trx-frontend-http): drop the rig description from the top bar
CI / test (pull_request) Successful in 8m22s
CI / frontend (pull_request) Successful in 3m1s
CI / reuse (pull_request) Successful in 3s
CI / lint (pull_request) Successful in 2m17s
The header repeated the active rig's hardware string and mode list beside
the rig picker.  With a real SDR that reads

  SoapySDR driver=airspyhf,serial=c852eb5dd23539f8 · RX · SDR filters ·
  LSB · USB · CW · CWR · AM · +7 modes

which is longer than every other control in the bar combined, and it is
already on the About tab in full, split across its Rig, Active rig,
Connection, Modes and VFO rows.

Remove the element and the builder behind it.  Rig switching keeps its
feedback through the existing hint channel rather than by briefly
rewriting a permanent label, and the identity that belongs in a header —
the rig's display name — stays in the left subtitle.

The freed width is not spent: the tab strip now reaches Settings before
it needs to scroll, where it previously faded out during Statistics.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 18:59:28 +02:00
sjgandClaude Opus 5 dd5760c436 [style](trx-frontend-http): fade the scrolled tab strip edge
CI / lint (pull_request) Successful in 2m19s
CI / test (pull_request) Successful in 8m17s
CI / frontend (pull_request) Successful in 3m0s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m17s
CI / test (push) Successful in 7m33s
CI / frontend (push) Successful in 2m9s
CI / reuse (push) Successful in 3s
The page tabs scroll rather than wrap, so the last visible tab was sliced
mid-word ("Se…" for Settings), which reads as a rendering fault instead of
as an invitation to scroll.

Fade the trailing edge with a mask.  A colour-matched cover gradient is
the usual trick, but the card is transparent, so a cover would have to
track the page background across both themes and all nine styles; a mask
is colour-agnostic.  Only the trailing edge is faded, leaving the first
tab crisp while the strip sits at rest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 18:48:34 +02:00
sjgandClaude Opus 5 eee3630f04 [feat](trx-frontend-http): compact single-row top bar
The header's height depended on the viewport width, and not even
monotonically: 112px at 1440, 169px at 1100, 131px at 900, 246px at 720.
Both control groups wrapped, so every width produced a different ragged
block — eight page tabs across four rows at 1100px, and action controls
across three.  Four different control heights (32, 34, 45 and 54px) sat
in the same row, the 54px one being the rig picker with its summary
stacked underneath, and on narrow viewports the icon buttons stretched to
fill half the row, rendering a play triangle centred in a 249px box.

Lay both groups out as one row that never wraps.  Controls are a uniform
2rem and no longer stretch, the rig summary sits inline beside its select,
and the page tabs scroll instead of wrapping.  Secondary controls —
layout, style and theme — move into an overflow menu when the bar cannot
hold them, leaving audio, record and the rig picker inline.

Deciding when they no longer fit needs natural widths, not rendered ones:
the nav has min-width 0 and scrolls, so it always shrinks to the leftover
space and always reports scrolling, and the bar reports overflow even when
nothing is clipped.  scrollWidth on the scroll container is its
unconstrained content width, which is what the fit test compares against
the space available.

Measured after the change: 72px at 1440, 1280, 1100, 900 and 480, every
control 32px, nothing clipped at any width.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdyUjuXejCEfiub675z6cz
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-08-02 18:45:43 +02:00
sjg 074c67c7b9 refactor: convert APRS plugin to TypeScript 2026-08-01 12:43:40 +02:00
sjg 508ed8a8e7 feat(ui): separate scheduler controls subsection
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 2s
CI / reuse (pull_request) Failing after 2s
CI / lint (push) Failing after 0s
CI / test (push) Failing after 1s
CI / reuse (push) Failing after 1s
2026-08-01 11:28:51 +02:00
sjg d9fc623ef4 fix(ui): simplify operator layout picker
CI / lint (push) Failing after 1s
CI / test (push) Failing after 0s
CI / reuse (push) Failing after 0s
CI / lint (pull_request) Failing after 2s
CI / test (pull_request) Failing after 2s
CI / reuse (pull_request) Failing after 1s
2026-08-01 11:25:32 +02:00
sjg 53736ef750 fix(ui): hide SDR power and align header controls
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 2s
CI / reuse (pull_request) Failing after 1s
2026-08-01 11:23:57 +02:00
sjg 6566eae2c7 fix(ui): keep workspace and rig context visible
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 1s
CI / reuse (pull_request) Failing after 1s
CI / lint (push) Failing after 0s
CI / test (push) Failing after 0s
CI / reuse (push) Failing after 1s
2026-08-01 11:19:31 +02:00
sjg af74430551 fix(ui): make rig switching atomic and visible 2026-08-01 11:15:39 +02:00
sjg d07dbdc645 feat(ui): focus broadcast workspace on reception 2026-08-01 11:14:10 +02:00
sjg 9fbf90ee91 feat(ui): explain operator workspace choices 2026-08-01 11:12:33 +02:00
sjg b20da5c541 style(ui): polish shared interaction components
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 1s
CI / reuse (pull_request) Failing after 2s
CI / lint (push) Failing after 2s
CI / test (push) Failing after 1s
CI / reuse (push) Failing after 2s
2026-08-01 10:43:29 +02:00
sjg a0bdaa2c4b feat(ui): improve radio operator experience
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 1s
CI / reuse (pull_request) Failing after 1s
CI / lint (push) Failing after 1s
CI / test (push) Failing after 1s
CI / reuse (push) Failing after 0s
2026-08-01 02:24:47 +02:00
sjgandClaude Opus 4.8 2121817c04 [style](trx-frontend-http): refine web UI design system and a11y
Introduce a shared design-token layer and apply it to the web
frontend for a more consistent, readable, and accessible feel.
Pure CSS plus one HTML block; no app.js behaviour changes, and the
existing multi-theme (style x light/dark) system is preserved.

- Add spacing, type, radius and motion tokens to :root.
- Fix undefined --surface consumed by .controls-tray, which dropped
  the panel background entirely; it now resolves per theme.
- Set body line-height and font smoothing; collapse near-duplicate
  font sizes onto canonical scale steps.
- Rebuild the auth gate with classes and replace hardcoded colours
  (#ff6b6b, #9aa4b5) with theme variables so it renders correctly in
  every theme.
- Add an opacity fade on tab switches, gated by prefers-reduced-motion.
- Extend focus-visible rings to the spectrum canvas, tabindex controls
  and links.
- Add a self-theming --accent-text token to lift accent-coloured text
  (links, active tab) to WCAG AA without altering brand fills.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NFpGtGTWUEYXLwZeZs2RAV
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-07-17 20:57:43 +02:00
sjg ba48de2d30 Initial commit
Sync docs to Wiki / wiki (push) Has been cancelled
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-05-17 23:25:14 +02:00