fix(visualizer): full-width spectrum + device pick auto-starts capture

Spectrum width
- grid-auto-flow: column with implicit columns wasn't reliably
  stretching to fill the parent. Switch to explicit
  grid-template-columns: repeat(var(--spectrum-bars), minmax(0, 1fr))
  with the bar count exposed as a CSS variable from JS so the
  column count and the actual bar count stay in sync.
- !important on display/grid-template-columns/width to defeat any
  legacy descendant rules.

Device selection
- Picking a device in the audio-device dropdown is an explicit
  signal that the user wants capture. Auto-enable the visualizer
  if it isn't already on, then call applyVisualizerMode so the
  WS subscription happens and the badge flips from 'Available' to
  'Active'. Was only doing this when visualizer was already on,
  which is why the user kept seeing 'Available, not capturing'.
This commit is contained in:
2026-04-25 02:24:01 +03:00
parent 6066b4a2c5
commit a0f74dfc39
3 changed files with 15 additions and 8 deletions
+6 -7
View File
@@ -6867,21 +6867,20 @@ body.visualizer-active .now-playing .spectrogram-canvas {
/* ─── Spectrum bars (JS-injected; real audio from backend FFT) ── */
.now-playing .spectrum {
/* Grid with explicit equal-width columns guarantees each bar
claims its share of the full container width, regardless of
the bar count. */
display: grid;
/* Explicit equal-width columns. The CSS variable --spectrum-bars
is set by JS so adding/removing bars stays in sync. */
display: grid !important;
grid-template-columns: repeat(var(--spectrum-bars, 40), minmax(0, 1fr)) !important;
grid-auto-flow: column;
grid-auto-columns: 1fr;
align-items: end;
column-gap: 4px;
height: 70px;
margin: 36px 0 24px;
width: 100%;
width: 100% !important;
box-sizing: border-box;
min-width: 0;
}
.now-playing .spectrum span {
.now-playing .spectrum > span {
display: block;
width: 100%;
min-width: 0;
+3
View File
@@ -172,6 +172,9 @@ window.addEventListener('DOMContentLoaded', async () => {
const spectrumRoot = document.getElementById('player-spectrum');
if (spectrumRoot && !spectrumRoot.children.length) {
const SPECTRUM_BARS = 40;
// Sync the grid column count to the bar count so the row truly
// fills the column even if the bar count changes later.
spectrumRoot.style.setProperty('--spectrum-bars', SPECTRUM_BARS);
const frag = document.createDocumentFragment();
for (let i = 0; i < SPECTRUM_BARS; i++) {
const s = document.createElement('span');
+6 -1
View File
@@ -618,7 +618,12 @@ export async function onAudioDeviceChanged() {
const result = await resp.json();
updateAudioDeviceStatus({ available: result.success, ...result });
await checkVisualizerAvailability();
if (visualizerEnabled) applyVisualizerMode();
// Picking a device is an explicit signal the user wants
// capture: auto-enable the visualizer if it isn't already on.
if (!visualizerEnabled && visualizerAvailable) {
setVisualizerEnabled(true);
}
applyVisualizerMode();
showToast(t('settings.audio.device_changed'), 'success');
} else {
showToast(t('settings.audio.device_change_failed'), 'error');