diff --git a/server/public/connect.html b/server/public/connect.html index 9e7612d..34805d1 100644 --- a/server/public/connect.html +++ b/server/public/connect.html @@ -43,10 +43,10 @@ .topbar2{background:var(--card);border-bottom:1px solid var(--line);padding:.5rem 1rem;display:none;justify-content:space-between;align-items:center;} .topbar2.show{display:flex;} #barStatus{font-weight:600;font-size:.9rem;color:var(--blue);} #endBtn{padding:.45rem 1rem;background:#fee2e2;color:#b91c1c;border:none;border-radius:8px;font-weight:600;cursor:pointer;} - #video{width:100vw;height:calc(100vh - 46px);background:#0b1220;object-fit:contain;display:none;cursor:crosshair;outline:none;} - /* Control bar sits vertically on the RIGHT; reserve a thin right strip so the screen uses the full - height/width otherwise (maximised view) and the icons never overlay the shared content. */ - body.has-bar #video{width:calc(100vw - 76px);} + #video{width:100vw;height:100vh;background:#0b1220;object-fit:contain;display:none;cursor:crosshair;outline:none;} + /* The control bar floats over the bottom-right corner (tiny icons), so the shared screen uses the + FULL viewport underneath it. */ + body.has-bar #video{width:100vw;height:100vh;} body.has-bar{background:#0b1220;} .profile{position:relative} .profile .pbtn{display:flex;align-items:center;gap:.4rem;background:rgba(255,255,255,.14);color:#fff;border:1px solid #46598c;border-radius:10px;padding:.45rem .85rem;font-weight:600;font-size:.88rem;cursor:pointer} @@ -323,15 +323,19 @@ function buildBar(){ { const hl=document.getElementById('homeLink'); if(hl) hl.style.display='none'; } bzcSession(true); const bar=document.createElement('div'); bar.id='sessionBar'; - bar.style.cssText='position:fixed;right:14px;top:50%;transform:translateY(-50%);z-index:2147483000;display:flex;flex-direction:column;gap:10px;align-items:center;background:rgba(15,23,42,.94);padding:12px 8px;border-radius:16px;box-shadow:0 10px 28px rgba(0,0,0,.35)'; - const mic=_btn('micBtn',SVG_MIC,'Mic','#2563eb'); - const chat=_btn('chatBtn',SVG_CHAT,'Chat','#475569'); - const rec=_btn('recBtn',SVG_REC,'','#0ea5e9'); rec.title='Record'; rec.querySelectorAll('span').forEach((s,i)=>{ if(i>0) s.remove(); }); - const end=_btn('endBtn2',SVG_END,'End','#dc2626'); + // Floats over the bottom-right corner with tiny icons, so the shared screen fills the whole viewport. + bar.style.cssText='position:fixed;right:16px;bottom:16px;z-index:2147483000;display:flex;flex-direction:row;gap:8px;align-items:center;background:rgba(15,23,42,.72);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:7px 9px;border-radius:14px;box-shadow:0 8px 22px rgba(0,0,0,.35)'; + const I=(n)=>(window.ic?window.ic(n,16):''); + const mic=_btn('micBtn',I('mic'),'Mic','#2563eb'); + const chat=_btn('chatBtn',I('chat'),'Chat','#334155'); + const rec=_btn('recBtn','','Record','#334155'); + const end=_btn('endBtn2',I('callEnd'),'End','#dc2626'); bar.appendChild(mic);bar.appendChild(chat);bar.appendChild(rec);bar.appendChild(end); document.body.appendChild(bar); - document.body.classList.add('has-bar'); // reserve space so the bar never overlays the shared screen - mic.onclick=()=>{const m=window.__mic;if(!m)return;const t=m.getAudioTracks()[0];if(!t)return;t.enabled=!t.enabled;mic.title=t.enabled?'Mute':'Unmute';mic.innerHTML=''+(t.enabled?SVG_MIC:SVG_MICOFF)+'';mic.style.background=t.enabled?'#2563eb':'#6b7280';}; + document.body.classList.add('has-bar'); + // Shrink from the default 48px round to a compact 38px so they read as "tiny icons". + [mic,chat,rec,end].forEach(b=>{ b.style.width='38px'; b.style.height='38px'; b.style.boxShadow='none'; }); + mic.onclick=()=>{const m=window.__mic;if(!m)return;const t=m.getAudioTracks()[0];if(!t)return;t.enabled=!t.enabled;mic.title=t.enabled?'Mute':'Unmute';mic.innerHTML=''+I(t.enabled?'mic':'micOff')+'';mic.style.background=t.enabled?'#2563eb':'#6b7280';}; chat.onclick=toggleChat; rec.onclick=()=>{ if(mediaRecorder&&mediaRecorder.state==='recording') stopRecording(); else startRecording(); }; end.onclick=()=>{ try{ws.send(JSON.stringify({type:'end-session',sessionId,reason:'agent-ended'}));}catch(_){} }; @@ -378,16 +382,33 @@ async function setupPeer(){ else if(s==='connected'){ clearTimeout(pc._dt); } }; } const send=(o)=>{if(inputChannel&&inputChannel.readyState==='open')inputChannel.send(JSON.stringify(o));}; -const rel=(e)=>{const r=video.getBoundingClientRect();return{x:(e.clientX-r.left)/r.width,y:(e.clientY-r.top)/r.height};}; +// Map a pointer event to NORMALIZED coords over the actual VIDEO CONTENT, not the