diff --git a/html/work-package-suite-styles.css b/html/work-package-suite-styles.css index 06027b1..6199e45 100644 --- a/html/work-package-suite-styles.css +++ b/html/work-package-suite-styles.css @@ -31,23 +31,43 @@ body { min-height: 100vh; } -/* HEADER — dark UI Shell bar */ +/* HEADER — dark UI Shell bar + Four groups share this bar, not two: .header-left and .header-right are in the + markup, and wp-chrome.js injects the project switcher and search between them + while auth-guard.js appends the user menu after. At 1024px that is more than + fits on one 48px line, and a fixed height meant the overflow had nowhere to go + but on top of its neighbours. min-height + wrap lets the bar grow instead. + One row still measures exactly 48px, so nothing moves at desk width. */ .header { background: var(--appbar); color: #fff; padding: 0 16px; - height: 48px; + min-height: 48px; display: flex; + flex-wrap: wrap; + row-gap: 6px; justify-content: space-between; align-items: center; } +/* Sizes to its content and never narrower than the logo. + This was `flex: 1; min-width: 0`, which put it in a dead tie with the chrome + wp-chrome.js injects as its sibling (`flex: 1 1 auto; min-width: 0`): both + claimed the same run of the bar, both were allowed to shrink to nothing, and + the chrome's wider content won every time. .header-left computed to 0 while + its `flex-shrink: 0` logo kept its 106px and overflowed — so the project + switcher rendered straight across the logo (F3). + Now the chrome is the only one that grows, and `min-width: auto` restores the + content-based floor, which is the logo plus the gap: the inner title block + keeps its own `min-width: 0`, so the project name still gives way first, by + the ellipsis .header-subtitle already carries. Truncation policy itself is + B2's, not this task's. */ .header-left { - flex: 1; + flex: 0 1 auto; display: flex; align-items: center; gap: 14px; - min-width: 0; + min-width: auto; } /* Prime logo (white-background wordmark) sits in a white chip on the dark bar */ @@ -95,10 +115,16 @@ body { text-overflow: ellipsis; } +/* Holds its natural size. Left to the default `flex-shrink: 1` it was squeezed + narrower than its buttons, so "Load Sample" ran underneath "Feedback". The + chrome between the two groups is the only flexible one, which is what gives + the three a defined order of giving way: right keeps its buttons, left keeps + its logo, the middle absorbs the difference. */ .header-right { display: flex; align-items: center; gap: 8px; + flex: 0 0 auto; } .header-button { diff --git a/tests/f_items.py b/tests/f_items.py index 5170e60..a9187ae 100644 --- a/tests/f_items.py +++ b/tests/f_items.py @@ -204,15 +204,41 @@ def f3(page, base, tok): wait_for="!!document.querySelector('.header-left')") time.sleep(0.9) got = page.eval("""(function(){ - var hl=document.querySelector('.header-left'), - logo=document.querySelector('.header-left .logo'), - ch=document.querySelector('.wpc-proj')||document.querySelector('.wp-chrome'); - if(!hl||!logo||!ch) return 'null'; - var L=logo.getBoundingClientRect(), C=ch.getBoundingClientRect(); - var ox=Math.min(C.right,L.right)-Math.max(C.left,L.left); - var oy=Math.min(C.bottom,L.bottom)-Math.max(C.top,L.top); + var hdr=document.querySelector('.header'), + hl=document.querySelector('.header-left'), + logo=document.querySelector('.header-left .logo'); + if(!hdr||!hl||!logo) return 'null'; + // Every group sharing this bar, not just the two the review named: the + // markup's own, plus what wp-chrome.js and auth-guard.js inject into it. + var boxes=[]; + ['.header-left','.wp-chrome','.header-right','#wp-usermenu'].forEach(function(s){ + var e=hdr.querySelector(s); if(!e) return; + var r=e.getBoundingClientRect(); + if(r.width>0||r.height>0) boxes.push({s:s,r:r}); + }); + var pairs=[]; + for(var i=0;i1&&oy>1) pairs.push(boxes[i].s+'/'+boxes[j].s+' '+Math.round(ox)+'x'+Math.round(oy)); + } + // The logo is flex-shrink:0 and keeps its width even when its parent is + // crushed, so check it against the chrome directly too. + var ch=hdr.querySelector('.wpc-proj')||hdr.querySelector('.wp-chrome'); + var lox=0,loy=0; + if(ch){var L=logo.getBoundingClientRect(),C=ch.getBoundingClientRect(); + lox=Math.min(C.right,L.right)-Math.max(C.left,L.left); + loy=Math.min(C.bottom,L.bottom)-Math.max(C.top,L.top);} + // Anything spilling past the bar lands on the tab row underneath it. + var H=hdr.getBoundingClientRect(), spill=0; + [].forEach.call(hdr.children,function(e){ + var r=e.getBoundingClientRect(); + if(r.width===0&&r.height===0) return; + if(r.bottom>H.bottom+1||r.top0, hlsw:hl.scrollWidth, hlcw:hl.clientWidth, name:((document.querySelector('.wpc-proj-name')||{}).textContent||'').trim()});})()""") @@ -225,6 +251,10 @@ def f3(page, base, tok): why.append(f"chrome over the logo by {o['ox']}x{o['oy']}px") if o["collapsed"]: why.append(f".header-left collapsed to 0 (content {o['hlsw']}px)") + if o["pairs"]: + why.append("overlapping groups: " + "; ".join(o["pairs"])) + if o["spill"]: + why.append(f"{o['spill']} group(s) spilling out of the bar") if why: hits.append(f"{w}px: " + ", ".join(why)) else: