openvibers/openvibe.live Commits

Channel: on a phone held upright a live channel's chat sits under the stream info and fills the screen (a third of the screen was empty while chat waited behind a button) (#163)

OP OpenVibers committed 28 days ago · 6130079535 · 2 files, +48 −0

Changes

ddiff --git a/public/css/features/channel.css b/public/css/features/channel.css
iindex a39f0064..e21efe81 100644
---- a/public/css/features/channel.css
++++ b/public/css/features/channel.css
@@@ -1485,3 +1485,24 @@
/* Tabs that run past the edge fade out there, so it reads as "scroll for more" (class set by app-channel.js). */
.ch-tabs.is-clipped { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); }
++
++/* A live channel on a phone held upright: the chat sits under the stream info and fills the screen below the video,
++ the way phone streaming apps do. The stream area was sized to the whole screen while the chat waited behind a
++ button, which left about a third of the screen empty (seen 2026-10-16). */
++@media (max-width: 768px) and (orientation: portrait) {
++ #page-channel #ch-live-area .stream-main { flex: none; overflow: visible; }
++ #page-channel #ch-live-area .stream-layout > .chat-sidebar {
++ position: relative; inset: auto; transform: none; transition: none; z-index: auto;
++ flex: 1 1 auto; width: 100%; height: auto; min-height: 220px; max-height: none;
++ border-radius: 0; box-shadow: none; border-top: 1px solid var(--border);
++ }
++ #page-channel #ch-live-area .stream-layout > .chat-sidebar .mobile-chat-close,
++ #page-channel #ch-live-area .stream-layout > .chat-sidebar > .chat-grip { display: none; }
++ /* Docked, the chat's messages get the room: a slim header, the tools beside nothing else. */
++ #page-channel #ch-live-area .stream-layout > .chat-sidebar .chat-header { padding: 6px 12px; min-height: 0; }
++ #page-channel #ch-live-area .stream-layout > .chat-sidebar .chat-input-area { padding-top: 6px; padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px)); }
++ /* The chat is on screen, so its button goes; the DM bubble steps aside as it does for the open chat sheet
++ (it covered the chat's emoji button). */
++ body:has(#page-channel.active #ch-live-area .stream-layout > .chat-sidebar) .mobile-chat-toggle,
++ body:has(#page-channel.active #ch-live-area .stream-layout > .chat-sidebar) #messenger-toggle { display: none !important; }
++}
ddiff --git a/test/channel-phone-chat.test.js b/test/channel-phone-chat.test.js
nnew file mode 100644
iindex 00000000..f906cc18
---- /dev/null
++++ b/test/channel-phone-chat.test.js
@@@ -0,0 +1,27 @@
++/**
++ * A live channel on a phone held upright shows its chat under the stream info, filling the screen below the video
++ * (public/css/features/channel.css). Before, the stream area was sized to the whole screen while the chat waited
++ * behind a floating button, which left about a third of the screen empty (seen 2026-10-16 at phone width). Docked,
++ * the chat's button and the DM bubble (which covered the chat's emoji button) step aside.
++ *
++ * A real browser pass at phone width is in the PR (local Live, a live test stream, a signed-out phone viewer).
++ *
++ * node test/channel-phone-chat.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', 'features', 'channel.css'), 'utf8');
++const at = css.lastIndexOf('@media (max-width: 768px) and (orientation: portrait) {\n #page-channel #ch-live-area .stream-main');
++assert.ok(at > 0, 'the portrait-phone block for a live channel exists');
++let depth = 0, end = css.indexOf('{', at);
++for (; end < css.length; end++) { if (css[end] === '{') depth++; else if (css[end] === '}' && --depth === 0) break; }
++const block = css.slice(at, end + 1);
++
++assert.match(block, /#ch-live-area \.stream-main \{ flex: none; overflow: visible; \}/, 'the stream area keeps its own height');
++assert.match(block, /\.stream-layout > \.chat-sidebar \{[^}]*position: relative;[^}]*transform: none;[^}]*flex: 1 1 auto;[^}]*min-height: 220px;/, 'the chat docks below and fills the rest');
++assert.match(block, /\.chat-sidebar > \.chat-grip \{ display: none; \}|> \.chat-grip \{ display: none; \}/, 'no bottom-sheet grip on the docked chat');
++assert.match(block, /\.mobile-chat-toggle,\s*body:has\([^)]*\) #messenger-toggle \{ display: none !important; \}/, 'its button and the DM bubble step aside');
++console.log('channel phone chat: all checks passed');