poster cards: print options wrap to full words instead of an ellipsis
The Driver rejected the ellipsis by name: the print options must LINE WRAP so
every label stays readable, because a button that no longer says what it does
has not been fixed.
Three measurements drove the CSS:
- a <fieldset> takes min-width:min-content from the UA stylesheet, which
OVERRIDES width and max-width. .pfs read width:82% while computing 431px
inside a 212px card. min-width:0 goes on the fieldset ITSELF, not only on
its children.
- the row is anchored at its TOP (top:100%;margin-top:-14px), not its bottom.
At bottom:-14px every extra line grew UPWARD over the preview image, which
is how the first overflow fix broke the card it was meant to repair.
- wrapping took the row from 35px to 78px, so the grid's row gap moves 64px
to 88px. The old gap was tuned when the row was a single line.
No text-overflow anywhere in .pfs. min-width:0 alone had let three 76-79px
labels share 172px, showing 40px each.
The gate gains the assertion that would have caught the ellipsis: a control is
clipped when scrollWidth exceeds clientWidth. Mutation-tested -- restoring
text-overflow:ellipsis reproduces 81 of 108 clipped and exits 1. Without that
assertion the gate passed a wall whose buttons all read "Pra...".
Measured at 390/768/1024/1440/1920px: 0 clipped, 0 overflow, 0 over-preview,
0 neighbour intrusions, 108 controls.
This commit is contained in:
parent
661133dd5c
commit
608ef3dd56
6 changed files with 98 additions and 72 deletions
|
|
@ -103,9 +103,15 @@ async function measure(width) {
|
|||
}
|
||||
const ctrls = all.filter((e) => /\\b(pbtn|pstock)\\b/.test((e.className||'').toString())).filter(vis)
|
||||
const tiny = ctrls.filter((e) => { const b = e.getBoundingClientRect(); return b.width < 18 || b.height < 10 })
|
||||
// FITS is not READABLE, and this gate asserted only the weaker one. A control 40px wide passes
|
||||
// every size check while showing five characters of a 76px label — measured, 81 of 108 controls
|
||||
// clipped, with Prayer List and Poster Map both rendering as Pra... A row made to fit by hiding
|
||||
// what its buttons SAY has not been fixed. scrollWidth > clientWidth is the browser telling us
|
||||
// the text did not fit its box.
|
||||
const clipped = ctrls.filter((e) => e.scrollWidth > e.clientWidth + 1)
|
||||
return { cards: cards.length, rows: cards.filter((c) => c.querySelector('.pfs')).length,
|
||||
overflowing, worst, intrusions, coveringPreview, worstY,
|
||||
previewsPainted, previewsBroken, noPreview,
|
||||
previewsPainted, previewsBroken, noPreview, clipped: clipped.length,
|
||||
controls: ctrls.length, tiny: tiny.length }
|
||||
})()`)
|
||||
await page.close()
|
||||
|
|
@ -128,7 +134,7 @@ for (const r of results) {
|
|||
+ ` · over-preview ${r.coveringPreview}${r.worstY ? ` (${r.worstY}px)` : ''}`
|
||||
+ ` · previews ${r.previewsPainted} painted`
|
||||
+ `${r.previewsBroken ? `/${r.previewsBroken} BROKEN` : ''}${r.noPreview ? `/${r.noPreview} none` : ''}`
|
||||
+ ` · ${r.controls} control(s), ${r.tiny} too small`)
|
||||
+ ` · ${r.controls} control(s), ${r.tiny} too small, ${r.clipped} clipped`)
|
||||
}
|
||||
|
||||
const fails = []
|
||||
|
|
@ -144,6 +150,13 @@ for (const r of results) {
|
|||
fails.push(`${at}: ${r.tiny} print control(s) shrank below a usable size — fitting the row by `
|
||||
+ 'crushing the buttons is not a fix')
|
||||
}
|
||||
// AND THE LABELS MUST BE READABLE. Same failure in a subtler form: the control keeps a usable
|
||||
// BOX while its text is ellipsised away, so a reader cannot tell Prayer List from Poster Map.
|
||||
if (r.clipped) {
|
||||
fails.push(`${at}: ${r.clipped} of ${r.controls} print control(s) have CLIPPED labels `
|
||||
+ '(scrollWidth exceeds clientWidth) — the button is big enough to press and no longer says '
|
||||
+ 'what it does')
|
||||
}
|
||||
// The row belongs BELOW the preview. Driver-reported 2026-09-24: "the download print options are
|
||||
// not showing up under the blue outline, they are overlapping where the blue outline would be".
|
||||
// THE PREVIEW MUST ACTUALLY BE THERE. A card with no image passes every geometry assertion
|
||||
|
|
|
|||
|
|
@ -436,7 +436,11 @@ useShadowStyles(
|
|||
// GAP must clear the OVERHANGING TAPES, not just the card boxes: the header tape
|
||||
// sits at top:-11px and the footer fieldset at bottom:-14px, so a 26px row gap
|
||||
// left ~1px of real air and the wall read as one dense block.
|
||||
'.grid{display:grid;gap:64px 30px;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));' +
|
||||
// ⚠ THE ROW GAP MUST CLEAR THE PRINT ROW. .pfs hangs BELOW its card (top:100%, margin-top:-14px),
|
||||
// so the vertical gap is what keeps it off the next card. 64px was tuned when that row was one
|
||||
// line at 35px; wrapping it to two lines takes 78px and needs 78-14=64 — exactly the gap, with
|
||||
// nothing spare, which showed up as 5 rows intruding into the card below. 88px leaves real room.
|
||||
'.grid{display:grid;gap:88px 30px;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));' +
|
||||
'max-width:1180px;margin:0 auto}' +
|
||||
'.card{position:relative;background:#fff;border:1px solid #e3e6ea;border-radius:3px;' +
|
||||
'padding:24px 12px 26px;box-shadow:0 1px 3px rgba(0,0,0,.10),0 6px 18px rgba(0,0,0,.07);' +
|
||||
|
|
@ -467,24 +471,33 @@ useShadowStyles(
|
|||
// the card's outline. Horizontal overflow traded for vertical. min-width:0 alone lets the
|
||||
// controls compress on ONE line, which is what the row was always meant to be.
|
||||
// The gate that passed this only measured horizontal edges; it now measures the row's top too.
|
||||
'.pfs{position:absolute;bottom:-14px;left:50%;transform:translateX(-50%);' +
|
||||
// ⚠ ANCHORED AT THE TOP, NOT THE BOTTOM. This was bottom:-14px, so any growth pushed the row
|
||||
// UPWARD over the preview — which is exactly how wrapping it turned a sideways overflow into
|
||||
// a vertical one the driver saw. Anchoring at top:100% pins it just under the card, so the
|
||||
// second line grows DOWN into empty space. MEASURED: 92px between the preview's bottom and
|
||||
// the next card, of which the single-line row used 35 — 51px spare.
|
||||
'.pfs{position:absolute;top:100%;margin-top:-14px;left:50%;transform:translateX(-50%);' +
|
||||
// ⚠ min-width:0 ON THE FIELDSET ITSELF. A <fieldset> gets `min-width:min-content` from the
|
||||
// UA stylesheet, which OVERRIDES width and max-width — measured: computed width 431px
|
||||
// inside a 212px card while the rule said 82%. That is the real reason `width:82%` read as
|
||||
// correct in source for so long and the row still burst the card.
|
||||
'width:82%;max-width:82%;min-width:0;box-sizing:border-box;margin:0;padding:0 4px 3px;' +
|
||||
'border:1px solid rgba(0,0,0,.14);' +
|
||||
'border-radius:2px;background:#fff;display:flex;flex-wrap:nowrap;gap:2px;justify-content:center;' +
|
||||
'border-radius:2px;background:#fff;display:flex;flex-wrap:wrap;gap:2px;justify-content:center;' +
|
||||
'box-shadow:0 1px 4px rgba(0,0,0,.10)}' +
|
||||
// Let every control shrink inside the row rather than push it open. overflow:hidden +
|
||||
// text-overflow keeps a squeezed label readable instead of spilling.
|
||||
'.pfs > .pbtn,.pfs > .pstock{min-width:0;max-width:100%;overflow:hidden;' +
|
||||
'text-overflow:ellipsis;white-space:nowrap}' +
|
||||
// ⚠ NO ELLIPSIS CRUSH. min-width:0 alone let three 76-79px labels share 172px — 40px each,
|
||||
// about five characters, so 'Prayer List' and 'Poster Map' both read 'Pra…'. MEASURED: 81
|
||||
// of 108 controls clipped. Fitting a row by hiding what its buttons say is not fitting it.
|
||||
// flex-basis:auto + wrap lets each control take the width its LABEL needs and flow to a
|
||||
// second line, which there is room for now that the row grows downward.
|
||||
'.pfs > .pbtn{flex:0 1 auto;min-width:0;white-space:nowrap}' +
|
||||
// ⚠ THE <select> IS THE ONE THAT WILL NOT SHRINK. Measured: with min-width:0 applied to
|
||||
// every child, .pstock still rendered 188px inside a 198px row because a <select> sizes to
|
||||
// its WIDEST OPTION and `flex:0 1 auto` keeps that as its basis. flex-basis:0 makes it share
|
||||
// the row like the buttons do; a cap keeps it from dominating the three text controls.
|
||||
'.pfs > .pstock{flex:1 1 0;max-width:38%}' +
|
||||
'.pfs > .pstock{flex:0 1 auto;min-width:0;max-width:100%}' +
|
||||
'.is-dark .pfs{background:#132019;border-color:rgba(110,231,183,.24)}' +
|
||||
'.pfs > legend{margin:0 auto;padding:0 5px;font-size:8px;text-transform:uppercase;' +
|
||||
'letter-spacing:.6px;font-weight:700;color:#8a93a0}' +
|
||||
|
|
|
|||
122
public/doxa-maps/my-upg-100-list/my-upg-100-list.js
generated
122
public/doxa-maps/my-upg-100-list/my-upg-100-list.js
generated
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-4QjITklNF8dldIMyzCtJ89iM0orN98L0CNHUbBo04Vtis/xxe1qkkEFQkCF/04i7" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-P80Is4VW2RBIxrqlYITNybtR8AiaxsbngqobOVFGhmc8IrGXraMzYexAuyZcTtVF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-4QjITklNF8dldIMyzCtJ89iM0orN98L0CNHUbBo04Vtis/xxe1qkkEFQkCF/04i7" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-P80Is4VW2RBIxrqlYITNybtR8AiaxsbngqobOVFGhmc8IrGXraMzYexAuyZcTtVF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-4QjITklNF8dldIMyzCtJ89iM0orN98L0CNHUbBo04Vtis/xxe1qkkEFQkCF/04i7" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-P80Is4VW2RBIxrqlYITNybtR8AiaxsbngqobOVFGhmc8IrGXraMzYexAuyZcTtVF" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue