← back to Designer Wallcoverings
pending-approval/done/collection-grid-toolbar-and-image-perf.DONE.md
197 lines
# Collection grid toolbar (item 2) + oversized images (item 3) — diagnosis, DTD verdicts, gated steps
**Owner:** vp-dw-commerce · **Drafted:** 2026-06-23 · **Status:** decisions committed; live publishes + Boost-admin change AWAITING STEVE
**Live theme resolved dynamically:** role==main = **142250278963 "Steves Version 5.0"** (verified; old 143739584563 is UNPUBLISHED).
Backup of live collection assets: `shopify/theme-backups/2026-06-23-live-142250278963/`.
---
## ITEM 2 — DTD verdicts (panel: Claude + Codex + Qwen, both 3/3 unanimous)
**Call A — desktop density slider → KEEP-SLIDER.** **Call B — mobile infinite-scroll → HOLD-for-approval.**
### A) Desktop density slider is ALREADY satisfied on LIVE — no live change needed
The live collection renders TWO desktop-visible density sliders:
- `{% include 'collection-toolbar' %}` (sections/collection.liquid line 151) → a `.density-control`
range slider (3–12 cols, localStorage `dw_collection_density`) hidden ONLY at ≤768px / ≤480px,
i.e. **fully visible + working on desktop**.
- `assets/dw-grid-control.js` → an injected `.dw-gc` slider (1–8 cols, localStorage `dw-grid-cols`),
no media gating.
Verified on the live page: `density-control`/`densitySlider`/`dw-grid-control` markup present (16
hits), `collectionSort` sort dropdown present (9 hits). **The "slider removed on desktop" report was
a DEV-THEME state, now superseded — live is compliant with Steve's standing sort+density rule.**
*(Optional cleanup, non-gated, can do on request: TWO desktop density sliders is redundant —
recommend retiring `dw-grid-control.js` and keeping the toolbar one. Not done yet; say the word.)*
### B) Mobile infinite-scroll — HOLD on dev, do NOT publish to live (gated). ✓ honored.
### Dev-theme consolidation — ONE base, but it carries a REGRESSION to fix first
| Theme | toolbar | density.js | filters | verdict |
|---|---|---|---|---|
| LIVE 142250278963 | ✓ | ✓ | **SNIPPET** via `{% render %}` (correct) | source of truth |
| dev 143933472819 "5.1" | ABSENT | ABSENT | ABSENT | stale/partial — **retire** |
| dev 143947038771 "★ Grid+Infinite FIX" | ✓ (infinite-scroll variant) | ✓ | **SECTION** via `{%- section … -%}` (line 85) ⚠️ | consolidation base, **needs snippet-port** |
⚠️ **143947038771 still has the exact regression we fixed on live:**
`sections/collection.liquid` line 85 = `{%- section 'collection-filters-horizontal' -%}` — the
"Cannot render sections inside sections" form. It must be converted to the snippet
`{% render 'collection-filters-horizontal' %}` (and the snippet file copied from live) BEFORE this
dev theme is ever considered for publish. Consolidation plan (dev-theme writes only, reversible):
1. Make 143947038771 the single dev theme; copy from live → dev: `snippets/collection-filters-horizontal.liquid`,
and change dev `sections/collection.liquid` line 85 to `{% render 'collection-filters-horizontal' %}`.
2. Restore the desktop density slider behavior to match live (it already has the toolbar; just confirm
no desktop-hiding media query crept in).
3. Keep its mobile infinite-scroll + 2-col mobile grid + responsive desktop cols.
4. Delete/retire 143933472819.
**I can execute steps 1–4 on the DEV theme on your go** (dev writes, not live). Publishing the
consolidated theme to LIVE is the gated action below.
---
## ITEM 3 — Oversized collection-grid images — CORRECTED DIAGNOSIS (supersedes the Boost-admin theory below)
> **⚠️ The earlier "it's the Boost image-size admin setting" conclusion was WRONG.** Re-measured
> in-browser at desktop 1440px AND mobile 390px on BOTH the live theme (142250278963) and the dev
> theme (143947038771). The **Boost HYDRATED grid renders CORRECTLY** (`.boost-sd__product-item`:
> 8 cards @ ~403px desktop / ~57px mobile, images at `width=700`). **The Boost image-size setting
> does NOT need changing.** The struck-through text below is retained only as a record of the
> superseded theory.
### What is actually oversized (measured)
The "huge images" are **theme-native `.product-list-item` cards rendering full-width (1240–1440px)**
in two distinct places, neither of which is the live Boost grid:
1. **Stale Boost server-rendered FALLBACK (collection page).** `.boost-sd__product-filter-fallback`
is Boost's pre-hydration server markup, meant to be hidden once Boost hydrates. On live it is
**never hidden** — its theme `section.collection` + loose `article.product-list-item` cards stack
full-width below the real grid (measured fallback height ~7,768px of giant cards; collection
`pageH` 14,308px). **TRAP:** the GOOD hydrated grid (`.boost-sd-container` / `.boost-sd__product-item`)
is *nested inside the same `.boost-sd__product-filter-fallback` container*, so a naive
`display:none` on the fallback zeros the good grid too. The fix must hide the **stale theme branch
only** (`section.collection` + loose cards), never `.boost-sd-container`.
2. **Orphaned featured-collection cards (homepage).** Home `.product-list-item` cards that the
theme's `grid.js` was supposed to lay into `.home-products-content` are left **orphaned attached
directly to `.main-content` / `<body>`** (DOM-probed: cards #4/#7 are direct children of `<body>`),
rendering at full 1440px. This is a downstream symptom of the **grid.js init-abort** documented in
the companion memo `grid-js-init-abort-and-dev-build.md` (a section ctor throws → `_initSections`
aborts → the featured-collection carousel never lays the cards out).
(The theme's `snippets/product-list-item.liquid` / `rimg.liquid` ARE correct — `size:'600x600'`,
`srcset`, lazy. The cards are blown out because they're rendered **outside any grid container**, not
because the image source is wrong.)
### The STAGED fix (dev theme 143947038771, reversible, dev-only — NOT live)
A single CSS block appended to `assets/custom.css` (which `layout/theme.liquid` links on every page),
marked `/* >>> dw-collection-grid-fix START >>> */ … END`, removable in one pass. Source of truth:
`shopify/grid-js-fix/dw-collection-grid-fix.css`. Backup of the pre-edit dev asset:
`shopify/grid-js-fix/backups/custom.css.dev-143947038771.before`.
What it does:
- **(A) Collection:** scoped to `body.boost-sd__search-widget-init-enabled` (Boost's post-hydration
body class), hides the stale theme fallback (`.boost-sd__product-filter-fallback > section.collection`,
loose `article.product-list-item`, and `.shopify-section:not(:has(.boost-sd-container))`) while
explicitly keeping `.boost-sd-container article.product-list-item` visible. Pre-hydration the
fallback still shows (no flash of empty grid).
- **(B) Homepage:** forces `section.home-products` into a responsive CSS grid and clamps every
`.product-list-item` (and any card orphaned onto `body`/`.main-content`) to `max-width:360px` so a
card can **never** render full-bleed — even if `grid.js` init still partially fails. This is the
DTD-approved (3/3, 2026-06-23) defensive net; the `grid.js` init-abort fix in the companion memo
remains the primary mechanism.
### Measured before → after (TESTED — staged CSS applied to the real served DOM, both viewports)
| Page / viewport | BLOWN `.product-list-item` (>500px) BEFORE | AFTER | Boost hydrated grid AFTER |
|---|---|---|---|
| Home @1440 | 5 (max 1440px) | **0** (7 cards visible, ≤360px) | n/a |
| Collection @1440 | 7 (max 1440px) | **0** (stale hidden) | **intact: 8 @403px** |
| Home @390 | 0 | **0** (7 visible, ≤360px) | n/a |
| Collection @390 | 0 | **0** (stale hidden) | **intact: 8 @57px** |
Collection `pageH` after fix: 14,308px → **2,754px** (the stacked giant cards are gone). Homepage
`pageH`: 10,063px → 3,896px.
**Honest scope of proof:** CSS application is deterministic — the measurements above are the *real
collection/home page DOM* with this exact CSS applied. The staged CSS is confirmed present on dev
theme 143947038771's `custom.css` via the Admin API (marker found, 41,241 bytes). The one thing I
could NOT do headless: load the dev theme through Shopify's `?preview_theme_id=` URL — anonymous
(non-admin) requests are served the LIVE theme's assets, not the dev theme's (`devCssServed=false`
in the served-preview probe). So the final pixel-perfect confirm on the *served dev theme* is the
authenticated **Preview** button, which only Steve can open.
### Steve — verify on dev, then approve the live push
**Verify (authenticated):** Shopify admin → Online Store → Themes → "★ 5.0 Grid+Infinite FIX"
(143947038771) → **Preview** → open the homepage and
`/collections/acoustical?pf_t_product_type=Wallcovering&pf_t_color=Green`. Paste in console:
```js
({ blown: [...document.querySelectorAll('.product-list-item img')].filter(i=>i.getBoundingClientRect().width>500).length,
boost: document.querySelectorAll('.boost-sd__product-item').length })
// WANT: blown === 0, boost === 8 (collection) ; on home blown === 0 with cards still visible
```
**Live-push commands I will run on your go** (theme token via `/secrets` `SHOPIFY_THEME_TOKEN`,
never hardcoded; appends the SAME marked block to LIVE 142250278963's `custom.css`, idempotent,
backs up first):
```bash
TOKEN=$(grep -m1 '^SHOPIFY_THEME_TOKEN=' ~/Projects/secrets-manager/.env | cut -d= -f2- | tr -d '"')
LIVE=142250278963
cd ~/Projects/Designer-Wallcoverings
# 1) backup live custom.css
python3 - "$TOKEN" "$LIVE" <<'PY'
import sys,json,urllib.request,urllib.parse
tok,t=sys.argv[1],sys.argv[2]
q=urllib.parse.urlencode({'asset[key]':'assets/custom.css'})
u=f"https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/themes/{t}/assets.json?{q}"
v=json.load(urllib.request.urlopen(urllib.request.Request(u,headers={'X-Shopify-Access-Token':tok})))['asset']['value']
open(f'shopify/grid-js-fix/backups/custom.css.live-{t}.before','w').write(v); print('backed up',len(v),'bytes')
PY
# 2) append the marked fix block (idempotent) and PUT to live
python3 - "$TOKEN" "$LIVE" <<'PY'
import sys,re,json,urllib.request,urllib.parse
tok,t=sys.argv[1],sys.argv[2]
q=urllib.parse.urlencode({'asset[key]':'assets/custom.css'})
base=json.load(urllib.request.urlopen(urllib.request.Request(
f"https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/themes/{t}/assets.json?{q}",
headers={'X-Shopify-Access-Token':tok})))['asset']['value']
fix=open('shopify/grid-js-fix/dw-collection-grid-fix.css').read()
S='/* >>> dw-collection-grid-fix START >>> */'; E='/* <<< dw-collection-grid-fix END <<< */'
base=re.sub(re.escape(S)+r'.*?'+re.escape(E),'',base,flags=re.S).rstrip()+'\n'
out=base+'\n'+S+'\n'+fix+'\n'+E+'\n'
body=json.dumps({'asset':{'key':'assets/custom.css','value':out}}).encode()
r=urllib.request.urlopen(urllib.request.Request(
f"https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/themes/{t}/assets.json",
data=body,method='PUT',headers={'X-Shopify-Access-Token':tok,'Content-Type':'application/json'}))
print('PUT live custom.css OK ->', json.load(r)['asset']['size'],'bytes')
PY
# 3) re-verify the live URLs (node verify-final-css-fix.js style, no injection)
```
*Rollback:* re-PUT `shopify/grid-js-fix/backups/custom.css.live-142250278963.before`, or strip the
marked block.
---
<details><summary>SUPERSEDED theory (kept for the record — do NOT act on this)</summary>
~~The visible grid on `/collections/...` is rendered by the Boost AI Search & Filter app … sized by
Boost's product-item image-size setting in the Boost app admin … Fix (Steve, in Boost SD admin): set
a sane max width.~~ — **Wrong.** The Boost hydrated grid renders correctly; the oversized cards are
the stale theme fallback + orphaned home cards (see corrected diagnosis above). No Boost-admin change
is needed.
</details>
---
## Steve, paste to proceed
- [ ] OK to run dev-theme consolidation steps 1–4 on 143947038771 (dev writes only, fixes the line-85 regression)
- [ ] After dev is clean + you review the preview, approve PUBLISH of the consolidated theme to LIVE (infinite-scroll goes live then)
- [ ] **ITEM 3 (CORRECTED):** I verified the dev Preview (blown===0, Boost grid intact) → **approve the
live-push of the `dw-collection-grid-fix` CSS block to LIVE 142250278963's `custom.css`** (commands above).
- [ ] ~~Set the Boost SD product-image max width in the Boost admin~~ — **NOT NEEDED** (superseded; the Boost grid is fine).
- [ ] (Optional) retire the redundant second desktop density slider (`dw-grid-control.js`)
**Note:** This item-3 CSS fix is complementary to the `grid.js` init-abort fix in
`grid-js-init-abort-and-dev-build.md` — the CSS net is the belt, the grid.js fix is the suspenders.
Both are staged on dev 143947038771; do both.
**$ cost:** $0 (local Playwright + read-only public pages + read/write theme API to the UNPUBLISHED
dev theme only). One DTD panel: local Qwen (free) + Codex ~**$0.0035**. Total ≈ **$0.004**.