fix: MPS-24 — facets compose; sort+price survive switching category

Operator: 'switching one breaks it' — picking a category reset the
active Sort + Price. Cause: facet category links / 'All' link / top
chips / lane 'See all' all pointed at a bare {tag_base}/tag/{slug}
with NO query string, so a click dropped ?sort= / ?price_*. (The
Sort select / Price form already preserved the tag via action='' +
path and each other as sibling fields — only category nav lost state.)

Fix: one shared facet_qs(sort_key, price_min, price_max) macro in
_facet_nav.j2 returning the ?sort=...&price_min=...&price_max=...
suffix, appended to every category/All/chip/See-all href in
_facet_nav.j2, home.j2, shop.j2. URL state, NOT localStorage
(operator's suggestion): shareable, no-JS, back-button correct, and
the destination SERP already reads those params. The & is HTML-escaped
to & in hrefs (Jinja autoescape) — browsers decode it fine.

Tests: +test_facet_links_preserve_sort_and_price; updated
test_tag_detail_renders_facet_sidebar +
test_facet_category_link_renders_tag_detail_not_home for the new
(correct) query-carrying behavior. 1135 passed.

Docs: mps-24.md Phases 2.8e–2.8h.
This commit is contained in:
russell@unturf.com 2026-05-16 11:22:23 -04:00
parent bcd8c2471b
commit 3bb05e4b5d
No known key found for this signature in database
5 changed files with 107 additions and 11 deletions

View file

@ -363,7 +363,40 @@ Tests (`test_functional.py::TestProductTagsSpa`):
Deferred (occasional click, not the hot path): AJAX-ifying the
"Suggest categories" link — still a full navigation by design.
**Phase 2.8e — the LAST link: `form.action` DOM-clobbered** (shipped
**Phase 2.8h — facets compose, not clobber** (shipped 2026-05-16):
operator: "switching one breaks it" — picking a category reset the
active Sort + Price. Cause: the facet category links / "All" link /
top chips / lane "See all" all pointed at a bare
`{tag_base}/tag/{slug}` with **no query string**, so a click dropped
`?sort=` / `?price_*`. (The Sort `<select>`/Price form already
preserved the tag via `action=""` + path, and each other as sibling
fields — only category navigation lost state.) Fix: one shared
`facet_qs(sort_key, price_min, price_max)` macro in `_facet_nav.j2`
returning the `?sort=…&price_min=…&price_max=…` suffix; appended to
every category/All/chip/See-all href in `_facet_nav.j2`, `home.j2`,
`shop.j2`. URL state, **not localStorage** (operator's suggestion):
shareable, no-JS, back-button correct, and the destination SERP
already reads those params. Tests:
`test_facet_links_preserve_sort_and_price`,
updated `test_tag_detail_renders_facet_sidebar` /
`test_facet_category_link_renders_tag_detail_not_home`.
**Phase 2.8g — facet sidebar nested scrollbar removed** (shipped
2026-05-16): `ul.facet-tag-list` had `max-height:60vh;
overflow-y:auto` → ugly inner scrollbar on the sidebar / mobile
accordion. Dropped; the list flows full-height and the page scrolls.
**Phase 2.8f — chips navigate to the tag SERP like the left nav**
(shipped 2026-05-16): the top chip strip's category links already
pointed at `{tag_base}/tag/{slug}`, but `tag_filter.js` decided
whether to intercept by inspecting **`chips[0]`** — the "All" chip,
which points at the shop home (no `/tag/`) — so it never detected the
real category links and always did the in-place "default cards"
hide/show. Now it scans ALL chips: any `/tag/` href → bail → full
navigation, so a chip behaves exactly like its matching left-nav
category (server renders the SERP in the shop's `home_layout`).
**Phase 2.8e — `form.action` DOM-clobbered by `<input name=action>`** (shipped
2026-05-16): with 2.8d live, the operator's Network panel showed the
proxy-proof `ajax=1` working (a real `fetch` to `tags` → 200, 0.7 kB
JSON) — but also four requests to a URL literally named