Commit Graph

897 Commits

Author SHA1 Message Date
sjg 473bbb280a [style](trx-frontend): add golden rain theme
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:42:09 +01:00
sjg 587b06c6d8 [feat](trx-frontend-http): overlay bookmarks on spectrum; enforce one per freq
Draw bookmark frequency markers on the spectrum canvas: amber vertical
line + ribbon shape (rectangle with V-notch) at each bookmark in view.
Below the freq axis, show a #spectrum-bookmark-axis row of clickable
amber ribbon labels (clip-path bookmark shape); clicking tunes the rig.
Labels auto-appear / collapse as bookmarks scroll in and out of view.

Server: reject POST/PUT with 409 Conflict when another bookmark already
exists at the requested freq_hz (BookmarkStore::freq_taken helper).

Client: bmFetch() triggers a spectrum redraw so markers appear
immediately on load without requiring a tab visit first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:39:09 +01:00
sjg e80f71ced6 [style](trx-frontend-http): make bookmark decoders selectable; gate add on control role
Replace the free-text decoder input with FT8/WSPR checkboxes so users
cannot enter arbitrary decoder strings. Hide the "+ Add Bookmark" button
by default and show it only when the authenticated role is `control`
(or auth is disabled), matching the server-side write-endpoint guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:30:59 +01:00
sjg 832fac1d64 [fix](trx-rs): refine wfm denoise and favicon handling
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:26:04 +01:00
sjg 616ff1b79e [feat](trx-backend-soapysdr): add wfm denoise levels
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:22:02 +01:00
sjg dc3c99b0ee [feat](trx-frontend-http): add Bookmarks tab to web UI
Add a "Bookmarks" tab between Main and Plugins in the tab bar.

HTML: tab panel with toolbar (category filter + Add Bookmark button),
an inline add/edit form (hidden by default, prefills freq/mode/BW from
the current rig state), and a sortable table showing all columns with
Tune / Edit / Del action buttons.

CSS: responsive bm-* classes following existing card/button theming,
works in both dark and light modes and all palette variants.

bookmarks.js: fetches bookmarks on tab activation, renders table with
event delegation, handles create/update/delete via REST, and applies a
bookmark by calling set_freq → set_mode → set_bandwidth, plus toggles
FT8/WSPR decoders when the stored mode is DIG.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:17:15 +01:00
sjg 32a7629e6a [feat](trx-frontend-http): add bookmark CRUD REST endpoints
GET /bookmarks          — list all (optional ?category= filter); rx role
POST /bookmarks         — create; control role enforced in handler
PUT /bookmarks/{id}     — update; control role enforced in handler
DELETE /bookmarks/{id}  — remove; control role enforced in handler

Auth middleware classifies /bookmarks and /bookmarks/* as Read so rx
users can reach GET; write handlers call require_control() to reject
lower-privileged sessions with 403.

Also serves bookmarks.js via GET /bookmarks.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:17:01 +01:00
sjg 34f6b42330 [feat](trx-frontend-http): add BookmarkStore backed by pickledb
Add pickledb and dirs dependencies. Introduce BookmarkStore wrapping
PickleDb behind Arc<RwLock<>> with list/get/insert/upsert/remove ops.
Keys stored as "bm:{id}" in ~/.config/trx-rs/bookmarks.db; falls back
to ./bookmarks.db when config dir is unavailable.

Wire BookmarkStore into build_server() as actix-web app_data so all
request handlers can share the store.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:16:50 +01:00
sjg 31238098ca [fix](trx-backend-soapysdr): raise wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:07:29 +01:00
sjg 623aad10d1 [fix](trx-backend-soapysdr): preserve more stereo under denoise
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:06:15 +01:00
sjg fb52558652 [feat](trx-backend-soapysdr): adapt wfm stereo separation gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 19:01:08 +01:00
sjg d569db6643 [fix](trx-backend-soapysdr): fine tune wfm phase trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:53:12 +01:00
sjg 2b1764b90e [fix](trx-backend-soapysdr): restore neutral wfm stereo trim
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:50:54 +01:00
sjg a1a8aaeb9d [fix](trx-backend-soapysdr): rebalance wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:48:51 +01:00
sjg 129c27548e [fix](trx-backend-soapysdr): reduce wfm output gain
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:46:49 +01:00
sjg ded6e2a1f8 [fix](trx-backend-soapysdr): widen wfm stereo image
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:43:07 +01:00
sjg fbd881af7b [fix](trx-frontend): add peak hold off and scale waterfall floor
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:38:17 +01:00
sjg 0244839a4f [fix](trx-frontend): restore spectrum peak hold
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:34:13 +01:00
sjg 353ce517ec [style](trx-frontend): shorten aprs live bar window
Limit the APRS live bar to the last 15 minutes and show that
window in the overlay header.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:23:07 +01:00
sjg 00f5108a58 [feat](trx-client): support website_name in header
Add an optional website_name config field and prefer it over
callsign for the linked web header title label.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:19:36 +01:00
sjg 31b40fc1ef [fix](trx-frontend): gate RDS display updates on WFM mode
updateRdsPsOverlay was called on every spectrum frame (25 Hz)
regardless of mode, doing 15+ DOM element lookups and text updates
even in USB/AM/CW/etc.  The server-side RDS DSP already only runs
in WFM; align the client:

- Spectrum SSE handler: only increment rdsFrameCount and call
  updateRdsPsOverlay when lastModeName === "WFM"
- Mode change: call resetRdsDisplay() when switching to or from WFM
  so the overlay and RDS panel are cleared promptly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:14:56 +01:00
sjg e337b6d2de [feat](trx-client): link web header title to website
Add an optional website URL to config and use it for the web header
title when present, falling back to the version title otherwise.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:12:31 +01:00
sjg 5899592b6c [fix](trx-rs): limit aprs live bar to one hour
Attach replay timestamps to APRS history and filter the APRS live bar
so it only shows the last hour of valid entries.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:08:38 +01:00
sjg 63fd35802e [feat](trx-frontend): add Neon Disco colour scheme
Deep purple-black backgrounds, neon magenta (#ff10e0) as primary
accent and neon green (#39ff14) as secondary.  Waterfall sweeps
hue 300→120 (magenta→green).  Light variant uses muted (#cc00a8 /
#1f8800) counterparts on a lavender-tinted white background.

- style.css: dark + light CSS variable blocks for neon-disco
- app.js: CANVAS_PALETTE entry; "neon-disco" added to valid styles
- index.html: Neon Disco option in the style picker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:06:17 +01:00
sjg 08a91ebe43 [style](trx-frontend): theme receiver marker via CSS var
Remove hardcoded #3388ff from the TRX circleMarker; apply
.trx-receiver-marker class and use stroke/fill: var(--accent-green)
so the dot follows the active colour scheme.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:02:33 +01:00
sjg e2a9e4d610 [feat](trx-frontend): rich popup for receiver/owner marker on map
Replace plain-text receiver marker popup with a styled info card
matching the APRS popup layout.  Shows callsign, trx-server version
and build date, owner callsign (when different), QTH coordinates,
and all configured rigs with manufacturer/model; active rig is
badged.

Rig data (manufacturer, model, display_name, active state) is stored
in serverRigs/serverActiveRigId on each /rigs refresh.  Popup content
is rebuilt live on popupopen so it always reflects current state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 18:00:22 +01:00
sjg 2188d62069 [feat](trx-frontend): rich popup for receiver/owner marker on map
Replace plain-text receiver marker popup with a styled info card
matching the APRS popup layout.  Shows:
- Station callsign (serverCallsign / ownerCallsign)
- trx-server version and build date
- Owner callsign (when different from station callsign)
- QTH coordinates
- All configured rigs with manufacturer/model; active rig badged

Rig data (manufacturer, model, display_name, active state) is
stored in serverRigs/serverActiveRigId on each /rigs refresh.
Popup content is rebuilt live on popupopen so it always reflects
the current state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:58:48 +01:00
sjg c2add05a7c [fix](trx-frontend): use server decode history only
Remove APRS client-side persistence, reset decode views before replay,
and clear decode panes only after the server clears its history.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:58:16 +01:00
sjg 0e6d2c0c47 [style](trx-frontend): theme radio path line via CSS var
Remove hardcoded #3388ff colour from L.polyline options; use
stroke: var(--accent-green) and stroke-opacity in the CSS class
so the path follows the active colour scheme automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:53:52 +01:00
sjg 1ef1da7c0d [feat](trx-frontend): show animated radio path on APRS station click
Draw a blue dashed polyline from the receiver to the clicked APRS
station on popup open; remove it on popup close.  CSS stroke-dashoffset
animation creates a traveling-dash effect suggesting signal propagation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:50:39 +01:00
sjg 6e9d0040bb [fix](trx-frontend): preserve APRS reception timestamp across page refresh
Previously aprsMapAddStation forced Leaflet map init on a hidden element
during history restore.  When live packets later arrived they stamped a
fresh _tsMs, resetting the displayed age to "0s ago".

Decouple data storage from Leaflet rendering:
- aprsMapAddStation now stores station data in stationMarkers immediately
  (with the original _tsMs from localStorage) without touching the map
- _aprsAddMarkerToMap creates Leaflet markers only when the map is ready
- initAprsMap materialises all buffered APRS entries on first open

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:47:43 +01:00
sjg 42e73f5eeb [fix](trx-frontend): fix APRS map popup age, distance, and dark theme
- Rebuild popup content on popupopen event so age and distance
  are always computed fresh at the moment of opening; store
  _aprsCall on each marker for O(1) lookup
- Extend map to fill viewport down to the footer instead of 60%
- Override Leaflet popup background/color to use CSS theme vars,
  fixing invisible text in dark theme

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:27:38 +01:00
sjg db425156a4 [feat](trx-frontend-http): rich APRS map tooltips with distance and age
Each station popup now shows:
- Callsign/SSID header
- Age (s/min/h ago, from _tsMs stamped on receive)
- Distance from receiver (Haversine, km or m)
- Packet type and via path
- Full info/comment string

Adds haversineKm(), formatTimeAgo(), buildAprsPopupHtml() helpers in
app.js and .aprs-popup-* CSS. Passes full packet object as 7th arg
to aprsMapAddStation from aprs.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 17:19:00 +01:00
sjg dd051beee3 [style](trx-frontend-http): match APRS tab clear button to CW reference
Remove custom #aprs-clear-btn CSS overrides and SVG icon; reduce to a
plain <button>Clear</button> so it inherits the same global button
style as the CW clear button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 16:37:37 +01:00
sjg f537e1a11b [feat](trx-client): add configurable initial map zoom
Add an HTTP frontend config option for the initial APRS map zoom,
expose it through frontend metadata, and apply it in the web UI.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 16:35:12 +01:00
sjg 8c6c370563 [style](trx-frontend): rebalance aprs overlay title spacing
Tighten the spacing inside the APRS title while adding more room
between the title and the clear action.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:33:32 +01:00
sjg 1ae44a714f [style](trx-frontend): reduce aprs clear text size
Scale the APRS overlay inline clear text down for better balance
with the enlarged APRS title.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:31:28 +01:00
sjg 21a019a0fa [style](trx-frontend): enlarge aprs overlay title
Increase the APRS overlay header base text size so the title reads
larger alongside the clear action.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:28:50 +01:00
sjg 81dca146cf [style](trx-frontend): enlarge aprs clear text
Increase the APRS overlay inline clear text size for stronger
readability.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:25:49 +01:00
sjg 5b3d0c0865 [style](trx-frontend): increase aprs overlay text size
Increase the APRS overlay header text and make the inline clear text
match the row's base text size.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:24:32 +01:00
sjg aa73a4bc00 [style](trx-frontend): simplify aprs overlay clear action
Render the APRS overlay clear action as inline clickable text inside
a span wrapper instead of a button-like control.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:23:08 +01:00
sjg eec147c26f [style](trx-frontend): reduce aprs overlay header height
Cut the APRS overlay header sizing further so the row reads much
smaller and no longer dominates the overlay.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:20:46 +01:00
sjg 579ce31bbd [style](trx-frontend): inset aprs overlay from edges
Offset the APRS overlay slightly from the waterfall edges so it reads
as a hovering strip and leaves the waterfall visible at the sides.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:20:08 +01:00
sjg 69253959c8 [style](trx-frontend): shrink aprs overlay clear control
Reduce the APRS overlay clear control so it no longer sets the
header row height.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:18:42 +01:00
sjg 17a643d070 [style](trx-frontend): polish aprs overlay clear control
Wrap the APRS overlay clear action in a styled span and place it
next to the APRS title for a tighter header layout.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:16:20 +01:00
sjg 26e51447d7 [style](trx-frontend): tighten aprs overlay header
Reduce the APRS overlay header height by trimming spacing and scaling
down the clear control chrome.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:14:39 +01:00
sjg b24d6663a2 [style](trx-frontend-http): align RDS bar border-radius with UI standard
Replace 999px pill on #rds-ps-overlay with 6px to match the rest of
the UI button rounding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:13:20 +01:00
sjg 436e1d8e23 [style](trx-frontend-http): align APRS bar border-radius with UI standard
Replace 999px pill radii with 6px (overlay), 4px (clear btn, pin),
3px (clear icon) — matching the standard button radius used throughout
the rest of the UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:12:53 +01:00
sjg b6848c0c8e [style](trx-frontend): refine aprs web controls
Restyle the APRS clear button and tighten the APRS overlay bar to use
more compact, polished chrome while keeping the existing behavior.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:06:36 +01:00
sjg 39c4f1d800 [style](trx-frontend-http): tighten APRS bar entry spacing further
Reduce line-height to 1.05, use 0.1rem vertical padding + hairline
border-bottom to separate entries instead of whitespace.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-01 15:01:59 +01:00