[fix](trx-frontend-http): uniform buttons, jog wheel, VFO picker, signal graph, and client count

Reorganize layout: frequency row with jog wheel on top, mode and
transmit/power side by side below. Replace VFO text box with segmented
picker. Add rolling signal history canvas. Track connected SSE clients
and display count in status hint. Unify button heights and add Enter
key support for TX limit input.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
2026-02-08 09:53:33 +01:00
parent b142d68ca2
commit 37c36d196e
5 changed files with 412 additions and 61 deletions
@@ -19,8 +19,117 @@ 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); }
.vfo-box { width: 100%; min-height: 2.6rem; padding: 0.45rem 0.5rem; border: 1px solid var(--border-light); border-radius: 6px; background: var(--input-bg); color: var(--text); white-space: pre-line; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
button { padding: 0.5rem 0.9rem; border-radius: 6px; border: 1px solid var(--btn-border); background: var(--btn-bg); color: var(--text); cursor: pointer; height: 2.4rem; }
.controls-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
align-items: start;
}
.btn-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
}
.btn-grid button { width: 100%; height: 2.6rem; }
.jog-container {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0.6rem;
}
.jog-wheel {
width: 52px;
height: 52px;
border-radius: 50%;
background: radial-gradient(circle at 40% 35%, #2a3444, #1a2230);
border: 2px solid var(--border-light);
position: relative;
cursor: grab;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.05);
user-select: none;
-webkit-user-select: none;
touch-action: none;
}
.jog-indicator {
position: absolute;
width: 4px;
height: 10px;
background: var(--accent-green);
border-radius: 2px;
top: 4px;
left: 50%;
transform-origin: 50% 22px;
transform: translateX(-50%);
pointer-events: none;
}
.jog-btn {
width: 2.2rem;
height: 2.2rem;
font-size: 1.2rem;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
flex-shrink: 0;
}
.jog-step {
display: flex;
border: 1px solid var(--border-light);
border-radius: 6px;
overflow: hidden;
margin-left: 0.3rem;
}
.jog-step button {
border: none;
border-right: 1px solid var(--border-light);
border-radius: 0;
height: 2rem;
padding: 0 0.55rem;
font-size: 0.78rem;
background: var(--input-bg);
color: var(--text-muted);
cursor: pointer;
}
.jog-step button:last-child { border-right: none; }
.jog-step button.active {
background: var(--btn-bg);
color: var(--accent-green);
font-weight: 600;
}
.vfo-picker {
display: flex;
border: 1px solid var(--border-light);
border-radius: 6px;
overflow: hidden;
}
.vfo-picker button {
flex: 1;
border: none;
border-right: 1px solid var(--border-light);
border-radius: 0;
height: 2.6rem;
background: var(--input-bg);
color: var(--text-muted);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.85rem;
}
.vfo-picker button:last-child { border-right: none; }
.vfo-picker button.active {
background: var(--btn-bg);
color: var(--accent-green);
font-weight: 600;
}
#signal-graph {
width: 100%;
height: 60px;
margin-top: 0.4rem;
border-radius: 6px;
background: var(--input-bg);
border: 1px solid var(--border-light);
}
button { padding: 0.5rem 0.9rem; border-radius: 6px; border: 1px solid var(--btn-border); background: var(--btn-bg); color: var(--text); cursor: pointer; height: 2.6rem; }
button:disabled { opacity: 0.6; cursor: not-allowed; }
.hint { color: var(--text-muted); font-size: 0.85rem; }
.inline { display: flex; gap: 0.5rem; align-items: center; }
@@ -51,4 +160,9 @@ button:focus-visible, input:focus-visible, select:focus-visible {
.card { padding: 1rem; }
button { min-height: 2.8rem; font-size: 0.95rem; }
input.status-input, select.status-input { font-size: 1.1rem; }
.controls-row { grid-template-columns: 1fr; }
.jog-container { flex-wrap: wrap; }
.vfo-picker { flex-direction: column; }
.vfo-picker button { border-right: none; border-bottom: 1px solid var(--border-light); }
.vfo-picker button:last-child { border-bottom: none; }
}