diff --git a/docs/reference/file-map.md b/docs/reference/file-map.md index 3be9a2d..9a6a349 100644 --- a/docs/reference/file-map.md +++ b/docs/reference/file-map.md @@ -229,6 +229,35 @@ cannot decide says `INCONCLUSIVE`. --- +## The project switcher: what it shows at each width (`B2`, `T2.3`) + +Written here because `T2.3` says to, so it is not re-litigated. Test name is always +**"Micron EUV Cleanroom Enable 2667008"** — the real one, and the one that breaks things. + +| Width | The app bar shows | Why | +|---|---|---| +| **≥ 1024px** | the full project **name** | There is room. The cap is raised to 400px (button) / 340px (name) so a real name fits without an ellipsis. | +| **< 1024px** | the project **number** alone, e.g. `2667008` | Short, stable, unambiguous. Dropping the name entirely beats shortening it to "Micron EUV Clean…" on the one control whose job is to tell you which job you are in. | + +The number is not prefixed to the name at wide widths. Real project names already end +with their number, so `2667008 — Micron EUV Cleanroom Enable 2667008` printed it twice. + +**The full name is reachable at every width by three routes**, none of them hover-only +(Field View is a touch surface — `C1`): + +1. **The drawer** — `.wp-sidenav-proj`, under the drawer head, on every page. Wraps onto + as many lines as it needs and is never truncated. This is the guaranteed one. +2. **The switcher's `title`** — the full `number — name`, so it surfaces on hover *and* + on keyboard focus. +3. **The switcher popover** — every project is listed with its full name and number. + +The ellipsis is kept only as a backstop for a name longer than anything real. Verified +at 390, 768, 1024 and 1440: no truncation at any of them, and the drawer carries the +whole name at all four. + +`T1.1` correctness is preserved — with a project active the switcher never reads +"Select a project"; with none active it reads exactly that at every width. + ## Discrepancies Things the plan asserts that the repo contradicts. Listed per T0.1's fourth done-when. diff --git a/html/wp-chrome.css b/html/wp-chrome.css index 60b9ed9..027a559 100644 --- a/html/wp-chrome.css +++ b/html/wp-chrome.css @@ -90,6 +90,13 @@ text-transform: uppercase; color: var(--wpc-fg-dim); } +/* B2. These two caps are the "does not fit 280px" the review measured: a real name + ran past 240px and was ellipsised on the one control whose job is to say which job + you are in. Above 1024px the bar has the room, so the caps are raised until a real + project name fits — "Micron EUV Cleanroom Enable 2667008" is the one to test with. + Below 1024px the label is the project number instead (see wp-chrome.js), which is + short enough that these caps never bite. The ellipsis stays only as a backstop for + a name longer than anything real. */ .wpc-proj-name { display: block; font-weight: 600; @@ -98,6 +105,10 @@ text-overflow: ellipsis; max-width: 240px; } +@media (min-width: 1024px) { + .wpc-proj-btn { max-width: 400px; } + .wpc-proj-name { max-width: 340px; } +} .wpc-caret { flex: 0 0 auto; align-self: flex-end; margin-bottom: 3px; font-size: 10px; line-height: 1; color: var(--wpc-fg-dim); } diff --git a/html/wp-chrome.js b/html/wp-chrome.js index 027de73..9fc8f3f 100644 --- a/html/wp-chrome.js +++ b/html/wp-chrome.js @@ -67,10 +67,31 @@ try { return (window.ProjectData && ProjectData.getActive()) || null; } catch (e) { return null; } } + // B2 breakpoint plan. "Micron EUV Cleanroom Enable 2667008" does not fit the bar, + // and an ellipsis at every width gives you "Micron EUV Clean…" on the one control + // whose job is to tell you which job you are in. So the bar drops the name rather + // than shortening it: below 1024px it shows the project NUMBER alone, which is + // short, stable and unambiguous. The full name is never more than a hover, a focus + // or the drawer away — see projectTitle() and the drawer head. + // Documented in docs/reference/file-map.md. + var WIDE = '(min-width: 1024px)'; + function isWide() { + try { return window.matchMedia(WIDE).matches; } catch (e) { return true; } + } function projectLabel(p) { if (!p) return 'Select a project'; var n = p.name || '(unnamed)'; - return p.number ? (p.number + ' — ' + n) : n; + if (!p.number) return n; // no number to fall back to + // Wide: the name, which is what people recognise, and which usually carries the + // number inside it anyway ("Micron EUV Cleanroom Enable 2667008") — prefixing the + // number there printed it twice. Narrow: the number alone. + return isWide() ? n : p.number; + } + // Always the whole thing, whatever the bar is showing. + function projectTitle(p) { + if (!p) return 'Select a project'; + var n = p.name || '(unnamed)'; + return (p.number ? (p.number + ' — ' + n) : n) + ' — switch project'; } // Switching project reloads the current page with ?project=. Every page @@ -146,8 +167,18 @@ var c = activeProject(); var nameEl = btn.querySelector('.wpc-proj-name'); if (nameEl) nameEl.textContent = projectLabel(c); + // The full name stays reachable at every width, by hover and by keyboard focus. + btn.title = projectTitle(c); if (!pop.hidden) render(); }; + // Crossing the breakpoint has to re-label, or a resized window keeps whichever + // form was picked at load. + try { + var mq = window.matchMedia(WIDE); + var onChange = function () { wrap.wpcRefresh(); }; + if (mq.addEventListener) mq.addEventListener('change', onChange); + else if (mq.addListener) mq.addListener(onChange); + } catch (e) {} return wrap; } diff --git a/html/wp-sidenav.css b/html/wp-sidenav.css index edbca29..8bef14e 100644 --- a/html/wp-sidenav.css +++ b/html/wp-sidenav.css @@ -51,6 +51,24 @@ .wp-sidenav-head .wp-logo-chip{ flex: 0 0 auto; } .wp-sidenav-title{ font-size: 13px; font-weight: 600; line-height: 1.25; } .wp-sidenav-title span{ display: block; font-size: 11px; font-weight: 400; color: #a8a8a8; } + +/* The active project, in full (B2). Below 1024px the app bar shows the project + number alone, so this is where the whole name has to be readable — it wraps on + as many lines as it needs and is never truncated. */ +.wp-sidenav-proj{ + padding: 12px 14px; border-bottom: 1px solid #393939; flex: 0 0 auto; + display: flex; flex-direction: column; gap: 2px; +} +.wp-sidenav-proj[hidden]{ display: none; } +.wp-sidenav-proj-k{ + font-size: 10px; font-weight: 600; letter-spacing: .08em; + text-transform: uppercase; color: #a8a8a8; +} +.wp-sidenav-proj strong{ + font-size: 13px; font-weight: 600; line-height: 1.3; color: #f4f4f4; + overflow-wrap: anywhere; +} +.wp-sidenav-proj-n{ font-size: 11px; color: #c6c6c6; } .wp-sidenav-close{ margin-left: auto; width: 32px; height: 32px; padding: 0; flex: 0 0 auto; background: none; border: none; border-radius: 0; color: #c6c6c6; diff --git a/html/wp-sidenav.js b/html/wp-sidenav.js index db707c2..0488506 100644 --- a/html/wp-sidenav.js +++ b/html/wp-sidenav.js @@ -142,6 +142,10 @@ 'Work Package SuitePrime Controls' + '' + '' + + // The active project in full, wrapped rather than truncated. Below 1024px the + // app bar shows the project NUMBER alone (B2), so this is where the whole name + // is always readable. It is also the only place it is guaranteed to fit. + '
' + '
' + rows + '
' + '
' + (who ? '
Signed in as' + esc(who) + '
' : '') + @@ -167,6 +171,28 @@ }); document.body.appendChild(scrim); document.body.appendChild(drawer); + paintProject(); + // Selecting a project on the launcher does not reload, so subscribe rather than + // paint once — the same single source T1.1 established. + try { + if (window.ProjectData && ProjectData.onActiveChange) { + ProjectData.onActiveChange(paintProject); + } + } catch (e) {} + } + + // Full name, never abbreviated. Absent rather than empty when no project is active, + // so the drawer does not carry a stray blank band. + function paintProject() { + var box = document.getElementById('wp-sidenav-proj'); + if (!box) return; + var p = null; + try { p = (window.ProjectData && ProjectData.getActive && ProjectData.getActive()) || null; } catch (e) {} + if (!p || !(p.name || p.number)) { box.innerHTML = ''; box.hidden = true; return; } + box.hidden = false; + box.innerHTML = 'Project' + + '' + esc(p.name || '(unnamed)') + '' + + (p.number ? '' + esc(p.number) + '' : ''); } function focusables() {