openvibers/openvibe.live Commits

The live player's fullscreen button stays on the bar on a phone: buttons keep their size, the readouts give way, the stats gauge steps aside under 420 px (#384)

OP OpenVibers committed 17 days ago · 3e24602796 · 2 files, +38 −0

Changes

ddiff --git a/public/css/style.css b/public/css/style.css
iindex b071e5aa..1176166e 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -2060,6 +2060,16 @@ a.pulse-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.vc-btn:active { transform: scale(0.92); }
.vc-btn.active { color: var(--accent); }
.vc-spacer { flex: 1; }
++/* The fullscreen button never leaves the bar (Maticus, 2026-10-26: on a phone the bar was cut off right after the clip
++ button, so the scissors got tapped for fullscreen; it happened at 360 px with larger text while rewinding). Buttons
++ keep their size; the readouts in the middle give way first, and on a narrow phone the stats gauge steps aside. */
++.video-controls > * { flex-shrink: 0; }
++.video-controls > .dvr-time-display,
++.video-controls > .viewer-badge,
++.video-controls > .uptime-badge { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
++@media (max-width: 420px) {
++ .video-controls > #btn-stats { display: none; }
++}
/* Volume group */
.vc-volume-group {
ddiff --git a/test/player-controls-fit.test.js b/test/player-controls-fit.test.js
nnew file mode 100644
iindex 00000000..878171a1
---- /dev/null
++++ b/test/player-controls-fit.test.js
@@@ -0,0 +1,28 @@
++/**
++ * The live player's fullscreen button never leaves the control bar on a phone (Maticus, 2026-10-26: "it cuts it off
++ * right at the scissors … you can't tap the square thing to make it full screen"). Measured in Chrome: at 360 px with
++ * larger text while rewinding, the bar (play, volume, time, LIVE, viewers, stats, clip, fullscreen) was 6 px wider than
++ * the player and the container clipped the last button. Buttons keep their size; the readouts give way; the stats gauge
++ * steps aside on a narrow phone.
++ *
++ * node test/player-controls-fit.test.js
++ */
++'use strict';
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const css = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'style.css'), 'utf8');
++const frag = fs.readFileSync(path.join(__dirname, '..', 'public', 'fragments', 'channel.html'), 'utf8');
++
++assert.ok(css.includes('.video-controls > * { flex-shrink: 0; }'), 'no button shrinks or is pushed out');
++const giving = css.match(/\.video-controls > \.dvr-time-display,\s*\.video-controls > \.viewer-badge,\s*\.video-controls > \.uptime-badge \{([^}]*)\}/);
++assert.ok(giving && /flex-shrink: 1/.test(giving[1]) && /min-width: 0/.test(giving[1]) && /text-overflow: ellipsis/.test(giving[1]), 'the readouts give way');
++assert.match(css, /@media \(max-width: 420px\) \{\s*\.video-controls > #btn-stats \{ display: none; \}\s*\}/, 'the gauge steps aside on a narrow phone');
++
++// Fullscreen stays the bar's last button, right after the clip button.
++const bar = frag.slice(frag.indexOf('<div class="video-controls">'), frag.indexOf('<!-- Stream stats overlay'));
++const ids = [...bar.matchAll(/id="([^"]+)"/g)].map((m) => m[1]);
++assert.deepStrictEqual(ids.slice(-2), ['btn-clip', 'btn-fullscreen']);
++
++console.log('player controls fit: fullscreen stays on the bar at phone widths');