From a6de7024e8307f154310905900c2e82ef57a966f Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Tue, 2 Jun 2026 08:57:16 -0400 Subject: [PATCH] =?UTF-8?q?zebra-report:=20hide-panel=20toggle=20+=20camer?= =?UTF-8?q?a=20PiP=20overlay=20=E2=80=94=20mirror?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zebra-report/zebra-spaces.html | 83 ++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index 6a5da35..64d7ae3 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -29,12 +29,14 @@ /* buttons + inputs */ html.theme-dark button, html.theme-dark .game-tabs button, - html.theme-dark .theme-toggle { + html.theme-dark .theme-toggle, + html.theme-dark .controls-toggle { background: #000; color: #ccc; border-color: #444; } html.theme-dark button:hover:not(:disabled), html.theme-dark .game-tabs button:hover:not(.active), - html.theme-dark .theme-toggle:hover { background: #1a1a1a; } + html.theme-dark .theme-toggle:hover, + html.theme-dark .controls-toggle:hover { background: #1a1a1a; } html.theme-dark button.invert { background: #ccc; color: #000; border-color: #ccc; } html.theme-dark button.invert:hover:not(:disabled) { background: #999; } html.theme-dark .game-tabs button.active { background: #ccc; color: #000; border-color: #ccc; } @@ -83,13 +85,15 @@ html.theme-dark footer span { color: #555 !important; } html.theme-dark footer a { color: #777 !important; } - .theme-toggle { - position: fixed; top: 0.6rem; right: 0.8rem; z-index: 9999; + .theme-toggle, .controls-toggle { + position: fixed; top: 0.6rem; z-index: 9999; background: #fff; color: #000; border: 1px solid #000; padding: 0.2rem 0.55rem; font-family: monospace; font-size: 0.7rem; cursor: pointer; line-height: 1; } - .theme-toggle:hover { background: #f0f0f0; } + .theme-toggle { right: 0.8rem; } + .controls-toggle { right: 4.3rem; } + .theme-toggle:hover, .controls-toggle:hover { background: #f0f0f0; } /* two-column page on desktop: left = timeline (1fr, takes remaining * space — hosts screen shares + the running event feed), right = * controls (kept narrow so the screen share gets maximum pixels). @@ -101,9 +105,22 @@ gap: 1.25rem; align-items: start; } + /* collapsed: right column folds away so the screen share fills the + * full viewport width. The timeline column's right border + padding + * collapse with it. */ + .page.controls-collapsed { + grid-template-columns: minmax(0, 1fr); + gap: 0; + } + .page.controls-collapsed > .controls { display: none; } + .page.controls-collapsed > .timeline { border-right: none; padding-right: 0; } + /* honour the pre-paint pref so first-paint matches saved state */ + html.controls-collapsed-pref .page { grid-template-columns: minmax(0, 1fr); gap: 0; } + html.controls-collapsed-pref .page > .controls { display: none; } + html.controls-collapsed-pref .page > .timeline { border-right: none; padding-right: 0; } .timeline { border-right: 1px solid #ddd; padding-right: 1.25rem; min-height: 60vh; - min-width: 0; display: flex; flex-direction: column; + min-width: 0; display: flex; flex-direction: column; position: relative; } .controls { min-width: 0; } .game-tabs { display: flex; gap: 0.4rem; margin-bottom: 0.5rem; flex-wrap: wrap; } @@ -185,6 +202,26 @@ } .camera-tile.needs-tap .tap-play { display: flex; } + /* PiP mode: when a screen is being shared, cameras get out of the way — + * they float as a small vertical strip in the bottom-right of the + * timeline column, layered over the screen tile. Standard Zoom/Meet + * pattern. Scrolls vertically if there are more than fit. The screen + * keeps the full timeline width so 1080p screen-share stays huge. */ + .timeline:has(> #sec-screens:not(.hidden)) > #sec-cameras { + position: absolute; right: 0.6rem; bottom: 0.6rem; + width: clamp(180px, 22%, 320px); + max-height: 70vh; overflow-y: auto; + z-index: 50; padding: 0.35rem; + background: rgba(0,0,0,0.55); + border-radius: 4px; + } + .timeline:has(> #sec-screens:not(.hidden)) > #sec-cameras > h2 { + color: #ddd; font-size: 0.75rem; margin: 0 0 0.3rem; border-bottom: none; + } + .timeline:has(> #sec-screens:not(.hidden)) #cameras { grid-template-columns: 1fr; gap: 0.3rem; } + .timeline:has(> #sec-screens:not(.hidden)) .camera-tile video { max-height: 16vh; } + .timeline:has(> #sec-screens:not(.hidden)) .camera-tile .screen-meta { font-size: 0.6rem; padding: 0.15rem 0.3rem; } + /* latency panel: one row per live PC, fixed-width columns so the numbers * line up vertically as values bounce. lat-good < 50ms, mid < 150ms, * bad ≥ 150ms — colour-tagged so the user can scan at a glance. */ @@ -319,10 +356,18 @@ try { document.documentElement.classList.add('theme-dark'); } } catch(_){ document.documentElement.classList.add('theme-dark'); } +/* sidebar-collapsed pre-paint: apply to so the .page child can + * read it via :has() or via a body-level class added on DOMContentLoaded */ +try { + if (localStorage.getItem('zebra-spaces-controls-v1') === 'hidden'){ + document.documentElement.classList.add('controls-collapsed-pref'); + } +} catch(_){} +
@@ -538,6 +583,28 @@ $('btn-theme').addEventListener('click', () => { try { localStorage.setItem(THEME_KEY, goDark ? 'dark' : 'light'); } catch(_){} applyThemeLabel(); }); + +/* controls-panel collapse — promotes the pre-paint pref onto the + * .page element, then keeps both in sync on click. Pre-paint class on + * stays so a fresh load with a saved 'hidden' pref still shows + * the layout collapsed instantly. */ +const CONTROLS_KEY = 'zebra-spaces-controls-v1'; +function applyControlsLabel(){ + const hidden = document.querySelector('.page').classList.contains('controls-collapsed'); + const btn = $('btn-controls-toggle'); if (btn) btn.textContent = hidden ? 'show panel' : 'hide panel'; +} +if (document.documentElement.classList.contains('controls-collapsed-pref')){ + document.querySelector('.page').classList.add('controls-collapsed'); +} +applyControlsLabel(); +$('btn-controls-toggle').addEventListener('click', () => { + const page = document.querySelector('.page'); + const goHidden = !page.classList.contains('controls-collapsed'); + page.classList.toggle('controls-collapsed', goHidden); + document.documentElement.classList.toggle('controls-collapsed-pref', goHidden); + try { localStorage.setItem(CONTROLS_KEY, goHidden ? 'hidden' : 'shown'); } catch(_){} + applyControlsLabel(); +}); const VAULT_PREFIX = 'zspc-id-v1|'; const PBKDF2_ITER = 600000; @@ -2183,8 +2250,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');