From 7c879e603881e98f5a69270564e32d1c34f69a2a Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Thu, 24 Sep 2026 00:20:15 -0700 Subject: [PATCH] fix(review): the heid code-review and bug-hunt panels on r2c, folded (both 4/4 with retries) - 1:1 start-aligns. The centred flex item overflowed both sides and the start was unreachable; measured, a 3000px picture hid its leftmost 980px. Auto margins still centre a small picture. - Drag lifecycle: a move with no button ends the drag, so a press released outside the stage never pans on a later hover. Capture is now load-bearing in a test. The threshold is 4px of total movement. - A press on the stage's own scrollbar is never a pan. The arrows clamp to the stage's client box, so they are never under a classic scrollbar. The test runs a browser without --hide-scrollbars and asserts the gutter exists. - Stacked, the arrows' CSS spot is the stage's centre (30vh), set in view.html because base.html lost to the page's later rule. - The stage reveal is `hidden` until bound, and keeps Fit's drop shadow when revealed. A blurred picture composes blur() drop-shadow(). - The mode follows another tab. A failed or unknown size returns the arrows to their CSS spot. - Tests: object-position, vertical centring, the Fit half of aria-pressed, a storage read that throws, a large picture's toggle, Fit forgetting 1:1, single-axis pan. - Declared: the r2b reveal test reads "no blur" (the shadow stays), and the r2_flow 360px-offset row is retired. Mutation tables 137/137 across four. 810 passed. --- booth/templates/base.html | 15 +- booth/templates/view.html | 55 ++++- docs/contracts/r2c_review_stage.contract.md | 74 +++++-- tests/mutations/r2_flow.toml | 14 +- tests/mutations/r2c.toml | 201 ++++++++++++++++- tests/test_flow_browser.py | 233 +++++++++++++++++++- 6 files changed, 546 insertions(+), 46 deletions(-) diff --git a/booth/templates/base.html b/booth/templates/base.html index 754653c..339cd28 100644 --- a/booth/templates/base.html +++ b/booth/templates/base.html @@ -660,6 +660,10 @@ .reveal-all .tray-item.is-blurred img,.reveal-all .film-f.is-blurred img, .reveal-all .review .vstage.is-blurred img,.reveal-all .review .vstage.is-blurred video{filter:none} .reveal-all .item.blurred .reveal,.reveal-all #vreveal{display:none} + /* a revealed review picture keeps Fit's shadow on its own pixels (r2c) */ + .review .vstage.is-img.is-blurred.revealed img,.reveal-all .review .vstage.is-img.is-blurred img{ + filter:drop-shadow(0 10px 24px rgb(0 0 0 / .32))} + #vreveal[hidden]{display:none} /* The two booth-wide blur controls: the fog (server state, a form) and the reveal (this tab only, a button). Same quiet chip as the rest of the chrome. */ .blur-all{display:inline-block;margin:0} @@ -755,9 +759,11 @@ .vstage.is-img img{width:100%;height:100%;object-fit:contain; filter:drop-shadow(0 10px 24px rgb(0 0 0 / .32))} /* 1:1 β€” the pixel truth. The mode is `stage-one` on (set before the - stage exists). Auto margins centre a small picture and still let a large - one scroll from its true edge. */ - .stage-one .vstage.is-img{overflow:auto;padding:0} + stage exists). START alignment, never centring: a centred flex item larger + than its scroll box overflows BOTH sides, and the start side can never be + scrolled to (heid code-review; measured: a 3000px picture hid its leftmost + 980px). Auto margins still centre a picture smaller than the stage. */ + .stage-one .vstage.is-img{overflow:auto;padding:0;justify-content:flex-start;align-items:flex-start} .stage-one .vstage.is-img img{flex:none;width:auto;height:auto;max-width:none;max-height:none;margin:auto;object-fit:fill} /* r2c S4: a 1:1 picture larger than the stage pans by dragging */ .stage-one .vstage.can-pan{cursor:grab;user-select:none} @@ -779,6 +785,9 @@ .review .vstage audio{width:min(640px,92%)} .review .vstage video{max-width:100%;max-height:100%} .review .vstage.is-blurred img,.review .vstage.is-blurred video{filter:blur(22px)} + /* `filter` is one property: a blur rule REPLACES the shadow unless it says + both (heid code-review, groa). A blurred review picture keeps Fit's shadow. */ + .review .vstage.is-img.is-blurred img{filter:blur(22px) drop-shadow(0 10px 24px rgb(0 0 0 / .32))} .review .vstage.is-blurred.revealed img,.review .vstage.is-blurred.revealed video{filter:none} .review-body > .reveal{position:absolute;top:14px;left:14px;z-index:5;cursor:pointer;font-family:var(--font-mono); font-size:var(--size-micro);padding:6px 9px;border-radius:var(--radius-md);border:1px solid rgb(255 255 255 / .16); diff --git a/booth/templates/view.html b/booth/templates/view.html index aeb21b2..9028d49 100644 --- a/booth/templates/view.html +++ b/booth/templates/view.html @@ -55,7 +55,9 @@ {# The stage's reveal sits OVER the stage, outside its scrolled content (r2c): in 1:1 a panned picture would otherwise carry it out of view, and outside the stage it can never start a pan. #} - {% if blurred %}{% endif %} + {# JS-only, so `hidden` until the script binds it (heid bug-hunt: shown with + scripts off, it did nothing) β€” the toggle's own pattern. #} + {% if blurred %}{% endif %} {% if next_url %}β€Ί{% endif %}