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)
Changes
@@@ -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; }++}@@@ -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;@@@ -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);++})();@@@ -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 });++})();
@@ -1516,3 +1516,31 @@
@@ -1516,3 +1516,31 @@
.toast-offer-text { margin: 0; }
.toast-offer-text { margin: 0; }
.toast-offer-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.toast-offer-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
@media (max-width: 768px) { .toast.toast-offer { max-width: none; } }
@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; }
+}
@@ -7256,6 +7256,11 @@ body.theme-light .btn-outline:hover {
@@ -7256,6 +7256,11 @@ body.theme-light .btn-outline:hover {
font-weight: 600;
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 Widget ─────────────────────────────────────── */
.floating-chat-fab {
.floating-chat-fab {
position: fixed;
position: fixed;
@@ -3480,3 +3480,16 @@ function startUptime(startedAt) {
@@ -3480,3 +3480,16 @@ function startUptime(startedAt) {
update();
update();
uptimeInterval = setInterval(update, 1000);
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);
+})();
@@ -177,3 +177,21 @@
@@ -177,3 +177,21 @@
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
else 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 });
+})();