Spectrum control strip: one height, fields that hold their units, no staggering #45
@@ -0,0 +1,116 @@
|
|||||||
|
# Spectrum Controls — Visual Rework
|
||||||
|
|
||||||
|
The strip between the spectrum and the radio controls (`#spectrum-controls`)
|
||||||
|
holds eight controls in two groups. This proposes how it should *look*.
|
||||||
|
|
||||||
|
Every control stays, in its current order, with its current name and its
|
||||||
|
current behaviour. Nothing here changes what a button does, what commits when,
|
||||||
|
or what is stored. It is a styling and layout change.
|
||||||
|
|
||||||
|
*Status: implemented. Kept as the record of what was changed and why.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What it looks like now
|
||||||
|
|
||||||
|
```
|
||||||
|
Bandwidth [ 12 ] kHz [Set] [Auto BW] [Sweet-spot] Peak Hold [2 s] Floor [-115] dB Range [90] dB [Auto] Contrast [——●——] 1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Four problems, all of them visual:
|
||||||
|
|
||||||
|
**1. Four different control heights on one line.** The bare number inputs, the
|
||||||
|
buttons, the `select` and the range slider are each sized by their own rule, so
|
||||||
|
nothing shares a baseline and the row reads as a pile rather than a strip.
|
||||||
|
|
||||||
|
**2. Units are loose text.** `kHz`, `dB`, `dB` and the contrast value `1.0` are
|
||||||
|
text nodes sitting outside the control they belong to, separated from it by a
|
||||||
|
gap the same size as the gap between unrelated controls. The eye has to work
|
||||||
|
out which number owns which unit.
|
||||||
|
|
||||||
|
**3. A quarter of the strip is a hole.** `justify-content: space-between` puts
|
||||||
|
about 250 px of nothing in the middle at 1600 px, and the two groups read as
|
||||||
|
two unrelated things because the only thing between them is emptiness.
|
||||||
|
|
||||||
|
**4. The groups stagger between 1100 and 1400 px.** The bandwidth group wraps
|
||||||
|
to two lines while the level group stays on one, so the level group floats at a
|
||||||
|
height of its own, aligned with neither line of the group beside it. This is
|
||||||
|
the worst of it, and it happens at a common window width.
|
||||||
|
|
||||||
|
Two smaller things: 24 px controls are below any touch-target guideline, and
|
||||||
|
the contrast readout has no fixed width, so the row twitches as the value
|
||||||
|
changes between `1.0` and `0.9`.
|
||||||
|
|
||||||
|
## Proposed
|
||||||
|
|
||||||
|
**One control height, units inside their field, and a rule where the clusters
|
||||||
|
meet.**
|
||||||
|
|
||||||
|
- **A field is one box.** Label, value and unit share a single bordered box —
|
||||||
|
`Bandwidth │ 12.0 │ kHz` — so a number and its unit can never be read apart.
|
||||||
|
Fields, buttons, the peak-hold select and the contrast slider are all 1.7 rem
|
||||||
|
tall, on 44 px targets under a coarse pointer.
|
||||||
|
- **A rule, not a hole.** The two clusters are separated by a thin vertical
|
||||||
|
rule with normal spacing either side. The slack goes to a flexible spacer, so
|
||||||
|
the strip is left-aligned rather than pushed apart.
|
||||||
|
- **A cluster never splits.** Each cluster is `nowrap`; the container wraps. If
|
||||||
|
a cluster does not fit on the line it drops whole to the next one,
|
||||||
|
left-aligned with the one above. No staggering, at any width.
|
||||||
|
- **Rules fall away at line starts.** A cluster that begins a line has no rule
|
||||||
|
hanging off its left edge.
|
||||||
|
- **The contrast readout gets a fixed, tabular slot**, so the row is still.
|
||||||
|
|
||||||
|
Below the existing mobile breakpoint the strip already stacks; the same field
|
||||||
|
component applies there, which is most of what makes it look deliberate.
|
||||||
|
|
||||||
|
## What this does not change
|
||||||
|
|
||||||
|
`Set` stays. `Auto BW` and `Auto` keep their names, even though they mean
|
||||||
|
different things — that is a naming question, not a styling one. Sweet-spot
|
||||||
|
stays where it is and keeps its behaviour. Nothing gains or loses persistence.
|
||||||
|
Nothing moves into a popover, and no control is hidden behind a click.
|
||||||
|
|
||||||
|
Those are all worth arguing about separately; a note of them is at the end of
|
||||||
|
this file so the arguments are not lost.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
One pass, no behaviour touched:
|
||||||
|
|
||||||
|
1. `.spectrum-field` and `.spectrum-btn` in `style.css`, replacing the six
|
||||||
|
per-id rules (`#spectrum-bw-input`, `#spectrum-floor-input`,
|
||||||
|
`#spectrum-range-input`, `#spectrum-bw-label`, `#spectrum-floor-label`,
|
||||||
|
`#spectrum-range-label`) that currently repeat the same declarations.
|
||||||
|
2. Markup in `index.html`: the loose `kHz` / `dB` text nodes move inside their
|
||||||
|
label, which keeps every id and every event handler exactly where it is.
|
||||||
|
3. `#spectrum-controls` becomes a wrapping flex row with a spacer;
|
||||||
|
`#spectrum-bw-row` and `#spectrum-level-row` become `nowrap` clusters with a
|
||||||
|
left rule.
|
||||||
|
4. The mobile block in the media query drops the rules it no longer needs.
|
||||||
|
|
||||||
|
`app.ts` is not touched. Every id survives, so the existing handlers, the
|
||||||
|
`spectrum-layout.mjs` geometry test and the broadcast-layout highlight all keep
|
||||||
|
working.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
Extend `spectrum-layout.mjs`, which already measures this area:
|
||||||
|
|
||||||
|
- Every control in the strip shares one height, at 1600, 1200 and 900 px.
|
||||||
|
- No two clusters sit at different vertical offsets on the same line — the
|
||||||
|
staggering bug, asserted directly.
|
||||||
|
- The strip never overflows its container and never overlaps the hint line.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Noted for later, not proposed here
|
||||||
|
|
||||||
|
Behavioural observations from reading the code, kept so they are not lost:
|
||||||
|
|
||||||
|
- `Auto BW` (filter) and `Auto` (display scaling) are both called Auto, 600 px
|
||||||
|
apart.
|
||||||
|
- `Floor`, `Range` and `Contrast` are not persisted; `Peak Hold` is.
|
||||||
|
- `Auto` and `Auto BW` are one-shot: no state, nothing to turn off.
|
||||||
|
- `Sweet-spot` retunes the SDR and waits up to 1.4 s per candidate centre, with
|
||||||
|
no busy indication.
|
||||||
|
- Contrast resets on a double-click that nothing advertises.
|
||||||
@@ -163,13 +163,14 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<div id="spectrum-size-grip" title="Drag to resize spectrum height" aria-label="Resize spectrum height"></div>
|
<div id="spectrum-size-grip" title="Drag to resize spectrum height" aria-label="Resize spectrum height"></div>
|
||||||
<div id="spectrum-controls">
|
<div id="spectrum-controls">
|
||||||
<div id="spectrum-bw-row">
|
<div id="spectrum-bw-row">
|
||||||
<label id="spectrum-bw-label">Bandwidth <input type="number" id="spectrum-bw-input" value="" step="0.1" min="0.1" /> kHz</label>
|
<label id="spectrum-bw-label" class="spectrum-field"><span class="spectrum-field-name">Bandwidth</span><input type="number" id="spectrum-bw-input" value="" step="0.1" min="0.1" /><span class="spectrum-field-unit">kHz</span></label>
|
||||||
<button id="spectrum-bw-set-btn" type="button">Set</button>
|
<button id="spectrum-bw-set-btn" class="spectrum-btn" type="button">Set</button>
|
||||||
<button id="spectrum-bw-auto-btn" type="button">Auto BW</button>
|
<button id="spectrum-bw-auto-btn" class="spectrum-btn" type="button">Auto BW</button>
|
||||||
<button id="spectrum-bw-sweet-btn" type="button">Sweet-spot</button>
|
<button id="spectrum-bw-sweet-btn" class="spectrum-btn" type="button">Sweet-spot</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="spectrum-controls-spacer" aria-hidden="true"></div>
|
||||||
<div id="spectrum-level-row">
|
<div id="spectrum-level-row">
|
||||||
<label class="overview-control" id="spectrum-peak-hold-label">Peak Hold
|
<label class="overview-control spectrum-field" id="spectrum-peak-hold-label"><span class="spectrum-field-name">Peak Hold</span>
|
||||||
<select id="overview-peak-hold" class="status-input">
|
<select id="overview-peak-hold" class="status-input">
|
||||||
<option value="0">Off</option>
|
<option value="0">Off</option>
|
||||||
<option value="500">0.5 s</option>
|
<option value="500">0.5 s</option>
|
||||||
@@ -182,10 +183,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<option value="60000">60 s</option>
|
<option value="60000">60 s</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label id="spectrum-floor-label">Floor <input type="number" id="spectrum-floor-input" value="-115" step="5" /> dB</label>
|
<label id="spectrum-floor-label" class="spectrum-field"><span class="spectrum-field-name">Floor</span><input type="number" id="spectrum-floor-input" value="-115" step="5" /><span class="spectrum-field-unit">dB</span></label>
|
||||||
<label id="spectrum-range-label">Range <input type="number" id="spectrum-range-input" value="90" step="10" min="10" /> dB</label>
|
<label id="spectrum-range-label" class="spectrum-field"><span class="spectrum-field-name">Range</span><input type="number" id="spectrum-range-input" value="90" step="10" min="10" /><span class="spectrum-field-unit">dB</span></label>
|
||||||
<button id="spectrum-auto-btn" type="button">Auto</button>
|
<button id="spectrum-auto-btn" class="spectrum-btn" type="button">Auto</button>
|
||||||
<label id="spectrum-gamma-label">Contrast <input type="range" id="spectrum-gamma-input" min="0.2" max="3.0" step="0.1" value="1.0" /><span id="spectrum-gamma-value">1.0</span></label>
|
<label id="spectrum-gamma-label" class="spectrum-field"><span class="spectrum-field-name">Contrast</span><input type="range" id="spectrum-gamma-input" min="0.2" max="3.0" step="0.1" value="1.0" /><span id="spectrum-gamma-value" class="spectrum-field-value">1.0</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="spectrum-hint" class="spectrum-hint-mouse">Scroll to zoom · Ctrl+Scroll to tune · Drag to pan · Drag BW edges to resize · +/- zoom · Arrows pan · 0 reset</div>
|
<div id="spectrum-hint" class="spectrum-hint-mouse">Scroll to zoom · Ctrl+Scroll to tune · Drag to pan · Drag BW edges to resize · +/- zoom · Arrows pan · 0 reset</div>
|
||||||
|
|||||||
@@ -4131,47 +4131,6 @@ body[data-operator-layout="broadcast"] #cw-bar-overlay {
|
|||||||
.signal-measure #sig-result {
|
.signal-measure #sig-result {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
#spectrum-controls {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: 0.45rem;
|
|
||||||
padding-top: 0.45rem;
|
|
||||||
}
|
|
||||||
#spectrum-bw-row,
|
|
||||||
#spectrum-level-row {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.35rem 0.4rem;
|
|
||||||
}
|
|
||||||
#spectrum-bw-label,
|
|
||||||
#spectrum-floor-label,
|
|
||||||
#spectrum-range-label,
|
|
||||||
#spectrum-peak-hold-label {
|
|
||||||
flex: 1 1 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
#spectrum-gamma-label {
|
|
||||||
flex: 1 1 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
#spectrum-gamma-input {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 3rem;
|
|
||||||
}
|
|
||||||
#spectrum-bw-input,
|
|
||||||
#spectrum-floor-input,
|
|
||||||
#spectrum-range-input,
|
|
||||||
#overview-peak-hold {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 3rem;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
#spectrum-bw-set-btn,
|
|
||||||
#spectrum-bw-auto-btn,
|
|
||||||
#spectrum-bw-sweet-btn,
|
|
||||||
#spectrum-auto-btn {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
.spectrum-edge-shift {
|
.spectrum-edge-shift {
|
||||||
width: 0.95rem;
|
width: 0.95rem;
|
||||||
}
|
}
|
||||||
@@ -4821,111 +4780,166 @@ body[data-operator-layout="broadcast"] #cw-bar-overlay {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
/* ── Spectrum control strip ────────────────────────────────────────────
|
||||||
|
Two clusters of controls under the plot: the receiver's bandwidth on the
|
||||||
|
left, the display's levels on the right. Everything in here is one height
|
||||||
|
and one shape — a row whose controls each size themselves reads as a pile
|
||||||
|
rather than a strip.
|
||||||
|
|
||||||
|
The container wraps; a cluster does not. A cluster that cannot fit drops
|
||||||
|
whole to the next line and starts it left-aligned, rather than splitting and
|
||||||
|
leaving the cluster beside it floating at a height of its own, which is what
|
||||||
|
the two rows did to each other between 1100 and 1400 px. */
|
||||||
#spectrum-controls {
|
#spectrum-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
flex-wrap: wrap;
|
||||||
padding: 3px 4px 0;
|
padding: 3px 4px 0;
|
||||||
gap: 0.6rem;
|
gap: 0.35rem 0.5rem;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
#spectrum-bw-row {
|
#spectrum-bw-row,
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.4rem;
|
|
||||||
}
|
|
||||||
#spectrum-bw-label {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.3rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
#spectrum-bw-input {
|
|
||||||
width: 4.5rem;
|
|
||||||
padding: 1px 4px;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--input-bg);
|
|
||||||
color: var(--text);
|
|
||||||
text-align: right;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
|
||||||
#spectrum-bw-set-btn,
|
|
||||||
#spectrum-bw-auto-btn,
|
|
||||||
#spectrum-bw-sweet-btn {
|
|
||||||
height: 1.5rem;
|
|
||||||
min-height: 0;
|
|
||||||
padding: 0 8px;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
#spectrum-level-row {
|
#spectrum-level-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.4rem;
|
flex-wrap: nowrap;
|
||||||
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
#spectrum-floor-label {
|
/* Takes the slack, so the clusters reach the ends of a wide strip without
|
||||||
display: flex;
|
`space-between` opening a quarter-width hole in the middle of it. */
|
||||||
|
.spectrum-controls-spacer {
|
||||||
|
flex: 1 1 1.5rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A field is one box: name, value and unit share a border, so a number can
|
||||||
|
never be read apart from the unit it is in. */
|
||||||
|
.spectrum-field {
|
||||||
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.3rem;
|
gap: 0.3rem;
|
||||||
|
/* Border-box on both field and button, or the button's own border and
|
||||||
|
padding add to the height and the two end up a couple of pixels apart —
|
||||||
|
which is the pile-of-controls look this is meant to end. */
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 1.7rem;
|
||||||
|
padding: 0 0.4rem 0 0.5rem;
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--input-bg);
|
||||||
|
white-space: nowrap;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
#spectrum-floor-input {
|
.spectrum-field:focus-within {
|
||||||
width: 3.4rem;
|
border-color: color-mix(in srgb, var(--accent-green) 45%, var(--border-light));
|
||||||
padding: 1px 4px;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--input-bg);
|
|
||||||
color: var(--text);
|
|
||||||
text-align: right;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
}
|
||||||
#spectrum-range-label {
|
.spectrum-field-name {
|
||||||
display: flex;
|
font-size: 0.72rem;
|
||||||
align-items: center;
|
|
||||||
gap: 0.3rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
#spectrum-range-input {
|
/* Unit and readout hold a fixed, tabular slot: the row must not twitch as a
|
||||||
width: 3.4rem;
|
value goes from 1.0 to 0.9. */
|
||||||
padding: 1px 4px;
|
.spectrum-field-unit,
|
||||||
font-size: 0.75rem;
|
.spectrum-field-value {
|
||||||
border: 1px solid var(--border);
|
font-size: 0.7rem;
|
||||||
border-radius: 4px;
|
color: var(--text-muted);
|
||||||
background: var(--input-bg);
|
font-variant-numeric: tabular-nums;
|
||||||
|
min-width: 1.7rem;
|
||||||
|
}
|
||||||
|
.spectrum-field-value {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
height: 1.5rem;
|
|
||||||
}
|
}
|
||||||
#spectrum-auto-btn {
|
.spectrum-field input[type="number"] {
|
||||||
height: 1.5rem;
|
width: 3.2rem;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
text-align: right;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
.spectrum-field input[type="number"]:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#spectrum-bw-input {
|
||||||
|
width: 3.6rem;
|
||||||
|
}
|
||||||
|
/* The select carries `status-input` for the sake of other layouts, which gives
|
||||||
|
it a border and a background of its own; inside a field that reads as a box
|
||||||
|
drawn inside a box. */
|
||||||
|
#spectrum-controls .spectrum-field select {
|
||||||
|
width: auto;
|
||||||
|
height: 1.35rem;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
padding: 0 8px;
|
padding: 0 0.1rem;
|
||||||
font-size: 0.75rem;
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.74rem;
|
||||||
}
|
}
|
||||||
#spectrum-gamma-label {
|
.spectrum-field input[type="range"] {
|
||||||
display: flex;
|
width: 5.5rem;
|
||||||
align-items: center;
|
height: 1.2rem;
|
||||||
gap: 0.3rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
}
|
|
||||||
#spectrum-gamma-input {
|
|
||||||
width: 5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
#spectrum-gamma-value {
|
.spectrum-btn {
|
||||||
font-size: 0.75rem;
|
box-sizing: border-box;
|
||||||
min-width: 1.6rem;
|
height: 1.7rem;
|
||||||
text-align: right;
|
min-height: 0;
|
||||||
|
padding: 0 0.6rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.73rem;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
/* Fingers need more than a 27 px target; a mouse does not, and the strip has
|
||||||
|
no width to spare on a desktop. */
|
||||||
|
@media (hover: none) and (pointer: coarse) {
|
||||||
|
.spectrum-field,
|
||||||
|
.spectrum-btn {
|
||||||
|
height: 2.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Narrow screens: the same fields, stacked. This sits after the rules it
|
||||||
|
overrides — `#spectrum-bw-row` in both places has identical specificity, so
|
||||||
|
whichever comes last wins, and from inside the earlier media query the
|
||||||
|
narrow rules silently lost. */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
/* Narrow: the clusters stack, and a field takes the width so its name and
|
||||||
|
its value sit at opposite ends of a line the thumb can hit. */
|
||||||
|
#spectrum-controls {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 0.45rem;
|
||||||
|
padding-top: 0.45rem;
|
||||||
|
}
|
||||||
|
#spectrum-bw-row,
|
||||||
|
#spectrum-level-row {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.35rem 0.4rem;
|
||||||
|
}
|
||||||
|
.spectrum-controls-spacer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#spectrum-controls .spectrum-field {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
#spectrum-controls .spectrum-field input[type="number"],
|
||||||
|
#spectrum-controls .spectrum-field input[type="range"],
|
||||||
|
#spectrum-controls .spectrum-field select {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 3rem;
|
||||||
|
}
|
||||||
|
#spectrum-controls .spectrum-btn {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.spectrum-hint-mouse,
|
.spectrum-hint-mouse,
|
||||||
.spectrum-hint-touch {
|
.spectrum-hint-touch {
|
||||||
|
|||||||
@@ -196,6 +196,62 @@ try {
|
|||||||
await fixture.close();
|
await fixture.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The strip of controls under the plot. Its two clusters — the receiver's
|
||||||
|
// bandwidth and the display's levels — used to size themselves independently:
|
||||||
|
// four control heights on one line, and between about 1100 and 1400 px the
|
||||||
|
// left cluster wrapped to two lines while the right one did not, leaving the
|
||||||
|
// two at heights that matched neither each other nor anything else.
|
||||||
|
const stripFixture = await startWebFixture({ spectrum: true });
|
||||||
|
const strip = await startBrowser(chromium);
|
||||||
|
try {
|
||||||
|
for (const width of [1600, 1200, 900]) {
|
||||||
|
await strip.page.setViewportSize({ width, height: 950 });
|
||||||
|
await strip.page.goto(stripFixture.origin, { waitUntil: "domcontentloaded" });
|
||||||
|
await strip.page.locator("#spectrum-panel").waitFor({ state: "visible" });
|
||||||
|
await strip.page.waitForTimeout(1600);
|
||||||
|
|
||||||
|
const measured = await strip.page.evaluate(() => {
|
||||||
|
const controls = document.getElementById("spectrum-controls");
|
||||||
|
const box = (element) => element.getBoundingClientRect();
|
||||||
|
const clusters = [...controls.children]
|
||||||
|
.filter((child) => child.id)
|
||||||
|
.map((child) => ({ id: child.id, top: Math.round(box(child).top) }));
|
||||||
|
const parts = [...controls.querySelectorAll(".spectrum-field, .spectrum-btn")];
|
||||||
|
return {
|
||||||
|
heights: [...new Set(parts.map((part) => Math.round(box(part).height)))],
|
||||||
|
count: parts.length,
|
||||||
|
clusters,
|
||||||
|
// Rows are lines of the strip: clusters sharing a top are on one line.
|
||||||
|
lines: new Set(clusters.map((cluster) => cluster.top)).size,
|
||||||
|
overflows: controls.scrollWidth > controls.clientWidth + 1,
|
||||||
|
insidePanel: box(controls).right
|
||||||
|
<= box(document.getElementById("spectrum-panel")).right + 1,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Five fields and four buttons: bandwidth, Set, Auto BW, Sweet-spot, peak
|
||||||
|
// hold, floor, range, Auto, contrast.
|
||||||
|
assert.equal(measured.count, 9, `the strip has ${measured.count} controls at ${width}px`);
|
||||||
|
assert.deepEqual(measured.heights.length, 1,
|
||||||
|
`controls are ${measured.heights.join(", ")}px tall at ${width}px`);
|
||||||
|
assert.equal(measured.overflows, false, `the strip overflows at ${width}px`);
|
||||||
|
assert.equal(measured.insidePanel, true, `the strip runs past the plot at ${width}px`);
|
||||||
|
|
||||||
|
// Either both clusters share a line, or each has one to itself. What must
|
||||||
|
// never happen is one cluster floating against the middle of the other.
|
||||||
|
const tops = measured.clusters.map((cluster) => cluster.top);
|
||||||
|
assert.ok(
|
||||||
|
measured.lines === 1 || measured.lines === measured.clusters.length,
|
||||||
|
`clusters sit at ${tops.join(", ")} at ${width}px`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.deepEqual(strip.runtimeErrors, []);
|
||||||
|
} finally {
|
||||||
|
await strip.browser.close();
|
||||||
|
await stripFixture.close();
|
||||||
|
}
|
||||||
|
|
||||||
// The band plan is fetched once at startup, which can land before the session
|
// The band plan is fetched once at startup, which can land before the session
|
||||||
// exists. It used to fail silently and never retry, so the allocations only
|
// exists. It used to fail silently and never retry, so the allocations only
|
||||||
// turned up if the operator reloaded the page by hand.
|
// turned up if the operator reloaded the page by hand.
|
||||||
|
|||||||
Reference in New Issue
Block a user