openvibers/openvibe.live Commits
The player: one button size, a real LIVE pill, glass chips; reconnecting is a pill at the top (#724)
Changes
@@@ -1864,3 +1864,22 @@ html[data-ov-motion="reduced"] #page-channel #ch-tabs { transition: none; }}@keyframes chChatRise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }@media (prefers-reduced-motion: reduce) { #page-channel.chat-revealing .stream-layout > .chat-sidebar { animation: none !important; } }++++/* ── The player's bar, 11-09 (the owner: "the buttons and the icons… better sized and centred… better tags"). One button++ size (40 px, 44 on a touch screen) with the icon centred at 18 px; LIVE is a red pill with a breathing dot (a grey++ glass pill when you are behind, "Go live"); the viewer count and the uptime are glass chips at a readable size;++ on a phone the uptime steps aside before anything else. ── */++.video-controls { min-height: 52px; padding: 4px 10px 6px; gap: 4px; }++.video-controls .vc-btn { width: 40px; height: 40px; min-width: 40px; min-height: 40px; padding: 0; border-radius: 12px; font-size: 18px; line-height: 1; }++.video-controls .vc-btn > i { width: 20px; text-align: center; }++@media (pointer: coarse) { .video-controls .vc-btn { width: 44px; height: 44px; min-width: 44px; min-height: 44px; } }++.video-controls .dvr-live-btn { width: auto !important; height: 28px !important; min-height: 28px !important; padding: 0 11px 0 9px !important; gap: 7px;++ background: var(--live-red, #e5484d) !important; font-size: 12px !important; letter-spacing: .08em; box-shadow: 0 2px 10px rgba(229, 72, 77, .35); }++.video-controls .dvr-live-btn .live-dot { width: 7px; height: 7px; background: #fff; box-shadow: 0 0 0 0 rgba(255, 255, 255, .6); animation: vc-live-breathe 1.8s ease-in-out infinite; }++.video-controls .dvr-live-btn.dvr-behind { background: rgba(255, 255, 255, .16) !important; box-shadow: none; }++@keyframes vc-live-breathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, .55); } 50% { box-shadow: 0 0 0 4px rgba(255, 255, 255, 0); } }++html[data-ov-motion=reduced] .video-controls .dvr-live-btn .live-dot { animation-duration: 3.6s; }++.video-controls .viewer-badge, .video-controls .uptime-badge { height: 28px; min-height: 28px; padding: 0 10px; border-radius: 999px; gap: 6px; font-size: 12.5px !important; font-weight: 600;++ background: rgba(255, 255, 255, .12); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); color: #fff; }++.video-controls .viewer-badge i, .video-controls .uptime-badge i { font-size: 12px; color: rgba(255, 255, 255, .75); }++@media (max-width: 480px) { .video-controls .uptime-badge { display: none; } .video-controls .viewer-badge { padding: 0 9px; } }@@@ -217,17 +217,25 @@styleEl = document.createElement('style');styleEl.id = 'ov-viewer-health-style';styleEl.textContent = [-- '.ov-freeze-notice{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:40;',-- 'display:flex;align-items:center;gap:10px;max-width:min(92%,420px);padding:9px 12px;border-radius:10px;',-- 'background:rgba(12,12,16,.86);color:#fff;font:13px/1.35 system-ui,-apple-system,Segoe UI,sans-serif;',-- 'box-shadow:0 6px 20px rgba(0,0,0,.35)}',++ '.ov-freeze-notice{position:absolute;left:50%;top:12px;transform:translateX(-50%);z-index:40;box-sizing:border-box;',++ 'display:flex;align-items:center;gap:10px;width:max-content;max-width:calc(100% - 24px);min-height:44px;padding:6px 6px 6px 12px;border-radius:999px;',++ 'background:rgba(10,12,18,.72);-webkit-backdrop-filter:blur(14px) saturate(1.3);backdrop-filter:blur(14px) saturate(1.3);color:#fff;',++ 'font:500 13px/1.25 Inter,system-ui,-apple-system,Segoe UI,sans-serif;letter-spacing:0;text-align:left;',++ 'box-shadow:0 8px 28px rgba(0,0,0,.4),inset 0 0 0 1px rgba(255,255,255,.1);animation:ov-freeze-in .32s cubic-bezier(.2,.9,.3,1) both}','.ov-freeze-notice[hidden]{display:none}',-- '.ov-freeze-notice-text{flex:1 1 auto;min-width:0}',-- '.ov-freeze-notice b{display:block;font-weight:600}',-- '.ov-freeze-notice small{opacity:.75;font-size:11px}',-- '.ov-freeze-notice button{flex:0 0 auto;border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.1);',-- 'color:#fff;border-radius:7px;padding:5px 9px;font:inherit;font-size:12px;cursor:pointer}',-- '.ov-freeze-notice button:hover{background:rgba(255,255,255,.2)}',++ '.ov-freeze-notice::before{content:"";flex:none;width:16px;height:16px;border-radius:50%;border:2.5px solid rgba(255,255,255,.22);',++ 'border-top-color:#4f7cff;border-right-color:#8b5cf6;animation:ov-freeze-turn .9s linear infinite}',++ '.ov-freeze-notice-text{flex:0 1 auto;min-width:0;display:grid;gap:1px}',++ '.ov-freeze-notice b{display:block;font-size:13px;font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',++ '.ov-freeze-notice small{display:block;font-size:11.5px;opacity:.72;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',++ '.ov-freeze-notice small:empty{display:none}',++ '.ov-freeze-notice button{flex:none;display:inline-grid;place-items:center;width:32px;height:32px;padding:0;border:0;border-radius:50%;',++ 'background:rgba(255,255,255,.12);color:#fff;cursor:pointer}',++ '.ov-freeze-notice button:hover,.ov-freeze-notice button:focus-visible{background:rgba(255,255,255,.24);outline:none}',++ '.ov-freeze-notice button svg{width:16px;height:16px}',++ '@keyframes ov-freeze-in{from{opacity:0;transform:translate(-50%,-6px) scale(.96)}}',++ '@keyframes ov-freeze-turn{to{transform:rotate(360deg)}}',++ 'html[data-ov-motion=reduced] .ov-freeze-notice::before{animation-duration:1.8s}',].join('');(document.head || document.documentElement).appendChild(styleEl);}@@@ -256,7 +264,10 @@text.appendChild(small);const btn = document.createElement('button');btn.type = 'button';-- btn.textContent = 'Copy debug info';++ // An icon button; its word is the tooltip and the accessible name.++ btn.setAttribute('aria-label', 'Copy details for support');++ btn.title = 'Copy details for support';++ btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 9h10v10H9zM5 15V5h10"/></svg>';btn.addEventListener('click', () => { try { onCopy && onCopy(); } catch (e) { /* nothing to do */ } });noticeEl.appendChild(text);noticeEl.appendChild(btn);@@@ -418,8 +429,8 @@if (!opts.notice) return;showFreezeNotice({container: opts.notice,-- title: 'The picture froze. Reconnecting…',-- detail: `Step: ${ladder.stageLabel}`,++ title: 'Reconnecting…',++ detail: `The picture froze: ${ladder.stageLabel}`,onCopy: () => {const text = buildDebugReport({streamId: opts.streamId,
@@ -1864,3 +1864,22 @@ html[data-ov-motion="reduced"] #page-channel #ch-tabs { transition: none; }
@@ -1864,3 +1864,22 @@ html[data-ov-motion="reduced"] #page-channel #ch-tabs { transition: none; }
}
}
@keyframes chChatRise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes chChatRise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { #page-channel.chat-revealing .stream-layout > .chat-sidebar { animation: none !important; } }
@media (prefers-reduced-motion: reduce) { #page-channel.chat-revealing .stream-layout > .chat-sidebar { animation: none !important; } }
+
+/* ── The player's bar, 11-09 (the owner: "the buttons and the icons… better sized and centred… better tags"). One button
+ size (40 px, 44 on a touch screen) with the icon centred at 18 px; LIVE is a red pill with a breathing dot (a grey
+ glass pill when you are behind, "Go live"); the viewer count and the uptime are glass chips at a readable size;
+ on a phone the uptime steps aside before anything else. ── */
+.video-controls { min-height: 52px; padding: 4px 10px 6px; gap: 4px; }
+.video-controls .vc-btn { width: 40px; height: 40px; min-width: 40px; min-height: 40px; padding: 0; border-radius: 12px; font-size: 18px; line-height: 1; }
+.video-controls .vc-btn > i { width: 20px; text-align: center; }
+@media (pointer: coarse) { .video-controls .vc-btn { width: 44px; height: 44px; min-width: 44px; min-height: 44px; } }
+.video-controls .dvr-live-btn { width: auto !important; height: 28px !important; min-height: 28px !important; padding: 0 11px 0 9px !important; gap: 7px;
+ background: var(--live-red, #e5484d) !important; font-size: 12px !important; letter-spacing: .08em; box-shadow: 0 2px 10px rgba(229, 72, 77, .35); }
+.video-controls .dvr-live-btn .live-dot { width: 7px; height: 7px; background: #fff; box-shadow: 0 0 0 0 rgba(255, 255, 255, .6); animation: vc-live-breathe 1.8s ease-in-out infinite; }
+.video-controls .dvr-live-btn.dvr-behind { background: rgba(255, 255, 255, .16) !important; box-shadow: none; }
+@keyframes vc-live-breathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, .55); } 50% { box-shadow: 0 0 0 4px rgba(255, 255, 255, 0); } }
+html[data-ov-motion=reduced] .video-controls .dvr-live-btn .live-dot { animation-duration: 3.6s; }
+.video-controls .viewer-badge, .video-controls .uptime-badge { height: 28px; min-height: 28px; padding: 0 10px; border-radius: 999px; gap: 6px; font-size: 12.5px !important; font-weight: 600;
+ background: rgba(255, 255, 255, .12); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); color: #fff; }
+.video-controls .viewer-badge i, .video-controls .uptime-badge i { font-size: 12px; color: rgba(255, 255, 255, .75); }
+@media (max-width: 480px) { .video-controls .uptime-badge { display: none; } .video-controls .viewer-badge { padding: 0 9px; } }
@@ -217,17 +217,25 @@
@@ -217,17 +217,25 @@
styleEl = document.createElement('style');
styleEl = document.createElement('style');
styleEl.id = 'ov-viewer-health-style';
styleEl.id = 'ov-viewer-health-style';
styleEl.textContent = [
styleEl.textContent = [
- '.ov-freeze-notice{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:40;',
- 'display:flex;align-items:center;gap:10px;max-width:min(92%,420px);padding:9px 12px;border-radius:10px;',
- 'background:rgba(12,12,16,.86);color:#fff;font:13px/1.35 system-ui,-apple-system,Segoe UI,sans-serif;',
- 'box-shadow:0 6px 20px rgba(0,0,0,.35)}',
+ '.ov-freeze-notice{position:absolute;left:50%;top:12px;transform:translateX(-50%);z-index:40;box-sizing:border-box;',
+ 'display:flex;align-items:center;gap:10px;width:max-content;max-width:calc(100% - 24px);min-height:44px;padding:6px 6px 6px 12px;border-radius:999px;',
+ 'background:rgba(10,12,18,.72);-webkit-backdrop-filter:blur(14px) saturate(1.3);backdrop-filter:blur(14px) saturate(1.3);color:#fff;',
+ 'font:500 13px/1.25 Inter,system-ui,-apple-system,Segoe UI,sans-serif;letter-spacing:0;text-align:left;',
+ 'box-shadow:0 8px 28px rgba(0,0,0,.4),inset 0 0 0 1px rgba(255,255,255,.1);animation:ov-freeze-in .32s cubic-bezier(.2,.9,.3,1) both}',
'.ov-freeze-notice[hidden]{display:none}',
'.ov-freeze-notice[hidden]{display:none}',
- '.ov-freeze-notice-text{flex:1 1 auto;min-width:0}',
- '.ov-freeze-notice b{display:block;font-weight:600}',
- '.ov-freeze-notice small{opacity:.75;font-size:11px}',
- '.ov-freeze-notice button{flex:0 0 auto;border:1px solid rgba(255,255,255,.35);background:rgba(255,255,255,.1);',
- 'color:#fff;border-radius:7px;padding:5px 9px;font:inherit;font-size:12px;cursor:pointer}',
- '.ov-freeze-notice button:hover{background:rgba(255,255,255,.2)}',
+ '.ov-freeze-notice::before{content:"";flex:none;width:16px;height:16px;border-radius:50%;border:2.5px solid rgba(255,255,255,.22);',
+ 'border-top-color:#4f7cff;border-right-color:#8b5cf6;animation:ov-freeze-turn .9s linear infinite}',
+ '.ov-freeze-notice-text{flex:0 1 auto;min-width:0;display:grid;gap:1px}',
+ '.ov-freeze-notice b{display:block;font-size:13px;font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
+ '.ov-freeze-notice small{display:block;font-size:11.5px;opacity:.72;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
+ '.ov-freeze-notice small:empty{display:none}',
+ '.ov-freeze-notice button{flex:none;display:inline-grid;place-items:center;width:32px;height:32px;padding:0;border:0;border-radius:50%;',
+ 'background:rgba(255,255,255,.12);color:#fff;cursor:pointer}',
+ '.ov-freeze-notice button:hover,.ov-freeze-notice button:focus-visible{background:rgba(255,255,255,.24);outline:none}',
+ '.ov-freeze-notice button svg{width:16px;height:16px}',
+ '@keyframes ov-freeze-in{from{opacity:0;transform:translate(-50%,-6px) scale(.96)}}',
+ '@keyframes ov-freeze-turn{to{transform:rotate(360deg)}}',
+ 'html[data-ov-motion=reduced] .ov-freeze-notice::before{animation-duration:1.8s}',
].join('');
].join('');
(document.head || document.documentElement).appendChild(styleEl);
(document.head || document.documentElement).appendChild(styleEl);
}
}
@@ -256,7 +264,10 @@
@@ -256,7 +264,10 @@
text.appendChild(small);
text.appendChild(small);
const btn = document.createElement('button');
const btn = document.createElement('button');
btn.type = 'button';
btn.type = 'button';
- btn.textContent = 'Copy debug info';
+ // An icon button; its word is the tooltip and the accessible name.
+ btn.setAttribute('aria-label', 'Copy details for support');
+ btn.title = 'Copy details for support';
+ btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 9h10v10H9zM5 15V5h10"/></svg>';
btn.addEventListener('click', () => { try { onCopy && onCopy(); } catch (e) { /* nothing to do */ } });
btn.addEventListener('click', () => { try { onCopy && onCopy(); } catch (e) { /* nothing to do */ } });
noticeEl.appendChild(text);
noticeEl.appendChild(text);
noticeEl.appendChild(btn);
noticeEl.appendChild(btn);
@@ -418,8 +429,8 @@
@@ -418,8 +429,8 @@
if (!opts.notice) return;
if (!opts.notice) return;
showFreezeNotice({
showFreezeNotice({
container: opts.notice,
container: opts.notice,
- title: 'The picture froze. Reconnecting…',
- detail: `Step: ${ladder.stageLabel}`,
+ title: 'Reconnecting…',
+ detail: `The picture froze: ${ladder.stageLabel}`,
onCopy: () => {
onCopy: () => {
const text = buildDebugReport({
const text = buildDebugReport({
streamId: opts.streamId,
streamId: opts.streamId,