diff --git a/voice-poc/public/app.js b/voice-poc/public/app.js index 381639c..3bb755f 100644 --- a/voice-poc/public/app.js +++ b/voice-poc/public/app.js @@ -536,14 +536,46 @@ function renderTiles() { renderStageEmpty(); } -function renderScreens() { - els.screens.innerHTML = ''; +// share keys: 'me' or peer id; popped-out shares render in their own window +const poppedWindows = new Map(); // key -> {win, name} + +function activeShares() { const shares = []; - if (S.sharing && S.screenStream) shares.push({ name: `${S.name} (you)`, stream: S.screenStream }); + if (S.sharing && S.screenStream) shares.push({ key: 'me', name: `${S.name} (you)`, stream: S.screenStream }); for (const peer of S.peers.values()) { - if (peer.screenStream) shares.push({ name: peer.name, stream: peer.screenStream }); + if (peer.screenStream) shares.push({ key: peer.id, name: peer.name, stream: peer.screenStream }); } - for (const share of shares) { + return shares; +} + +function renderScreens() { + // prune popouts whose share ended + const live = new Set(activeShares().map((s) => s.key)); + for (const [key, p] of [...poppedWindows]) { + if (!live.has(key)) { + try { p.win.close(); } catch {} + poppedWindows.delete(key); + } + } + + els.screens.innerHTML = ''; + els.screens.classList.toggle('multi', activeShares().length > 1); + for (const share of activeShares()) { + if (poppedWindows.has(share.key)) { + // rendered in its own window — show a small placeholder card to re-embed + const ph = document.createElement('div'); + ph.className = 'screen-card popped'; + const btn = document.createElement('button'); + btn.className = 'pop-btn'; + btn.textContent = '⧉ re-embed'; + btn.onclick = () => closePopout(share.key); + const label = document.createElement('div'); + label.className = 'label'; + label.textContent = `${share.name} — popped out`; + ph.append(btn, label); + els.screens.appendChild(ph); + continue; + } const card = document.createElement('div'); card.className = 'screen-card'; const video = document.createElement('video'); @@ -556,11 +588,47 @@ function renderScreens() { label.className = 'label'; label.innerHTML = '●'; label.appendChild(document.createTextNode(share.name)); - card.append(video, label); + const pop = document.createElement('button'); + pop.className = 'pop-btn'; + pop.title = 'Pop out in new window'; + pop.textContent = '⧉'; + pop.onclick = () => popOutShare(share); + card.append(video, label, pop); els.screens.appendChild(card); } } +function popOutShare(share) { + if (poppedWindows.has(share.key)) return; + const win = window.open('', `share-${share.key}`, 'width=960,height=540'); + if (!win) { + toast('Pop-out blocked by the browser — allow pop-ups for this page', 'error'); + return; + } + win.document.write(`