Repository navigation
Fix product-card overflow and pager wrapping; align Playwright image pin - #62
Merged
Merged
Conversation
The product card's info row could not shrink: .availability was white-space: nowrap and .price is flex: none, so on mobile columns (~165-195px of inner width) 'While Stock Lasts' plus a 199.99 pill needed more room than the card had and the pill rendered outside the card's right edge. Below 720px the row now stacks (label above pill); elsewhere the label wraps instead of overflowing. The pager did not wrap because it was too wide — it wrapped because its width changed. pageWindow() returned 3 items on page 1, 4 on page 2, 5 on page 3 and 7 mid-range, so the control resized on every page change and the widest case overflowed, dropping Next onto a second line. It now always emits exactly slots items (7 desktop, 5 mobile via matchMedia mirroring MOBILE_BREAKPOINT), ellipses occupy the same 38px box as a page button, and mobile compacts the buttons with icon-only Prev/Next under 400px. Constant slot count also makes bridging a one-page gap free, so that behaviour is kept. Also fixes an unrelated hover bug spotted while verifying: the current page's label went invisible on hover, because .pagination button:hover (0,2,1) outranks .pagination .active-page (0,2,0) and repainted the background light while the text stayed near-white. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
tests/e2e pinned @playwright/test 1.62.0 while .devcontainer/Dockerfile
still pinned the v1.61.1-noble image, so every e2e test failed to launch
a browser ('Please update docker image as well') and main was red. Bump
the image and the version strings that document it.
That surfaced two WebKit 26 behaviour changes:
- Registering a service worker while page.route() interception is active
wedges the page: waitForTimeout still resolves but every protocol call
(locator.count, evaluate, screenshot) times out. AlertsModal registers
/sw.js on open, which hung all four modal specs on webkit only. Confirmed
by aborting /sw.js — the modal then opens and the page stays responsive.
routeOffers() now aborts it; the SPA specs never exercise the worker and
pwa*.spec.ts, which do, never mock routes.
- PushManager/Notification are now exposed headlessly, so isPushSupported()
is true and the modal renders its .push-row (+84px, exactly the snapshot
delta). Genuine capability change, so alerts-modal-webkit.png is
re-recorded.
Also anchor the root .gitignore's Python build dirs (/lib/, /lib64/):
unanchored 'lib/' matched frontend/src/lib/ at any depth, and git only kept
the app source because frontend/.gitignore re-includes it — tooling that
reads just the root file treats the whole tree as ignored.
Verified in the rebuilt image: make test green (unit, installer, e2e 89/89
across all engines, load, security).
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Devin Review asked whether the desktop baselines were genuinely unaffected by dropping white-space: nowrap on .availability, or whether the 0.02 maxDiffPixelRatio was hiding a change. Measured it: renders are byte-stable across repeat runs (control passes), and with the nowrap version as a zero-tolerance baseline the same browser produces a page 1px taller (1280x1398 -> 1280x1399, 6706 differing pixels, ratio 0.01). So the grid snapshots were passing on tolerance, not on being identical — exactly the masking the review flagged. Re-record all visual baselines with the 1.62.0 browsers this PR pins, so they reflect the actual rendering instead of being stale-but-tolerated. harness-smoke's static-fixture snapshots are unchanged. Also document two implicit things the review called out: the mobile slot count encodes radius = (slots - 5) / 2, so 5 slots deliberately means no ±1 neighbours and 7 is the minimum to get them back; and routeOffers() aborting /sw.js applies to every caller, so a future offline assertion in those specs would silently test a no-SW app. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the two reported layout bugs, plus the pre-existing breakage that had to be cleared to verify them.
Card price-pill overflow.
.product-infocould not shrink —.availabilitywaswhite-space: nowrapand.priceisflex: none— so on mobile columns (~165–195px of inner width) "While Stock Lasts" plus a199.99pill needed more space than the card had, and the pill rendered outside the card's right edge. Below 720px the row now stacks (label above pill); everywhere else the label wraps instead of overflowing.Pager wrapping. The pager did not wrap because it was too wide, it wrapped because its width changed:
pageWindow()returned 3 items on page 1, 4 on page 2, 5 on page 3 and 7 mid-range, so the control resized on every page change and the widest case overflowed, droppingNextonto a second line. It now always emits exactlyslotsitems (7 desktop / 5 mobile viamatchMedia, mirroringMOBILE_BREAKPOINT), ellipses occupy the same 38px box as a page button, and mobile compacts the buttons with icon-only Prev/Next under 400px.Bonus bug found while verifying: hovering the current page button made its label invisible —
.pagination button:hover(specificity 0,2,1) outranks.pagination .active-page(0,2,0), repainting the background light while the text stayed near-white.Unblocking
main(second commit).tests/e2epinned@playwright/test@1.62.0while.devcontainer/Dockerfilestill pinnedv1.61.1-noble, so every e2e test failed to launch a browser and CI was red. Bumping the image surfaced two WebKit 26 changes, both root-caused rather than papered over:page.route()interception is active wedges the page —waitForTimeoutstill resolves but every protocol call times out.AlertsModalregisters/sw.json open, which hung all four modal specs on webkit only.routeOffers()now aborts**/sw.js; the SPA specs don't exercise the worker andpwa*.spec.ts, which do, never mock routes.PushManager/Notificationare now exposed headlessly, soisPushSupported()is true and the modal renders its.push-row(+84px, exactly the snapshot delta). Genuine capability change, soalerts-modal-webkit.pngis re-recorded.Also anchors the root
.gitignore's Python build dirs (/lib/,/lib64/): unanchoredlib/matchedfrontend/src/lib/at any depth, and git only kept the app source becausefrontend/.gitignorere-includes it — tooling that reads only the root ignore file treats the whole app tree as ignored.Test plan
make testpasses locally in the rebuilt image (unit, installer, e2e 89/89 across chromium/firefox/webkit/chromium-push, load, security)pageWindownow asserts a constant slot count, ordering, uniqueness and clamping over every page of several ranges; the e2e pager spec asserts the slot count and pager height do not change while paging.Notes for the reviewer
< 1 … 4 … 23 >— the ±1 neighbours are dropped, because 7 slots cannot fit one line at 320px even compacted. Paging stays one tap via Prev/Next, and arrow-key paging is unaffected.aria-label="Previous page"/"Next page"so the accessible names survive hiding the words under 400px; the one e2e selector that usedname: 'Next'was updated..npmrc(legacy-peer-deps=true, added onmainjust before this branch) is validated here —npm ciworks in the container again. Worth remembering it is repo-wide and will also silence real peer conflicts, e.g. the vite/vitest/vite-plugin-svelte chain documented inCLAUDE.md.CLAUDE.mdso the next agent does not re-derive them.Generated with Devin