[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>
This commit is contained in:
@@ -176,6 +176,8 @@ pub struct FrontendRuntimeContext {
|
||||
pub remote_rigs: Arc<Mutex<Vec<RemoteRigEntry>>>,
|
||||
/// Owner callsign from trx-client config/CLI for frontend display.
|
||||
pub owner_callsign: Option<String>,
|
||||
/// Optional website URL for the web UI header title link.
|
||||
pub owner_website_url: Option<String>,
|
||||
/// Latest spectrum frame from the active SDR rig; None for non-SDR backends.
|
||||
pub spectrum: Arc<Mutex<SharedSpectrum>>,
|
||||
}
|
||||
@@ -208,6 +210,7 @@ impl FrontendRuntimeContext {
|
||||
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
||||
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
||||
owner_callsign: None,
|
||||
owner_website_url: None,
|
||||
spectrum: Arc::new(Mutex::new(SharedSpectrum::default())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,6 +1265,7 @@ let serverVersion = null;
|
||||
let serverBuildDate = null;
|
||||
let serverCallsign = null;
|
||||
let ownerCallsign = null;
|
||||
let ownerWebsiteUrl = null;
|
||||
let serverRigs = [];
|
||||
let serverActiveRigId = null;
|
||||
let serverLat = null;
|
||||
@@ -1282,11 +1283,26 @@ function updateFooterBuildInfo() {
|
||||
function updateTitle() {
|
||||
const titleEl = document.getElementById("rig-title");
|
||||
if (titleEl) {
|
||||
titleEl.textContent = serverVersion ? `trx-rs v${serverVersion}` : "trx-rs";
|
||||
if (ownerWebsiteUrl) {
|
||||
const label = ownerCallsign || displayLabelFromUrl(ownerWebsiteUrl);
|
||||
titleEl.innerHTML =
|
||||
`<a class="title-link" href="${escapeMapHtml(ownerWebsiteUrl)}" target="_blank" rel="noopener">${escapeMapHtml(label)}</a>`;
|
||||
} else {
|
||||
titleEl.textContent = serverVersion ? `trx-rs v${serverVersion}` : "trx-rs";
|
||||
}
|
||||
}
|
||||
updateDocumentTitle(lastSpectrumData?.rds ?? null);
|
||||
}
|
||||
|
||||
function displayLabelFromUrl(url) {
|
||||
try {
|
||||
const host = new URL(url).hostname.replace(/^www\./i, "");
|
||||
return host || url;
|
||||
} catch (_e) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
function render(update) {
|
||||
if (!update) return;
|
||||
if (update.server_version) serverVersion = update.server_version;
|
||||
@@ -1295,6 +1311,9 @@ function render(update) {
|
||||
if (typeof update.owner_callsign === "string" && update.owner_callsign.length > 0) {
|
||||
ownerCallsign = update.owner_callsign;
|
||||
}
|
||||
if (typeof update.owner_website_url === "string" && update.owner_website_url.length > 0) {
|
||||
ownerWebsiteUrl = update.owner_website_url;
|
||||
}
|
||||
if (update.server_latitude != null) serverLat = update.server_latitude;
|
||||
if (update.server_longitude != null) serverLon = update.server_longitude;
|
||||
if (typeof update.initial_map_zoom === "number" && Number.isFinite(update.initial_map_zoom)) {
|
||||
|
||||
@@ -508,6 +508,14 @@ small { color: var(--text-muted); }
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
.title { font-size: 1.4rem; font-weight: 700; display: inline-flex; align-items: center; gap: 0.35rem; }
|
||||
.title-link {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.title-link:hover {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.14em;
|
||||
}
|
||||
.overview-strip {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
@@ -36,6 +36,7 @@ struct FrontendMeta {
|
||||
active_rig_id: Option<String>,
|
||||
rig_ids: Vec<String>,
|
||||
owner_callsign: Option<String>,
|
||||
owner_website_url: Option<String>,
|
||||
show_sdr_gain_control: bool,
|
||||
initial_map_zoom: u8,
|
||||
}
|
||||
@@ -82,6 +83,9 @@ fn inject_frontend_meta(json: &str, meta: FrontendMeta) -> String {
|
||||
if let Some(owner) = meta.owner_callsign {
|
||||
map.insert("owner_callsign".to_string(), serde_json::json!(owner));
|
||||
}
|
||||
if let Some(url) = meta.owner_website_url {
|
||||
map.insert("owner_website_url".to_string(), serde_json::json!(url));
|
||||
}
|
||||
map.insert(
|
||||
"show_sdr_gain_control".to_string(),
|
||||
serde_json::json!(meta.show_sdr_gain_control),
|
||||
@@ -105,6 +109,7 @@ fn frontend_meta_from_context(
|
||||
active_rig_id: active_rig_id_from_context(context),
|
||||
rig_ids: rig_ids_from_context(context),
|
||||
owner_callsign: owner_callsign_from_context(context),
|
||||
owner_website_url: owner_website_url_from_context(context),
|
||||
show_sdr_gain_control: show_sdr_gain_control_from_context(context),
|
||||
initial_map_zoom: initial_map_zoom_from_context(context),
|
||||
}
|
||||
@@ -140,6 +145,10 @@ fn owner_callsign_from_context(context: &FrontendRuntimeContext) -> Option<Strin
|
||||
context.owner_callsign.clone()
|
||||
}
|
||||
|
||||
fn owner_website_url_from_context(context: &FrontendRuntimeContext) -> Option<String> {
|
||||
context.owner_website_url.clone()
|
||||
}
|
||||
|
||||
fn show_sdr_gain_control_from_context(context: &FrontendRuntimeContext) -> bool {
|
||||
context.http_show_sdr_gain_control
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user