fix(#6105): close the drawer-over-picker stacking class via z-index, not per-site guards

Codex found the body-reparented picker (z-200, later body child) could be revealed
UNDER a full-screen drawer/panel via multiple paths (swipe, breakpoint resize,
profile-switch). Rather than guard each open-site (whack-a-mole + my resize guard
over-fired on keyboard reflows), fix the class once: .model-dropdown--floating gets
z-index:190 — above the composer-mobile-config-panel (z-180) it opens from, below
the mobile sidebar + workspace panel (both z-200) — so any drawer/panel that opens
covers the picker, matching master's stacking intent. Reverted the two boot.js
guards. Co-authored-by webtecnica.
This commit is contained in:
nesquena-hermes committed 2026-07-16 01:15:11 +00:00
1 parent 7ed58510bc
commit a69bc3a264
2 files changed
+9 -24

No files matched your search

-22
View File
@@ -436,11 +436,6 @@ function _openMobileSidebarFromGesture(){
if(_isDesktopWidth())return;
const sidebar=document.querySelector('.sidebar');
if(!sidebar)return;
// #6105/#6080: the phone model picker is reparented to <body> at z-index:200,
// the same level as the sidebar — as a later body child it would paint ON TOP
// of the drawer. Close it first (which also restores it into the footer) so a
// left-edge swipe reveals the session drawer cleanly, not an orphaned popover.
try{if(typeof closeModelDropdown==='function')closeModelDropdown();}catch(_){}
try{if(typeof _syncMobileSidebarPanelFromMainView==='function')_syncMobileSidebarPanelFromMainView();}catch(_){}
const layout=document.querySelector('.layout');
if(layout)layout.classList.remove('sidebar-collapsed');
@@ -2482,23 +2477,6 @@ function applyEmptyStateSuggestionPref(){
}
window.addEventListener('resize',()=>{
// #6105/#6080: the floating phone model picker is a <body> child at z-index:200,
// the same level as the mobile sidebar drawer and the workspace panel. A direct
// landscape/tablet→phone resize can re-reveal an already-open drawer/panel
// *underneath* the picker (no click fires, so outside-click-close doesn't run).
// Close + restore the picker before we re-sync drawer state, but only when a
// phone-width layout will actually surface one of those z-200 siblings — so an
// ordinary keyboard/URL-bar reflow doesn't dismiss the picker mid-use.
try{
if(typeof closeModelDropdown==='function' && !_isDesktopWidth()){
const dd=document.getElementById('composerModelDropdown');
if(dd&&dd.classList.contains('open')){
const drawerOpen=!!document.querySelector('.sidebar.mobile-open');
const panelOpen=(typeof _workspacePanelMode!=='undefined'&&_workspacePanelMode&&_workspacePanelMode!=='closed');
if(drawerOpen||panelOpen) closeModelDropdown();
}
}
}catch(_){}
_syncWorkspacePanelInlineWidth();
syncWorkspacePanelState();
if(!window.visualViewport) _forceMobileViewportReflow();
+9 -2
View File
@@ -3253,8 +3253,15 @@
Geist Contrast skin — both establish a fixed containing block that would
otherwise resolve `fixed` against the FOOTER, dropping the menu below the
fold). Same idiom as #profileDropdown. JS owns left/top/width/maxHeight; this
rule only flips positioning and relaxes the desktop width clamps. */
.model-dropdown.model-dropdown--floating{position:fixed;left:0;bottom:auto;min-width:0;}
rule only flips positioning and relaxes the desktop width clamps.
z-index:190 is deliberate: ABOVE the .composer-mobile-config-panel (z-180) it
can be opened from, but BELOW the full-screen mobile sidebar drawer and
workspace panel (both z-200) — so whenever one of those surfaces opens (by
swipe, breakpoint resize, profile-switch, or any future path) it covers the
picker, exactly as it did on master when the picker lived inside the composer's
lower stacking context. This single stacking rule closes the whole "drawer
opened behind the floating picker" class without per-open-site guards. */
.model-dropdown.model-dropdown--floating{position:fixed;left:0;bottom:auto;min-width:0;z-index:190;}
.model-scope-note{position:sticky;top:0;z-index:2;padding:9px 14px;border-bottom:1px solid var(--border);color:var(--text);font-size:11px;font-weight:650;line-height:1.4;background:color-mix(in srgb,var(--surface) 82%,var(--accent-bg));box-shadow:0 1px 0 rgba(0,0,0,.12);}
.model-group{padding:8px 14px 4px;font-size:10px;font-weight:700;letter-spacing:.04em;color:var(--muted);text-transform:uppercase;border-top:1px solid var(--border2);margin-top:2px;}.model-group.collapsible{cursor:pointer;user-select:none}.model-group.collapsible:before{content:'\25b6';display:inline-block;font-size:8px;margin-right:5px;transition:transform .15s ease}.model-group.collapsible.open:before{transform:rotate(90deg)}.model-group-body:empty{display:none}
.model-group.sub{padding:4px 14px 2px 22px;font-size:9px;border-top:none;margin-top:0;letter-spacing:.03em;color:var(--muted);background:transparent;}.model-group.sub.collapsible:before{content:'\25b6';display:inline-block;font-size:7px;margin-right:4px;transition:transform .15s ease}.model-group.sub.collapsible.open:before{transform:rotate(90deg)}.model-group-body.sub{padding-left:8px;border-left:1px solid var(--border);}