From a0ca4ceeda06f1037cf7c8d226dc91a96ff9c982 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Sun, 8 Feb 2026 10:43:34 +0100 Subject: [PATCH] [feat](trx-frontend-http): callsign link, centered freq, title, jog lock - Make server callsign a clickable link to qrzcq.com - Center frequency input text and use DSEG14 Classic font - Include callsign in page title (e.g. N0CALL - trx-frontend-http v0.1.0) - Block jog wheel when rig lock is active Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stanislaw Grams --- .../trx-frontend-http/assets/web/app.js | 20 +++++++++++++------ .../trx-frontend-http/assets/web/index.html | 2 +- .../trx-frontend-http/assets/web/style.css | 4 +++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index 13dcba7..7eb1b65 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -36,6 +36,8 @@ let lastFreqHz = null; let jogStep = 1000; // default 1 kHz let jogAngle = 0; let lastClientCount = null; +let lastLocked = false; +const originalTitle = document.title; function readyText() { return lastClientCount !== null ? `Ready \u00b7 ${lastClientCount} user${lastClientCount !== 1 ? "s" : ""}` : "Ready"; @@ -155,10 +157,15 @@ function render(update) { } // Server subtitle: "trx-server vX.Y.Z hosted by CALL" if (update.server_version || update.server_callsign) { - let text = "trx-server"; - if (update.server_version) text += ` v${update.server_version}`; - if (update.server_callsign) text += ` hosted by ${update.server_callsign}`; - serverSubtitle.textContent = text; + let parts = "trx-server"; + if (update.server_version) parts += ` v${update.server_version}`; + if (update.server_callsign) { + const cs = update.server_callsign; + serverSubtitle.innerHTML = `${parts} hosted by ${cs}`; + document.title = `${cs} - ${originalTitle}`; + } else { + serverSubtitle.textContent = parts; + } } setDisabled(false); if (update.info && update.info.capabilities && Array.isArray(update.info.capabilities.supported_modes)) { @@ -280,8 +287,8 @@ function render(update) { if (typeof update.clients === "number") lastClientCount = update.clients; powerHint.textContent = readyText(); - const locked = update.status && update.status.lock === true; - lockBtn.textContent = locked ? "Unlock" : "Lock"; + lastLocked = update.status && update.status.lock === true; + lockBtn.textContent = lastLocked ? "Unlock" : "Lock"; const tx = update.status && update.status.tx ? update.status.tx : null; txMeters.style.display = ""; @@ -462,6 +469,7 @@ const jogUpBtn = document.getElementById("jog-up"); const jogStepEl = document.getElementById("jog-step"); async function jogFreq(direction) { + if (lastLocked) { showHint("Locked", 1500); return; } if (lastFreqHz === null) return; const newHz = lastFreqHz + direction * jogStep; if (!freqAllowed(newHz)) { diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index 01518dd..094b6b8 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -2,7 +2,7 @@ - {pkg} v{ver} status + {pkg} v{ver} diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css index 4a7bcdc..cc4d256 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css @@ -19,7 +19,7 @@ body { font-family: sans-serif; margin: 0; min-height: 100vh; display: flex; ali .label { color: var(--text-muted); font-size: 0.9rem; margin-bottom: 6px; display: block; } .status { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.1rem 1rem; } input.status-input, select.status-input { width: 100%; padding: 0.45rem 0.5rem; font-size: 1rem; border: 1px solid var(--border-light); border-radius: 6px; background: var(--input-bg); color: var(--text); } -#freq { font-family: 'DSEG14 Classic', monospace; font-size: 2rem; padding: 0.5rem 0.6rem; letter-spacing: 0.05em; } +#freq { font-family: 'DSEG14 Classic', monospace; font-size: 2rem; padding: 0.5rem 0.6rem; letter-spacing: 0.05em; text-align: center; } .controls-row { display: grid; grid-template-columns: 1fr 1fr; @@ -140,6 +140,8 @@ small { color: var(--text-muted); } .logo-bg { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; opacity: 0.2; } .logo-bg img { max-width: 50%; max-height: 50%; filter: drop-shadow(0 4px 12px rgba(0,0,0,0.35)); } .subtitle { color: var(--text-muted); font-size: 0.95rem; } +.subtitle a { color: var(--accent-green); text-decoration: none; } +.subtitle a:hover { text-decoration: underline; } .band-tag { display: inline-block; padding: 2px 6px; border-radius: 6px; background: var(--btn-bg); color: var(--text); font-size: 0.82rem; border: 1px solid var(--border-light); margin-left: 6px; } .signal { display: flex; gap: 0.6rem; align-items: center; } .signal-bar { flex: 1 1 auto; height: 12px; border-radius: 999px; background: var(--btn-bg); border: 1px solid var(--border-light); overflow: hidden; }