openvibers/openvibe.live Commits

Phones: turn the phone and the stream fills the screen (the player was capped at half its height: 195px of 390); the player's buttons fit a 360px screen (clip and fullscreen were off its edge); the floating buttons step aside while you scroll down (#361)

OP OpenVibers committed 19 days ago · 11ceb8871b · 4 files, +64 −0

Changes

ddiff --git a/public/css/features/channel.css b/public/css/features/channel.css
iindex d9b974bf..72b6a079 100644
---- a/public/css/features/channel.css
++++ b/public/css/features/channel.css
@@@ -1516,3 +1516,31 @@
.toast-offer-text { margin: 0; }
.toast-offer-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
@media (max-width: 768px) { .toast.toast-offer { max-width: none; } }
++
++/* ── The player's controls on a narrow phone (2026-10-25) ─────────────────────────
++ At 360-390px the bar ran past the screen: clip and fullscreen sat at x 361-444, out of reach. Under 480px the volume
++ slider goes (a phone has volume buttons; mute stays) and so does the uptime badge, so every button fits. */
++@media (max-width: 480px) {
++ #page-channel .vc-volume-group .volume-slider { display: none !important; }
++ #page-channel #uptime-badge { display: none; }
++}
++
++/* ── A phone on its side: the stream fills the screen (2026-10-25) ───────────────
++ Landscape, at most 540px tall, on a touch screen. Every rule above sizes the player for a portrait phone (half the
++ screen height at most: 195px of 390), so turning the phone made the picture smaller instead of bigger. Here the
++ navbar steps aside on the channel page, the player takes the whole screen (a 16:9 stream fills it on most phones, a
++ 9:16 one sits in the middle), and the chat opens over the right side from its corner button. Turning back restores
++ all of it. */
++@media (orientation: landscape) and (max-height: 540px) and (hover: none) {
++ body:has(#page-channel.active) #navbar-mount { display: none; }
++ #page-channel.page.active { padding-top: 0; }
++ #page-channel .video-container,
++ #page-channel .video-container.is-vertical { aspect-ratio: auto; height: 100vh; height: 100dvh; max-height: none; border-radius: 0; }
++ #page-channel #video-element,
++ #page-channel #video-canvas { max-height: none; }
++ body:has(#page-channel.active) .chat-sidebar { top: 0; height: 100vh; height: 100dvh; }
++ /* The player's controls run along the bottom edge: the chat button moves to the top right corner, smaller, and the
++ messages button waits until the phone is upright again (it covered play and volume). */
++ #page-channel .mobile-chat-toggle { top: 10px; bottom: auto; right: 10px; width: 42px; height: 42px; font-size: 0.95rem; }
++ body:has(#page-channel.active) #messenger-toggle { display: none !important; }
++}
ddiff --git a/public/css/style.css b/public/css/style.css
iindex 73759f90..c9154d89 100644
---- a/public/css/style.css
++++ b/public/css/style.css
@@@ -7256,6 +7256,11 @@ body.theme-light .btn-outline:hover {
font-weight: 600;
}
++/* Phones, scrolling down: the floating buttons step aside (draggable-fab.js) and come back on the way up. */
++body .messenger-toggle, body .floating-chat-fab, body .mobile-chat-toggle { transition: transform 0.2s, opacity 0.2s, background 0.15s; }
++body.fabs-tucked .messenger-toggle, body.fabs-tucked .floating-chat-fab, body.fabs-tucked .mobile-chat-toggle { opacity: 0; transform: scale(0.6); pointer-events: none; }
++@media (prefers-reduced-motion: reduce) { body.fabs-tucked .messenger-toggle, body.fabs-tucked .floating-chat-fab, body.fabs-tucked .mobile-chat-toggle { transform: none; } }
++
/* ── Floating Chat Widget ─────────────────────────────────────── */
.floating-chat-fab {
position: fixed;
ddiff --git a/public/js/app-channel.js b/public/js/app-channel.js
iindex a2cf2f62..4d589937 100644
---- a/public/js/app-channel.js
++++ b/public/js/app-channel.js
@@@ -3480,3 +3480,16 @@ function startUptime(startedAt) {
update();
uptimeInterval = setInterval(update, 1000);
}
++
++/* A phone turned on its side on a channel page: the player fills the screen (channel.css, "A phone on its side"), so
++ bring it into view, the way a video app does when you turn the phone. Turning back leaves the page where it is. */
++(function _landscapePlayerInView() {
++ const sideways = window.matchMedia('(orientation: landscape) and (max-height: 540px) and (hover: none)');
++ const onChange = () => {
++ if (!sideways.matches) return;
++ const page = document.getElementById('page-channel');
++ if (page && page.classList.contains('active')) window.scrollTo({ top: 0, behavior: 'instant' });
++ };
++ if (sideways.addEventListener) sideways.addEventListener('change', onChange);
++ else if (sideways.addListener) sideways.addListener(onChange);
++})();
ddiff --git a/public/js/draggable-fab.js b/public/js/draggable-fab.js
iindex c20690fa..b9a5abfa 100644
---- a/public/js/draggable-fab.js
++++ b/public/js/draggable-fab.js
@@@ -177,3 +177,21 @@
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
else boot();
})();
++
++/* Phones: the floating buttons (messages, global chat, a channel's chat) tuck away while you scroll down to read (they
++ covered cards, titles and the clip feed's sound buttons) and come back when you scroll up, near the top, or at the
++ end of the page. */
++(function () {
++ 'use strict';
++ var phone = window.matchMedia('(max-width: 768px) and (pointer: coarse)');
++ var last = window.scrollY || 0, ticking = false;
++ function update() {
++ ticking = false;
++ var y = window.scrollY || 0;
++ var atEnd = y + window.innerHeight >= document.documentElement.scrollHeight - 80;
++ if (!phone.matches || y <= 120 || atEnd || y < last - 4) document.body.classList.remove('fabs-tucked');
++ else if (y > last + 4) document.body.classList.add('fabs-tucked');
++ last = y;
++ }
++ window.addEventListener('scroll', function () { if (!ticking) { ticking = true; requestAnimationFrame(update); } }, { passive: true });
++})();