[fix](trx-frontend-http): drop the rig description from the top bar #26
@@ -2013,7 +2013,6 @@ var signalSplitValueEl = document.getElementById("signal-split-value");
|
|||||||
var overviewPeakHoldEl = document.getElementById("overview-peak-hold");
|
var overviewPeakHoldEl = document.getElementById("overview-peak-hold");
|
||||||
var themeToggleBtn = document.getElementById("theme-toggle");
|
var themeToggleBtn = document.getElementById("theme-toggle");
|
||||||
var headerRigSwitchSelect = document.getElementById("header-rig-switch-select");
|
var headerRigSwitchSelect = document.getElementById("header-rig-switch-select");
|
||||||
var headerRigSummary = document.getElementById("header-rig-summary");
|
|
||||||
var headerStylePickSelect = document.getElementById("header-style-pick-select");
|
var headerStylePickSelect = document.getElementById("header-style-pick-select");
|
||||||
var rdsPsOverlay = document.getElementById("rds-ps-overlay");
|
var rdsPsOverlay = document.getElementById("rds-ps-overlay");
|
||||||
var tabMainEl = document.getElementById("tab-main");
|
var tabMainEl = document.getElementById("tab-main");
|
||||||
@@ -2730,19 +2729,6 @@ function populateRigPicker(selectEl, rigIds, activeRigId, disabled) {
|
|||||||
}
|
}
|
||||||
selectEl.disabled = disabled;
|
selectEl.disabled = disabled;
|
||||||
}
|
}
|
||||||
function updateRigIdentitySummary(rigId, pending = false) {
|
|
||||||
if (!headerRigSummary) return;
|
|
||||||
const rig = serverRigs.find((entry) => entry?.remote === rigId);
|
|
||||||
if (!rig) {
|
|
||||||
headerRigSummary.textContent = pending ? "Switching rigs…" : "No rig details available";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hardware = [rig.manufacturer, rig.model].map((value) => String(value || "").trim()).filter(Boolean).join(" ") || rig.remote;
|
|
||||||
const modes = Array.isArray(rig.supported_modes) ? rig.supported_modes.map(normalizeMode).filter(Boolean) : [];
|
|
||||||
const features = [rig.tx ? "TX" : "RX", rig.filter_controls ? "SDR filters" : null, ...modes.slice(0, 5)];
|
|
||||||
if (modes.length > 5) features.push(`+${modes.length - 5} modes`);
|
|
||||||
headerRigSummary.textContent = `${pending ? "Switching to " : ""}${hardware} · ${features.filter(Boolean).join(" · ")}`;
|
|
||||||
}
|
|
||||||
function updateRigSubtitle(activeRigId) {
|
function updateRigSubtitle(activeRigId) {
|
||||||
if (!rigSubtitle) return;
|
if (!rigSubtitle) return;
|
||||||
const name = activeRigId && lastRigDisplayNames[activeRigId] || activeRigId || "--";
|
const name = activeRigId && lastRigDisplayNames[activeRigId] || activeRigId || "--";
|
||||||
@@ -2773,7 +2759,6 @@ function applyRigList(activeRigId, rigIds, displayNames = {}) {
|
|||||||
const disableSwitch = lastRigIds.length === 0 || !authRole || authRole === "rx";
|
const disableSwitch = lastRigIds.length === 0 || !authRole || authRole === "rx";
|
||||||
populateRigPicker(headerRigSwitchSelect, lastRigIds, lastActiveRigId, disableSwitch);
|
populateRigPicker(headerRigSwitchSelect, lastRigIds, lastActiveRigId, disableSwitch);
|
||||||
updateRigSubtitle(lastActiveRigId);
|
updateRigSubtitle(lastActiveRigId);
|
||||||
updateRigIdentitySummary(lastActiveRigId);
|
|
||||||
window.trxUi?.setActiveRig(lastActiveRigId);
|
window.trxUi?.setActiveRig(lastActiveRigId);
|
||||||
if (rigListChanged) {
|
if (rigListChanged) {
|
||||||
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
||||||
@@ -5034,7 +5019,7 @@ async function switchRigFromSelect(selectEl) {
|
|||||||
rigSwitchInProgress = true;
|
rigSwitchInProgress = true;
|
||||||
setControlPending(selectEl, true);
|
setControlPending(selectEl, true);
|
||||||
selectEl.closest(".header-rig-switch")?.classList.add("is-switching");
|
selectEl.closest(".header-rig-switch")?.classList.add("is-switching");
|
||||||
updateRigIdentitySummary(nextRig, true);
|
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
||||||
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
||||||
try {
|
try {
|
||||||
const sidParam = sseSessionId ? `&session_id=${encodeURIComponent(sseSessionId)}` : "";
|
const sidParam = sseSessionId ? `&session_id=${encodeURIComponent(sseSessionId)}` : "";
|
||||||
@@ -5042,7 +5027,6 @@ async function switchRigFromSelect(selectEl) {
|
|||||||
lastActiveRigId = nextRig;
|
lastActiveRigId = nextRig;
|
||||||
resetDecoderStateOnRigSwitch();
|
resetDecoderStateOnRigSwitch();
|
||||||
updateRigSubtitle(lastActiveRigId);
|
updateRigSubtitle(lastActiveRigId);
|
||||||
updateRigIdentitySummary(lastActiveRigId);
|
|
||||||
window.trxUi?.setActiveRig(lastActiveRigId);
|
window.trxUi?.setActiveRig(lastActiveRigId);
|
||||||
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
||||||
window.trx.modules.backgroundDecode?.setRig(lastActiveRigId);
|
window.trx.modules.backgroundDecode?.setRig(lastActiveRigId);
|
||||||
@@ -5061,7 +5045,6 @@ async function switchRigFromSelect(selectEl) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("select_rig failed:", err);
|
console.error("select_rig failed:", err);
|
||||||
selectEl.value = prevRig || "";
|
selectEl.value = prevRig || "";
|
||||||
updateRigIdentitySummary(prevRig);
|
|
||||||
window.trxUi?.notify("Rig could not be switched", { kind: "error" });
|
window.trxUi?.notify("Rig could not be switched", { kind: "error" });
|
||||||
} finally {
|
} finally {
|
||||||
rigSwitchInProgress = false;
|
rigSwitchInProgress = false;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<div class="tab-bar-nav" aria-label="Primary navigation">
|
<div class="tab-bar-nav" aria-label="Primary navigation">
|
||||||
<button class="tab active" data-tab="main">
|
<button class="tab active" data-tab="main">
|
||||||
<svg class="tab-icon" aria-hidden="true"><use href="#icon-home"/></svg>
|
<svg class="tab-icon" aria-hidden="true"><use href="#icon-home"/></svg>
|
||||||
<span class="tab-label">Main</span>
|
<span class="tab-label">Radio</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" data-tab="bookmarks">
|
<button class="tab" data-tab="bookmarks">
|
||||||
<svg class="tab-icon" aria-hidden="true"><use href="#icon-bookmark"/></svg>
|
<svg class="tab-icon" aria-hidden="true"><use href="#icon-bookmark"/></svg>
|
||||||
@@ -85,7 +85,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<button id="header-rec-btn" class="header-bar-btn header-rec-btn" type="button" aria-label="Toggle recording" title="Toggle recording">REC</button>
|
<button id="header-rec-btn" class="header-bar-btn header-rec-btn" type="button" aria-label="Toggle recording" title="Toggle recording">REC</button>
|
||||||
<div class="header-rig-switch">
|
<div class="header-rig-switch">
|
||||||
<select id="header-rig-switch-select" aria-label="Select active rig"></select>
|
<select id="header-rig-switch-select" aria-label="Select active rig"></select>
|
||||||
<span id="header-rig-summary" class="header-rig-summary" aria-live="polite"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="header-style-pick">
|
<div class="header-style-pick">
|
||||||
<select id="header-style-pick-select" aria-label="Select UI style">
|
<select id="header-style-pick-select" aria-label="Select UI style">
|
||||||
|
|||||||
@@ -1419,18 +1419,6 @@ small { color: var(--text-muted); }
|
|||||||
gap: 0.4rem;
|
gap: 0.4rem;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.header-rig-summary {
|
|
||||||
display: block;
|
|
||||||
max-width: 12rem;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
min-width: 0;
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: var(--fs-xs);
|
|
||||||
line-height: 1.35;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.header-rig-switch select {
|
.header-rig-switch select {
|
||||||
min-width: 8rem;
|
min-width: 8rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
@@ -1564,6 +1552,12 @@ small { color: var(--text-muted); }
|
|||||||
background: color-mix(in srgb, var(--border-light) 70%, transparent);
|
background: color-mix(in srgb, var(--border-light) 70%, transparent);
|
||||||
}
|
}
|
||||||
.tab-bar-nav .tab { flex: 0 0 auto; }
|
.tab-bar-nav .tab { flex: 0 0 auto; }
|
||||||
|
/* Icons before scrolling: every tab already carries one, and four icons plus
|
||||||
|
* More always fit, so the strip never has to hide a destination. */
|
||||||
|
@media (max-width: 1180px) and (min-width: 701px) {
|
||||||
|
.tab-bar-nav .tab .tab-label { display: none; }
|
||||||
|
.tab-bar-nav .tab { padding: 0.5rem 0.6rem; }
|
||||||
|
}
|
||||||
.tab {
|
.tab {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -3094,9 +3088,22 @@ body[data-operator-layout="broadcast"] #cw-bar-overlay {
|
|||||||
body[data-operator-layout="broadcast"] .controls-row { grid-template-columns: 1fr auto; }
|
body[data-operator-layout="broadcast"] .controls-row { grid-template-columns: 1fr auto; }
|
||||||
body[data-operator-layout="broadcast"] #wfm-controls-col { grid-column: 1 / -1; }
|
body[data-operator-layout="broadcast"] #wfm-controls-col { grid-column: 1 / -1; }
|
||||||
}
|
}
|
||||||
.mobile-more-btn, .mobile-more-menu, .decoder-tab-select { display: none; }
|
/* One navigation model at every width. Statistics, Recorder, Settings and
|
||||||
|
* About are occasional destinations: they live behind More rather than
|
||||||
|
* competing with the operating tabs for the row and then scrolling out of
|
||||||
|
* reach. The mobile layout already grouped them this way; the desktop strip
|
||||||
|
* now matches it, which is why the tab strip no longer needs to scroll. */
|
||||||
|
.tab-bar-nav .tab[data-tab="statistics"],
|
||||||
|
.tab-bar-nav .tab[data-tab="recorder"],
|
||||||
|
.tab-bar-nav .tab[data-tab="settings"],
|
||||||
|
.tab-bar-nav .tab[data-tab="about"] { display: none; }
|
||||||
|
.mobile-more-btn { display: flex; flex: 0 0 auto; }
|
||||||
|
.mobile-more-menu, .decoder-tab-select { display: none; }
|
||||||
|
.tab-bar-nav { position: relative; }
|
||||||
.mobile-more-menu {
|
.mobile-more-menu {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
|
top: calc(100% + 0.4rem);
|
||||||
|
right: 0;
|
||||||
right: max(0.75rem, env(safe-area-inset-right));
|
right: max(0.75rem, env(safe-area-inset-right));
|
||||||
bottom: calc(5.4rem + env(safe-area-inset-bottom));
|
bottom: calc(5.4rem + env(safe-area-inset-bottom));
|
||||||
z-index: 80;
|
z-index: 80;
|
||||||
@@ -3293,6 +3300,12 @@ body[data-operator-layout="broadcast"] #cw-bar-overlay {
|
|||||||
.tab[data-tab="statistics"], .tab[data-tab="recorder"],
|
.tab[data-tab="statistics"], .tab[data-tab="recorder"],
|
||||||
.tab[data-tab="settings"], .tab[data-tab="about"] { display: none; }
|
.tab[data-tab="settings"], .tab[data-tab="about"] { display: none; }
|
||||||
.mobile-more-btn { display: flex; }
|
.mobile-more-btn { display: flex; }
|
||||||
|
.mobile-more-menu {
|
||||||
|
position: fixed;
|
||||||
|
top: auto;
|
||||||
|
right: max(0.75rem, env(safe-area-inset-right));
|
||||||
|
bottom: calc(5.4rem + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
.mobile-more-btn[aria-expanded="true"] {
|
.mobile-more-btn[aria-expanded="true"] {
|
||||||
color: var(--accent-text);
|
color: var(--accent-text);
|
||||||
background: color-mix(in srgb, var(--accent-green) 10%, transparent);
|
background: color-mix(in srgb, var(--accent-green) 10%, transparent);
|
||||||
@@ -3332,8 +3345,6 @@ body[data-operator-layout="broadcast"] #cw-bar-overlay {
|
|||||||
width: auto;
|
width: auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
/* Rig hardware/feature detail is on the left subtitle and the About tab. */
|
|
||||||
.header-rig-summary { display: none; }
|
|
||||||
.header-bar-btn {
|
.header-bar-btn {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@@ -724,7 +724,6 @@ const signalSplitValueEl = document.getElementById("signal-split-value");
|
|||||||
const overviewPeakHoldEl = document.getElementById("overview-peak-hold") as HTMLInputElement | null;
|
const overviewPeakHoldEl = document.getElementById("overview-peak-hold") as HTMLInputElement | null;
|
||||||
const themeToggleBtn = document.getElementById("theme-toggle") as HTMLButtonElement | null;
|
const themeToggleBtn = document.getElementById("theme-toggle") as HTMLButtonElement | null;
|
||||||
const headerRigSwitchSelect = document.getElementById("header-rig-switch-select") as HTMLSelectElement | null;
|
const headerRigSwitchSelect = document.getElementById("header-rig-switch-select") as HTMLSelectElement | null;
|
||||||
const headerRigSummary = document.getElementById("header-rig-summary");
|
|
||||||
const headerStylePickSelect = document.getElementById("header-style-pick-select") as HTMLSelectElement | null;
|
const headerStylePickSelect = document.getElementById("header-style-pick-select") as HTMLSelectElement | null;
|
||||||
const rdsPsOverlay = document.getElementById("rds-ps-overlay");
|
const rdsPsOverlay = document.getElementById("rds-ps-overlay");
|
||||||
const tabMainEl = document.getElementById("tab-main");
|
const tabMainEl = document.getElementById("tab-main");
|
||||||
@@ -1371,20 +1370,6 @@ function populateRigPicker(selectEl: HTMLSelectElement | null, rigIds: string[],
|
|||||||
selectEl.disabled = disabled;
|
selectEl.disabled = disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRigIdentitySummary(rigId: string | null, pending = false) {
|
|
||||||
if (!headerRigSummary) return;
|
|
||||||
const rig = serverRigs.find((entry) => entry?.remote === rigId);
|
|
||||||
if (!rig) {
|
|
||||||
headerRigSummary.textContent = pending ? "Switching rigs…" : "No rig details available";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hardware = [rig.manufacturer, rig.model].map(value => String(value || "").trim()).filter(Boolean).join(" ") || rig.remote;
|
|
||||||
const modes = Array.isArray(rig.supported_modes) ? rig.supported_modes.map(normalizeMode).filter(Boolean) : [];
|
|
||||||
const features = [rig.tx ? "TX" : "RX", rig.filter_controls ? "SDR filters" : null, ...modes.slice(0, 5)];
|
|
||||||
if (modes.length > 5) features.push(`+${modes.length - 5} modes`);
|
|
||||||
headerRigSummary.textContent = `${pending ? "Switching to " : ""}${hardware} · ${features.filter(Boolean).join(" · ")}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateRigSubtitle(activeRigId: string | null) {
|
function updateRigSubtitle(activeRigId: string | null) {
|
||||||
if (!rigSubtitle) return;
|
if (!rigSubtitle) return;
|
||||||
const name = (activeRigId && lastRigDisplayNames[activeRigId]) || activeRigId || "--";
|
const name = (activeRigId && lastRigDisplayNames[activeRigId]) || activeRigId || "--";
|
||||||
@@ -1421,7 +1406,6 @@ function applyRigList(activeRigId: string | null, rigIds: string[], displayNames
|
|||||||
const disableSwitch = lastRigIds.length === 0 || !authRole || authRole === "rx";
|
const disableSwitch = lastRigIds.length === 0 || !authRole || authRole === "rx";
|
||||||
populateRigPicker(headerRigSwitchSelect, lastRigIds, lastActiveRigId, disableSwitch);
|
populateRigPicker(headerRigSwitchSelect, lastRigIds, lastActiveRigId, disableSwitch);
|
||||||
updateRigSubtitle(lastActiveRigId);
|
updateRigSubtitle(lastActiveRigId);
|
||||||
updateRigIdentitySummary(lastActiveRigId);
|
|
||||||
window.trxUi?.setActiveRig(lastActiveRigId);
|
window.trxUi?.setActiveRig(lastActiveRigId);
|
||||||
if (rigListChanged) {
|
if (rigListChanged) {
|
||||||
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
||||||
@@ -4023,7 +4007,7 @@ async function switchRigFromSelect(selectEl: HTMLSelectElement) {
|
|||||||
rigSwitchInProgress = true;
|
rigSwitchInProgress = true;
|
||||||
setControlPending(selectEl, true);
|
setControlPending(selectEl, true);
|
||||||
selectEl.closest(".header-rig-switch")?.classList.add("is-switching");
|
selectEl.closest(".header-rig-switch")?.classList.add("is-switching");
|
||||||
updateRigIdentitySummary(nextRig, true);
|
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
||||||
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
showHint(`Switching to ${lastRigDisplayNames[nextRig] || nextRig}…`);
|
||||||
try {
|
try {
|
||||||
const sidParam = sseSessionId ? `&session_id=${encodeURIComponent(sseSessionId)}` : "";
|
const sidParam = sseSessionId ? `&session_id=${encodeURIComponent(sseSessionId)}` : "";
|
||||||
@@ -4031,7 +4015,6 @@ async function switchRigFromSelect(selectEl: HTMLSelectElement) {
|
|||||||
lastActiveRigId = nextRig;
|
lastActiveRigId = nextRig;
|
||||||
resetDecoderStateOnRigSwitch();
|
resetDecoderStateOnRigSwitch();
|
||||||
updateRigSubtitle(lastActiveRigId);
|
updateRigSubtitle(lastActiveRigId);
|
||||||
updateRigIdentitySummary(lastActiveRigId);
|
|
||||||
window.trxUi?.setActiveRig(lastActiveRigId);
|
window.trxUi?.setActiveRig(lastActiveRigId);
|
||||||
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
window.trx.modules.scheduler?.setRig(lastActiveRigId);
|
||||||
window.trx.modules.backgroundDecode?.setRig(lastActiveRigId);
|
window.trx.modules.backgroundDecode?.setRig(lastActiveRigId);
|
||||||
@@ -4050,7 +4033,6 @@ async function switchRigFromSelect(selectEl: HTMLSelectElement) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("select_rig failed:", err);
|
console.error("select_rig failed:", err);
|
||||||
selectEl.value = prevRig || "";
|
selectEl.value = prevRig || "";
|
||||||
updateRigIdentitySummary(prevRig);
|
|
||||||
window.trxUi?.notify("Rig could not be switched", { kind: "error" });
|
window.trxUi?.notify("Rig could not be switched", { kind: "error" });
|
||||||
} finally {
|
} finally {
|
||||||
rigSwitchInProgress = false;
|
rigSwitchInProgress = false;
|
||||||
|
|||||||
@@ -184,7 +184,10 @@ try {
|
|||||||
await page.locator('.tab[data-tab="main"]').click();
|
await page.locator('.tab[data-tab="main"]').click();
|
||||||
assert.equal(new URL(page.url()).pathname, "/");
|
assert.equal(new URL(page.url()).pathname, "/");
|
||||||
|
|
||||||
await page.locator('.tab[data-tab="about"]').click();
|
// About is an occasional destination, so it lives behind More at every
|
||||||
|
// width rather than in the operating tab strip.
|
||||||
|
await page.locator("#mobile-more-btn").click();
|
||||||
|
await page.locator('[data-navigate-tab="about"]').click();
|
||||||
await page.locator("#tab-about").waitFor({ state: "visible" });
|
await page.locator("#tab-about").waitFor({ state: "visible" });
|
||||||
assert.equal(new URL(page.url()).pathname, "/about");
|
assert.equal(new URL(page.url()).pathname, "/about");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user