fix(ios/mobile): safe-area insets, no keyboard auto-open, no h-scroll, swipe-back, hide desktop-download
Reported on the iOS TestFlight build: - #1/#5 notch/home-indicator: apply top safe-area inset per surface (chat list column + content panels) instead of on the whole shell, so headers sit below the Dynamic Island and nothing is cut off top/bottom. - #2: opening a chat no longer auto-focuses the composer (was popping the phone keyboard and shoving the layout up); tapping the box still focuses normally. - #3: overflow-x:hidden + max-width:100vw guards so pages can't pan left/right. - #4: left-edge swipe-right now triggers the existing bzcBack() (close popup/search/open chat) — a native-feeling back gesture with no native code. - #6: hide the 'Download app' (Windows) button when running inside the Capacitor app. Build marker -> 2026-07-17-batch90. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+27
-6
@@ -1020,7 +1020,13 @@
|
||||
relocated into the chat-list header (see placeHdrRight). The shell is pushed below the
|
||||
device status bar so no view overlaps it. */
|
||||
header{display:none;}
|
||||
.shell{padding-top:env(safe-area-inset-top,0px);}
|
||||
/* #3: kill any horizontal drift on phones (long content, 100vw children, safe-area math) — the page
|
||||
should never pan left/right. */
|
||||
html,body{overflow-x:hidden;max-width:100vw;}
|
||||
.shell,.content,.chatcol,.panel,.convo,.convo-msgs,.chatlist{overflow-x:hidden;max-width:100%;}
|
||||
/* #1/#5: the top safe-area inset (notch / Dynamic Island) is applied PER SURFACE — the chat-list
|
||||
column and each content panel — rather than on the whole shell, so nothing hides under the island
|
||||
and there's no double-padding. Bottom inset is handled by the fixed nav + panel bottom below. */
|
||||
.side-title{gap:.5rem;}
|
||||
.side-title h2{flex:1;}
|
||||
.side-title #hdrRight{display:flex;align-items:center;gap:.4rem;flex:0 0 auto;}
|
||||
@@ -1046,12 +1052,12 @@
|
||||
/* Meeting room code: always fully visible, full-width, easy to read */
|
||||
.meet-bar .code{flex:1 1 100%;font-size:.9rem;white-space:normal;word-break:break-word;text-align:center;background:var(--blue-soft);border-radius:8px;padding:.35rem .5rem;}
|
||||
/* Chat: one pane at a time (list, then the open conversation) */
|
||||
.chatcol{width:100%;flex:1 1 100%;padding-bottom:calc(60px + env(safe-area-inset-bottom,0px));}
|
||||
.chatcol{width:100%;flex:1 1 100%;padding-top:env(safe-area-inset-top,0px);padding-bottom:calc(60px + env(safe-area-inset-bottom,0px));}
|
||||
body.chat-open .chatcol{display:none;}
|
||||
.content{display:none;}
|
||||
body.chat-open .content, .shell:not(.is-chat) .content{display:block;}
|
||||
.shell:not(.is-chat) .chatcol{display:none;}
|
||||
.content .panel{bottom:calc(60px + env(safe-area-inset-bottom,0px));} /* clear the bottom nav + home indicator */
|
||||
.content .panel{top:env(safe-area-inset-top,0px);bottom:calc(60px + env(safe-area-inset-bottom,0px));} /* below the notch; clear the bottom nav + home indicator */
|
||||
/* Bigger touch targets */
|
||||
.chat-row{padding:.7rem .85rem;}
|
||||
.convo-head{padding:.7rem .85rem;}
|
||||
@@ -1078,7 +1084,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<script src="/icons.js?v=6"></script>
|
||||
<script>window.__BUILD='2026-07-15-batch89';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
<script>window.__BUILD='2026-07-17-batch90';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
// Emoji are rendered with the OS's own (colour) emoji font — instant, zero network.
|
||||
//
|
||||
// We used to run Twemoji over every emoji, which swapped each one for an <img> pulled INDIVIDUALLY from
|
||||
@@ -2713,7 +2719,7 @@ async function openConvo(kind,id){
|
||||
// are still safely on the server → the "messages disappear after reopen" bug). Keep the cached
|
||||
// render; only show empty if we truly have nothing cached to fall back to.
|
||||
if(!THREAD_CACHE.has(ckey)){ THREAD=[]; renderThread(); }
|
||||
const inp0=document.getElementById('msgInput'); if(inp0) inp0.focus();
|
||||
const inp0=document.getElementById('msgInput'); if(inp0 && !isMobileUA()) inp0.focus(); // #2: don't auto-open the phone keyboard on chat open
|
||||
return;
|
||||
}
|
||||
THREAD=msgs;
|
||||
@@ -2728,7 +2734,7 @@ async function openConvo(kind,id){
|
||||
const el=document.querySelector('#msgs .bubble[data-id="'+esc+'"]') || document.querySelector('#msgs [data-id="'+esc+'"]');
|
||||
if(el){ const sep=document.createElement('div'); sep.className='new-sep'; sep.innerHTML='<span>New messages</span>'; el.parentNode.insertBefore(sep, el); el.scrollIntoView({block:'start'}); el.parentNode.scrollTop-=40; const jl=document.getElementById('jumpLatest'); if(jl) jl.style.display='grid'; }
|
||||
}
|
||||
const inp=document.getElementById('msgInput'); if(inp) inp.focus();
|
||||
const inp=document.getElementById('msgInput'); if(inp && !isMobileUA()) inp.focus(); // #2: on phones, opening a chat should NOT pop the keyboard (user taps the box to type)
|
||||
}
|
||||
// ---------- @mentions (group chat) ----------
|
||||
let mentionItems=[], mentionIdx=0, mentionStart=-1;
|
||||
@@ -4611,6 +4617,21 @@ function bzcBack(){
|
||||
}
|
||||
try{ history.pushState(null,'',location.href); }catch(_){}
|
||||
window.addEventListener('popstate', ()=>{ if(bzcBack()){ try{ history.pushState(null,'',location.href); }catch(_){} } });
|
||||
// #4: iOS/Android have no on-screen back button in a full-screen webview, so give the app a native-feeling
|
||||
// left-edge SWIPE-back: a drag that begins at the very left edge and moves clearly rightward closes the
|
||||
// topmost layer (popup → in-conversation search → open chat) via the same bzcBack() used for the OS back.
|
||||
(function(){
|
||||
let sx=0, sy=0, edge=false;
|
||||
window.addEventListener('touchstart',(e)=>{
|
||||
if(e.touches.length!==1){ edge=false; return; }
|
||||
const t=e.touches[0]; edge = t.clientX<=24; sx=t.clientX; sy=t.clientY; // only arm when starting at the left edge
|
||||
}, {passive:true});
|
||||
window.addEventListener('touchend',(e)=>{
|
||||
if(!edge) return; edge=false;
|
||||
const t=e.changedTouches&&e.changedTouches[0]; if(!t) return;
|
||||
if((t.clientX-sx)>60 && Math.abs(t.clientY-sy)<50) bzcBack(); // rightward, mostly-horizontal swipe = back
|
||||
}, {passive:true});
|
||||
})();
|
||||
// Hamburger: on mobile it slides the rail drawer in/out; on desktop it collapses the rail.
|
||||
function toggleNav(){ if(window.innerWidth<=760) document.body.classList.toggle('rail-open'); else document.body.classList.toggle('rail-hidden'); }
|
||||
const _navT=document.getElementById('navToggle'); if(_navT) _navT.onclick=toggleNav;
|
||||
|
||||
Reference in New Issue
Block a user