[fix](trx-frontend): refine spectrum layout behavior
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -289,6 +289,7 @@ function applyCapabilities(caps) {
|
|||||||
if (centerFreqField) centerFreqField.style.display = "none";
|
if (centerFreqField) centerFreqField.style.display = "none";
|
||||||
stopSpectrumStreaming();
|
stopSpectrumStreaming();
|
||||||
}
|
}
|
||||||
|
scheduleSpectrumLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1653,6 +1654,8 @@ let serverLon = null;
|
|||||||
let initialMapZoom = 10;
|
let initialMapZoom = 10;
|
||||||
let spectrumCoverageMarginHz = 50_000;
|
let spectrumCoverageMarginHz = 50_000;
|
||||||
let spectrumUsableSpanRatio = 0.92;
|
let spectrumUsableSpanRatio = 0.92;
|
||||||
|
const DEFAULT_SPECTRUM_PLOT_HEIGHT_PX = 160;
|
||||||
|
let spectrumLayoutPending = false;
|
||||||
|
|
||||||
function updateFooterBuildInfo() {
|
function updateFooterBuildInfo() {
|
||||||
const serverEl = document.getElementById("footer-server-build");
|
const serverEl = document.getElementById("footer-server-build");
|
||||||
@@ -1662,6 +1665,56 @@ function updateFooterBuildInfo() {
|
|||||||
serverEl.textContent = `trx-server v${ver} ${build}`;
|
serverEl.textContent = `trx-server v${ver} ${build}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scheduleSpectrumLayout() {
|
||||||
|
if (spectrumLayoutPending) return;
|
||||||
|
spectrumLayoutPending = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
spectrumLayoutPending = false;
|
||||||
|
updateSpectrumAutoHeight();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSpectrumAutoHeight() {
|
||||||
|
const root = document.documentElement;
|
||||||
|
const tabMainEl = document.getElementById("tab-main");
|
||||||
|
const contentEl = document.getElementById("content");
|
||||||
|
const spectrumPanelEl = document.getElementById("spectrum-panel");
|
||||||
|
const spectrumCanvasEl = document.getElementById("spectrum-canvas");
|
||||||
|
if (!root || !tabMainEl || !contentEl || !spectrumPanelEl || !spectrumCanvasEl) return;
|
||||||
|
|
||||||
|
const mainVisible = getComputedStyle(tabMainEl).display !== "none";
|
||||||
|
const contentVisible = getComputedStyle(contentEl).display !== "none";
|
||||||
|
const spectrumVisible = getComputedStyle(spectrumPanelEl).display !== "none";
|
||||||
|
const currentHeight = Math.max(
|
||||||
|
DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
||||||
|
Math.round(spectrumCanvasEl.clientHeight || DEFAULT_SPECTRUM_PLOT_HEIGHT_PX),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!mainVisible || !contentVisible || !spectrumVisible) {
|
||||||
|
root.style.setProperty("--spectrum-plot-height", `${DEFAULT_SPECTRUM_PLOT_HEIGHT_PX}px`);
|
||||||
|
if (currentHeight !== DEFAULT_SPECTRUM_PLOT_HEIGHT_PX && lastSpectrumData) {
|
||||||
|
scheduleSpectrumDraw();
|
||||||
|
scheduleOverviewDraw();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabBottom = tabMainEl.getBoundingClientRect().bottom;
|
||||||
|
const contentBottom = contentEl.getBoundingClientRect().bottom;
|
||||||
|
const slackPx = Math.floor(tabBottom - contentBottom);
|
||||||
|
const nextHeight = Math.max(
|
||||||
|
DEFAULT_SPECTRUM_PLOT_HEIGHT_PX,
|
||||||
|
currentHeight + slackPx - 2,
|
||||||
|
);
|
||||||
|
if (Math.abs(nextHeight - currentHeight) < 2) return;
|
||||||
|
|
||||||
|
root.style.setProperty("--spectrum-plot-height", `${nextHeight}px`);
|
||||||
|
if (lastSpectrumData) {
|
||||||
|
scheduleSpectrumDraw();
|
||||||
|
scheduleOverviewDraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateTitle() {
|
function updateTitle() {
|
||||||
const titleEl = document.getElementById("rig-title");
|
const titleEl = document.getElementById("rig-title");
|
||||||
if (titleEl) {
|
if (titleEl) {
|
||||||
@@ -1716,6 +1769,7 @@ function render(update) {
|
|||||||
) {
|
) {
|
||||||
spectrumUsableSpanRatio = Math.max(0.01, Math.min(1.0, Number(update.spectrum_usable_span_ratio)));
|
spectrumUsableSpanRatio = Math.max(0.01, Math.min(1.0, Number(update.spectrum_usable_span_ratio)));
|
||||||
}
|
}
|
||||||
|
scheduleSpectrumLayout();
|
||||||
updateTitle();
|
updateTitle();
|
||||||
updateFooterBuildInfo();
|
updateFooterBuildInfo();
|
||||||
|
|
||||||
@@ -2719,12 +2773,14 @@ document.querySelector(".tab-bar").addEventListener("click", (e) => {
|
|||||||
btn.classList.add("active");
|
btn.classList.add("active");
|
||||||
document.querySelectorAll(".tab-panel").forEach((p) => p.style.display = "none");
|
document.querySelectorAll(".tab-panel").forEach((p) => p.style.display = "none");
|
||||||
document.getElementById(`tab-${btn.dataset.tab}`).style.display = "";
|
document.getElementById(`tab-${btn.dataset.tab}`).style.display = "";
|
||||||
|
scheduleSpectrumLayout();
|
||||||
if (btn.dataset.tab === "map") {
|
if (btn.dataset.tab === "map") {
|
||||||
initAprsMap();
|
initAprsMap();
|
||||||
sizeAprsMapToViewport();
|
sizeAprsMapToViewport();
|
||||||
if (aprsMap) setTimeout(() => aprsMap.invalidateSize(), 50);
|
if (aprsMap) setTimeout(() => aprsMap.invalidateSize(), 50);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
window.addEventListener("resize", () => { scheduleSpectrumLayout(); });
|
||||||
|
|
||||||
// --- Auth startup sequence ---
|
// --- Auth startup sequence ---
|
||||||
async function initializeApp() {
|
async function initializeApp() {
|
||||||
@@ -4878,16 +4934,24 @@ function createBookmarkChip(bm, colorMap) {
|
|||||||
|
|
||||||
function updateSideBookmarkStack(container, bookmarks, colorMap) {
|
function updateSideBookmarkStack(container, bookmarks, colorMap) {
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
container.innerHTML = "";
|
const nextKey = Array.isArray(bookmarks) ? bookmarks.map((bm) => bm.id).join(",") : "";
|
||||||
if (!Array.isArray(bookmarks) || bookmarks.length === 0) {
|
if (!Array.isArray(bookmarks) || bookmarks.length === 0) {
|
||||||
|
if (container.dataset.bmKey) {
|
||||||
|
container.innerHTML = "";
|
||||||
|
container.dataset.bmKey = "";
|
||||||
|
}
|
||||||
container.classList.remove("bm-side-visible");
|
container.classList.remove("bm-side-visible");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.classList.add("bm-side-visible");
|
if (container.dataset.bmKey !== nextKey) {
|
||||||
for (const bm of bookmarks) {
|
container.dataset.bmKey = nextKey;
|
||||||
container.appendChild(createBookmarkChip(bm, colorMap));
|
container.innerHTML = "";
|
||||||
|
for (const bm of bookmarks) {
|
||||||
|
container.appendChild(createBookmarkChip(bm, colorMap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
container.classList.add("bm-side-visible");
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBookmarkAxis(range) {
|
function updateBookmarkAxis(range) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
--filter-border: #385577;
|
--filter-border: #385577;
|
||||||
--wavelength-fg: #8da3be;
|
--wavelength-fg: #8da3be;
|
||||||
--spectrum-bg: #0a0f18;
|
--spectrum-bg: #0a0f18;
|
||||||
|
--overview-plot-height: 160px;
|
||||||
--spectrum-plot-height: 160px;
|
--spectrum-plot-height: 160px;
|
||||||
--jog-wheel-size: 83.2px;
|
--jog-wheel-size: 83.2px;
|
||||||
--header-waterfall-overlap: 0rem;
|
--header-waterfall-overlap: 0rem;
|
||||||
@@ -525,10 +526,8 @@ small { color: var(--text-muted); }
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 1 auto;
|
|
||||||
min-height: 0;
|
|
||||||
gap: 0;
|
gap: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0.9rem;
|
||||||
}
|
}
|
||||||
#signal-overlay-canvas {
|
#signal-overlay-canvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -833,7 +832,7 @@ small { color: var(--text-muted); }
|
|||||||
}
|
}
|
||||||
#overview-canvas {
|
#overview-canvas {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: var(--spectrum-plot-height);
|
height: var(--overview-plot-height);
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.header-left {
|
.header-left {
|
||||||
@@ -914,12 +913,7 @@ small { color: var(--text-muted); }
|
|||||||
.meter-bar { flex: 1 1 auto; height: 12px; border-radius: 999px; background: var(--btn-bg); border: 1px solid var(--border-light); overflow: hidden; }
|
.meter-bar { flex: 1 1 auto; height: 12px; border-radius: 999px; background: var(--btn-bg); border: 1px solid var(--border-light); overflow: hidden; }
|
||||||
.meter-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-green), var(--accent-yellow), var(--accent-red)); transition: width 150ms ease; }
|
.meter-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-green), var(--accent-yellow), var(--accent-red)); transition: width 150ms ease; }
|
||||||
.meter-value { font-size: 0.95rem; color: var(--text-heading); min-width: 64px; text-align: right; }
|
.meter-value { font-size: 0.95rem; color: var(--text-heading); min-width: 64px; text-align: right; }
|
||||||
#tab-main {
|
#content { display: flex; flex-direction: column; gap: 1.1rem; min-height: 0; overflow: visible; }
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
#content { display: flex; flex: 1 1 auto; flex-direction: column; gap: 1.1rem; min-height: 0; overflow: visible; }
|
|
||||||
.tab-panel { flex: 1 1 auto; min-height: 0; overflow: visible; }
|
.tab-panel { flex: 1 1 auto; min-height: 0; overflow: visible; }
|
||||||
.tab-bar {
|
.tab-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1514,26 +1508,16 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
/* ── Spectrum display ─────────────────────────────────────────────────── */
|
/* ── Spectrum display ─────────────────────────────────────────────────── */
|
||||||
#spectrum-panel {
|
#spectrum-panel {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
flex: 1 1 auto;
|
|
||||||
min-height: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
.spectrum-wrap {
|
.spectrum-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
#spectrum-canvas {
|
#spectrum-canvas {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1 1 auto;
|
height: var(--spectrum-plot-height);
|
||||||
min-height: var(--spectrum-plot-height);
|
|
||||||
height: auto;
|
|
||||||
background: var(--spectrum-bg);
|
background: var(--spectrum-bg);
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: 6px 6px 0 0;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
@@ -1541,7 +1525,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
}
|
}
|
||||||
.spectrum-edge-shift {
|
.spectrum-edge-shift {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc((100% - 18px) / 2);
|
top: calc(var(--spectrum-plot-height) / 2);
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
z-index: 8;
|
z-index: 8;
|
||||||
width: 1.7rem;
|
width: 1.7rem;
|
||||||
@@ -1646,7 +1630,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
|||||||
}
|
}
|
||||||
.spectrum-bookmark-side {
|
.spectrum-bookmark-side {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc((100% - 18px) / 2);
|
top: calc(var(--spectrum-plot-height) / 2);
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
z-index: 7;
|
z-index: 7;
|
||||||
width: 7.25rem;
|
width: 7.25rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user