openvibers/openvibe.live Commits
A channel on a phone: the channel line in about 100 px, the sheet just under it, the grip centred (#814)
Changes
@@@ -2226,7 +2226,7 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { a#page-channel.ch-is-live:not(.chat-collapsed) .channel-below-fold { display: none; }body:has(#page-channel.active.ch-is-live:not(.chat-collapsed)) #ov-footer { display: none; }#page-channel.ch-is-live.chat-collapsed #ch-bot-section { display: none !important; }-- #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar > .chat-grip { position: absolute; top: 0; left: 0; right: 0; height: 14px; z-index: 4; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar > .chat-grip { position: absolute; top: 0; height: 16px; z-index: 4; }#page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar .chat-header { padding-top: 8px; min-height: 46px; }#page-channel.ch-is-live .chat-sidebar .ch-goal-widget { padding: 3px 6px 0; }#page-channel.ch-is-live .chat-sidebar .cgw-goal { height: 30px; }@@@ -2244,3 +2244,20 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { ahtml.chat-compact #page-channel.ch-is-live .chat-sidebar .cgw-goal * { font-size: .66rem; }html.chat-compact #page-channel.ch-is-live .chat-sidebar .chat-input-area { padding-top: 4px; }}++++/* ── The channel line on a phone, live, compact (ask 366: "the top bar needs to be a little more compact so that we++ get a little more space out of it"): who on the first line, then live, watching and the title on one line, then the++ actions in one slim row with Share as its icon. About a hundred pixels instead of a hundred and fifty. ─── */++@media (max-width: 768px) and (orientation: portrait) {++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar { padding: 8px 12px 10px; row-gap: 8px; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar .ch-avatar { width: 40px; height: 40px; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-info-bar-text { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 1px; min-width: 0; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-info-bar-top { flex: 0 0 100%; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) :is(.ch-presence, .ch-stream-title) { margin: 0; font-size: .82rem; line-height: 1.35; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-stream-title { min-width: 0; color: var(--text-secondary); overflow-wrap: anywhere; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-presence:not(:empty) + .ch-meta + .ch-social-pills + .ch-stream-title::before,++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-presence:not(:empty) ~ .ch-stream-title::before { content: "·"; margin-right: 6px; color: var(--text-muted); }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right :is(.ch-action, .ovk-ask) { height: 38px; min-height: 38px; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right #ch-btn-share { width: 38px; padding: 0; justify-content: center; }++ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right #ch-btn-share > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }++}@@@ -43,9 +43,16 @@function lineSize() {const p = page();const info = p && p.querySelector('.stream-main > .ch-info-bar');-- const h = info && info.offsetParent !== null ? info.scrollHeight : 0;++ const h = info && info.offsetParent !== null ? lineHeight(info) : 0;return Math.max(180, Math.round(dockRoom() - (h || 150)));}++ /** What the channel line holds, top to its last shown child plus its padding (its box may be taller: it fills). */++ function lineHeight(info) {++ const top = info.getBoundingClientRect().top;++ let bottom = top;++ for (const k of info.children) { const r = k.getBoundingClientRect(); if (r.height) bottom = Math.max(bottom, r.bottom); }++ return Math.ceil(bottom - top + (parseFloat(getComputedStyle(info).paddingBottom) || 0));++ }const MODES = {side: { key: 'openvibe_chat_width', prop: '--chat-w', axis: 'x', min: 260, max: () => Math.min(window.innerWidth * 0.5, 760) },overlay: { key: 'openvibe_chat_overlay_w', prop: '--chat-ow', axis: 'x', min: 260, max: () => window.innerWidth * 0.7 },@@@ -196,6 +203,21 @@new MutationObserver(() => { const now = p.classList.contains('ch-is-live'); if (now !== was) { was = now; applySaved(); syncAll(); } }).observe(p, { attributes: true, attributeFilter: ['class'] });}++ // The channel line fills in after the page (the title, the live line, the actions): a sheet kept just under it++ // follows its height as it settles, so the line is never cut and never leaves a gap.++ const info = p && p.querySelector('.stream-main > .ch-info-bar');++ if (info && !info._ovLineWatch && typeof ResizeObserver === 'function') {++ info._ovLineWatch = true;++ let last = 0;++ new ResizeObserver(() => {++ const saved = read(MODES.sheet.key);++ if (!docked() || !(saved === LINE || saved > 0)) return;++ const h = lineHeight(info);++ if (Math.abs(h - last) < 2) return;++ last = h;++ setSize('sheet', LINE);++ }).observe(info);++ }}init();document.addEventListener('ov:fragment', init);
@@ -2226,7 +2226,7 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { a
@@ -2226,7 +2226,7 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { a
#page-channel.ch-is-live:not(.chat-collapsed) .channel-below-fold { display: none; }
#page-channel.ch-is-live:not(.chat-collapsed) .channel-below-fold { display: none; }
body:has(#page-channel.active.ch-is-live:not(.chat-collapsed)) #ov-footer { display: none; }
body:has(#page-channel.active.ch-is-live:not(.chat-collapsed)) #ov-footer { display: none; }
#page-channel.ch-is-live.chat-collapsed #ch-bot-section { display: none !important; }
#page-channel.ch-is-live.chat-collapsed #ch-bot-section { display: none !important; }
- #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar > .chat-grip { position: absolute; top: 0; left: 0; right: 0; height: 14px; z-index: 4; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar > .chat-grip { position: absolute; top: 0; height: 16px; z-index: 4; }
#page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar .chat-header { padding-top: 8px; min-height: 46px; }
#page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) > .chat-sidebar .chat-header { padding-top: 8px; min-height: 46px; }
#page-channel.ch-is-live .chat-sidebar .ch-goal-widget { padding: 3px 6px 0; }
#page-channel.ch-is-live .chat-sidebar .ch-goal-widget { padding: 3px 6px 0; }
#page-channel.ch-is-live .chat-sidebar .cgw-goal { height: 30px; }
#page-channel.ch-is-live .chat-sidebar .cgw-goal { height: 30px; }
@@ -2244,3 +2244,20 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { a
@@ -2244,3 +2244,20 @@ html[data-ov-motion="off"] #page-channel.ch-tabbed .ch-tab-panel.is-entering { a
html.chat-compact #page-channel.ch-is-live .chat-sidebar .cgw-goal * { font-size: .66rem; }
html.chat-compact #page-channel.ch-is-live .chat-sidebar .cgw-goal * { font-size: .66rem; }
html.chat-compact #page-channel.ch-is-live .chat-sidebar .chat-input-area { padding-top: 4px; }
html.chat-compact #page-channel.ch-is-live .chat-sidebar .chat-input-area { padding-top: 4px; }
}
}
+
+/* ── The channel line on a phone, live, compact (ask 366: "the top bar needs to be a little more compact so that we
+ get a little more space out of it"): who on the first line, then live, watching and the title on one line, then the
+ actions in one slim row with Share as its icon. About a hundred pixels instead of a hundred and fifty. ─── */
+@media (max-width: 768px) and (orientation: portrait) {
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar { padding: 8px 12px 10px; row-gap: 8px; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar .ch-avatar { width: 40px; height: 40px; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-info-bar-text { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 6px; row-gap: 1px; min-width: 0; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-info-bar-top { flex: 0 0 100%; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) :is(.ch-presence, .ch-stream-title) { margin: 0; font-size: .82rem; line-height: 1.35; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-stream-title { min-width: 0; color: var(--text-secondary); overflow-wrap: anywhere; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-presence:not(:empty) + .ch-meta + .ch-social-pills + .ch-stream-title::before,
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar:not(.ch-info-open) .ch-presence:not(:empty) ~ .ch-stream-title::before { content: "·"; margin-right: 6px; color: var(--text-muted); }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right :is(.ch-action, .ovk-ask) { height: 38px; min-height: 38px; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right #ch-btn-share { width: 38px; padding: 0; justify-content: center; }
+ #page-channel.ch-is-live .stream-layout:not(:has(.video-container.is-vertical)) .ch-info-bar-right #ch-btn-share > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
+}
@@ -43,9 +43,16 @@
@@ -43,9 +43,16 @@
function lineSize() {
function lineSize() {
const p = page();
const p = page();
const info = p && p.querySelector('.stream-main > .ch-info-bar');
const info = p && p.querySelector('.stream-main > .ch-info-bar');
- const h = info && info.offsetParent !== null ? info.scrollHeight : 0;
+ const h = info && info.offsetParent !== null ? lineHeight(info) : 0;
return Math.max(180, Math.round(dockRoom() - (h || 150)));
return Math.max(180, Math.round(dockRoom() - (h || 150)));
}
}
+ /** What the channel line holds, top to its last shown child plus its padding (its box may be taller: it fills). */
+ function lineHeight(info) {
+ const top = info.getBoundingClientRect().top;
+ let bottom = top;
+ for (const k of info.children) { const r = k.getBoundingClientRect(); if (r.height) bottom = Math.max(bottom, r.bottom); }
+ return Math.ceil(bottom - top + (parseFloat(getComputedStyle(info).paddingBottom) || 0));
+ }
const MODES = {
const MODES = {
side: { key: 'openvibe_chat_width', prop: '--chat-w', axis: 'x', min: 260, max: () => Math.min(window.innerWidth * 0.5, 760) },
side: { key: 'openvibe_chat_width', prop: '--chat-w', axis: 'x', min: 260, max: () => Math.min(window.innerWidth * 0.5, 760) },
overlay: { key: 'openvibe_chat_overlay_w', prop: '--chat-ow', axis: 'x', min: 260, max: () => window.innerWidth * 0.7 },
overlay: { key: 'openvibe_chat_overlay_w', prop: '--chat-ow', axis: 'x', min: 260, max: () => window.innerWidth * 0.7 },
@@ -196,6 +203,21 @@
@@ -196,6 +203,21 @@
new MutationObserver(() => { const now = p.classList.contains('ch-is-live'); if (now !== was) { was = now; applySaved(); syncAll(); } })
new MutationObserver(() => { const now = p.classList.contains('ch-is-live'); if (now !== was) { was = now; applySaved(); syncAll(); } })
.observe(p, { attributes: true, attributeFilter: ['class'] });
.observe(p, { attributes: true, attributeFilter: ['class'] });
}
}
+ // The channel line fills in after the page (the title, the live line, the actions): a sheet kept just under it
+ // follows its height as it settles, so the line is never cut and never leaves a gap.
+ const info = p && p.querySelector('.stream-main > .ch-info-bar');
+ if (info && !info._ovLineWatch && typeof ResizeObserver === 'function') {
+ info._ovLineWatch = true;
+ let last = 0;
+ new ResizeObserver(() => {
+ const saved = read(MODES.sheet.key);
+ if (!docked() || !(saved === LINE || saved > 0)) return;
+ const h = lineHeight(info);
+ if (Math.abs(h - last) < 2) return;
+ last = h;
+ setSize('sheet', LINE);
+ }).observe(info);
+ }
}
}
init();
init();
document.addEventListener('ov:fragment', init);
document.addEventListener('ov:fragment', init);