[object Object]

← back to Designer Wallcoverings

Draft gated live-push memo + before/after screenshots for collection hero/dup-title/mobile-header fixes (DTD F1=B/F2=A/F3=A)

a3d6742ae7b5db0f17b9ffc7e57eca96783158f7 · 2026-06-23 15:18:08 -0700 · Steve Studio

Files touched

Diff

commit a3d6742ae7b5db0f17b9ffc7e57eca96783158f7
Author: Steve Studio <steve@designerwallcoverings.com>
Date:   Tue Jun 23 15:18:08 2026 -0700

    Draft gated live-push memo + before/after screenshots for collection hero/dup-title/mobile-header fixes (DTD F1=B/F2=A/F3=A)
---
 .../collection-hero-duptitle-mobileheader.md       | 122 +++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/pending-approval/collection-hero-duptitle-mobileheader.md b/pending-approval/collection-hero-duptitle-mobileheader.md
new file mode 100644
index 00000000..86338f60
--- /dev/null
+++ b/pending-approval/collection-hero-duptitle-mobileheader.md
@@ -0,0 +1,122 @@
+# Collection-page presentation fixes — hero band (F1), duplicate title (F2), mobile header gap (F3)
+
+**Owner:** vp-dw-commerce · **Drafted:** 2026-06-23 · **Status:** built + staged on DEV + verified on real DOM; LIVE push + 1 customizer setting + per-collection images AWAITING STEVE
+**Live theme (role==main, verified):** **142250278963 "Steves Version 5.0"**
+**Dev theme staged on:** **143947038771 "★ 5.0 Grid+Infinite FIX (approve)"** — the SAME dev theme carrying the companion grid.js + oversized-image fixes, so one Preview shows ALL collection-page fixes together.
+**Gate reason:** customer-facing writes to the published theme + a customizer setting + setting `collection.image` on collections.
+
+Pairs with `pending-approval/grid-js-init-abort-and-dev-build.md` (the two JS console errors below are owned by THAT memo) and `pending-approval/collection-grid-toolbar-and-image-perf.md` (oversized grid images). Do all three; they don't conflict — all staged on 143947038771.
+
+---
+
+## What was wrong (root-caused on the real live DOM, both viewports)
+
+| # | Defect | Root cause (measured) |
+|---|---|---|
+| **F1** | Ugly grey "pill" hero | The title "Products" renders as `h1.boost-sd__header-title` with `background: rgba(0,0,0,.55)`, radius 6px, white text, padding — a treatment **designed to overlay a hero IMAGE for legibility**. But **NO `collection.image` is set** (`hasFeaturedImage:false`), so the dark pill floats on a flat grey block = "horrible." Violates Steve's HARD rule that every collection MUST have a background hero image. |
+| **F2** | Title printed twice | Both Boost's `h1.boost-sd__header-title` AND the OOTS theme leftover `h1.page-title` render the same "Products" stacked. |
+| **F3** | Mobile header dead-gap | `theme.css` mobile media query sets `.header-branding{padding:36px 0}` → 118px-tall logo block with a big empty gap; `CART(0)` tools bar (42px) marooned at the very top. Measured mobile header height 160px, branding block 118px. |
+
+JS console errors on the page (`Cannot read properties of null (reading 'addEventListener')` and `... (reading 'dataset')`) are the **StaticHeader / ProductListItem init-abort** — already root-caused + fixed in `grid-js-init-abort-and-dev-build.md`, staged on this same dev theme. NOT re-fixed here (would duplicate). The CSP/403/410 console lines are third-party (shop.app embed + a pixel), not theme-fixable, out of scope.
+
+---
+
+## Decisions — DTD panel (Claude + Codex + Qwen), 2026-06-23
+
+- **F1 = B** (2/1; Claude dissented, accepts): always-on hero with a branded fallback. Use `collection.image` first → else a customizer default hero → else a polished imageless state. So a shopper NEVER sees the grey dead-state, and per-collection images take over the moment they're set. Claude's dissent (a single shared default makes collections look identical) is absorbed: B uses `collection.image` first, the default is only a floor.
+- **F2 = A** (3/3): hide the theme `page-title`, keep Boost's (Boost is the live grid + header renderer, carries the image + description).
+- **F3 = A** (3/3): minimal surgical mobile CSS, reversible.
+
+---
+
+## What is STAGED on dev 143947038771 (reversible, dev-only — NOT live)
+
+| Asset | Change | Backup |
+|---|---|---|
+| `assets/custom.css` | appended a single marked block `/* >>> dw-collection-hero-fix START >>> */ … END` — F1 hero band styling, F2 dup-title hide, F3 mobile-header CSS. Idempotent (re-appends cleanly). | `shopify/collection-hero-fix/backups/assets_custom.css.{live,dev}-*.before` |
+| `snippets/dw-collection-hero-bg.liquid` | NEW snippet — emits the per-collection hero `background-image` inline (`collection.image` → `settings.collection_default_hero` → none) and sets `body.dw-collection-has-hero` so the title switches between white-on-image pill and clean dark type. | n/a (new file; remove to revert) |
+| `sections/collection.liquid` | ONE line added near the top: `{% render 'dw-collection-hero-bg' %}` (needs `collection` scope). | `…/backups/sections_collection.liquid.{live,dev}-*.before` |
+| `config/settings_schema.json` | added a "Collection hero" group with an `image_picker` `collection_default_hero` (the branded fallback Steve picks in the customizer). | `…/backups/settings_schema.json.dev-*.before` |
+
+Source of truth for all four: `shopify/collection-hero-fix/` (`dw-collection-hero.css`, `snippets_dw-collection-hero-bg.liquid`, `patched/sections_collection.liquid`, `patched/settings_schema.json`).
+
+---
+
+## Verified (real DOM, both viewports) — `shopify/collection-hero-fix/screenshots/`
+
+The staged CSS + the snippet's exact inline output were applied to the **real live `/collections/all` DOM** at 1440px and 390px (iPhone-13), measured + screenshotted:
+
+| State | BEFORE | AFTER |
+|---|---|---|
+| **F1 no-image** (the real current state of most collections) | dark `rgba(0,0,0,.55)` pill on grey dead-block | title bg → **transparent**, color → **#1a1a1a clean centered uppercase** on a soft band — `dev-{desktop,mobile}-AFTER-noimage.png` |
+| **F1 with-image** (once `collection.image`/default is set) | n/a | photo fills the hero band, title returns to **white-on-dark pill** (`rgba(0,0,0,.42)`, white) — `dev-desktop-AFTER-withimage.png` |
+| **F2 dup title** | theme `page-title` visible:true | theme `page-title` **visible:false** (Boost's kept) |
+| **F3 mobile gap** | branding block **118px**, header **160px** | branding **74px**, header **124px** — cart + logo tightened up |
+
+**Honest scope of proof:** CSS application is deterministic — these are the real collection-page DOM with the exact staged CSS/inline-style applied. The staged assets are confirmed present on dev 143947038771 via the Admin API. The one thing not done headless: load the served dev theme via `?preview_theme_id=` (anonymous requests are served the LIVE theme). The pixel-perfect confirm on the *served* dev theme is the authenticated **Preview** button — Steve's step below.
+
+---
+
+## STEVE — verify on dev, then approve
+
+### Step 1 — verify the dev Preview (authenticated)
+Shopify admin → Online Store → Themes → **"★ 5.0 Grid+Infinite FIX (approve)" (143947038771)** → **Preview** → open `/collections/all` and any real collection (e.g. `/collections/acoustical`). Expect:
+- "Products" is a single clean centered title (no grey pill, no duplicate) on collections with no image; and a real photo hero with white pill on any collection where you set an image.
+- Mobile: cart + logo tight at top, no dead gap.
+
+### Step 2 — pick the branded default hero (gated; customizer)
+In that same theme: **Customize → Theme settings → "Collection hero" → Default collection hero image** → upload a wide DW brand image (≈2000×600). This is the floor every imageless collection falls back to. *(Optional — without it, imageless collections show the polished clean-type band, which already looks good.)*
+
+### Step 3 — set per-collection images (gated; the HARD rule, do over time)
+For each important collection: **Collections → [collection] → Image** → set a representative hero. These always win over the default. This is the actual fulfillment of the `dw_every_collection_needs_bg_hero_image` rule; the theme fix above guarantees nothing looks broken while you work through them.
+
+### Step 4 — approve the LIVE push (I run on your go)
+Applies the SAME four staged changes to LIVE **142250278963** (backups already captured), with re-verify after. Commands (theme token via `/secrets` `SHOPIFY_THEME_TOKEN`, never hardcoded; CSS block idempotent + backed up first):
+
+```bash
+TOK=$(grep -m1 '^SHOPIFY_THEME_TOKEN=' ~/Projects/secrets-manager/.env | cut -d= -f2- | tr -d '"' | tr -d "'")
+LIVE=142250278963
+cd ~/Projects/Designer-Wallcoverings
+python3 - "$TOK" "$LIVE" <<'PY'
+import sys,json,urllib.request,urllib.parse,re,time
+tok,LIVE=sys.argv[1],sys.argv[2]; STORE='designer-laboratory-sandbox.myshopify.com'
+def get(k):
+    q=urllib.parse.urlencode({'asset[key]':k})
+    return json.load(urllib.request.urlopen(urllib.request.Request(f"https://{STORE}/admin/api/2024-10/themes/{LIVE}/assets.json?{q}",headers={'X-Shopify-Access-Token':tok})))['asset']['value']
+def put(k,v):
+    body=json.dumps({'asset':{'key':k,'value':v}}).encode()
+    s=json.load(urllib.request.urlopen(urllib.request.Request(f"https://{STORE}/admin/api/2024-10/themes/{LIVE}/assets.json",data=body,method='PUT',headers={'X-Shopify-Access-Token':tok,'Content-Type':'application/json'})))['asset']['size']
+    print('PUT',k,s,'bytes'); time.sleep(2)
+B='shopify/collection-hero-fix'
+# backup live custom.css + collection.liquid + settings_schema first
+for k in ['assets/custom.css','sections/collection.liquid','config/settings_schema.json']:
+    open(f"{B}/backups/{k.replace('/','_')}.live-{LIVE}.pushbak",'w').write(get(k))
+# 1) snippet (new)
+put('snippets/dw-collection-hero-bg.liquid', open(f'{B}/snippets_dw-collection-hero-bg.liquid').read())
+# 2) collection.liquid (render call) — verify live still matches the backup we patched from
+put('sections/collection.liquid', open(f'{B}/patched/sections_collection.liquid').read())
+# 3) settings_schema (adds the picker; merge live's current to avoid clobbering other edits)
+live_ss=json.loads(get('config/settings_schema.json'))
+if not any(isinstance(g,dict) and any(s.get('id')=='collection_default_hero' for s in g.get('settings',[])) for g in live_ss):
+    live_ss.insert(1,{"name":"Collection hero","settings":[
+      {"type":"paragraph","content":"Fallback hero image shown on collection pages that do not have their own Collection image set. Per-collection images always take priority."},
+      {"type":"image_picker","id":"collection_default_hero","label":"Default collection hero image","info":"Used only when a collection has no image of its own. Recommended 2000x600."}]})
+    put('config/settings_schema.json', json.dumps(live_ss,indent=2,ensure_ascii=False))
+else: print('settings_schema already has collection_default_hero, skipped')
+# 4) append marked CSS block to live custom.css (idempotent)
+S='/* >>> dw-collection-hero-fix START >>> */'; E='/* <<< dw-collection-hero-fix END <<< */'
+base=re.sub(re.escape(S)+r'.*?'+re.escape(E),'',get('assets/custom.css'),flags=re.S).rstrip()+'\n'
+put('assets/custom.css', base+'\n'+S+'\n'+open(f'{B}/dw-collection-hero.css').read()+'\n'+E+'\n')
+print('LIVE push complete')
+PY
+```
+
+**Rollback:** re-PUT the `*.live-142250278963.pushbak` backups, or strip the marked CSS block + delete the snippet + revert the one render line.
+
+### Checkboxes
+- [ ] Step 1 verified on the dev Preview (single clean title; photo-hero w/ pill when image set; mobile gap gone)
+- [ ] Step 2 default hero picked (optional)
+- [ ] Step 3 per-collection images being set (HARD rule)
+- [ ] **Approve LIVE push of the 4 staged changes to 142250278963** (commands above)
+
+**$ 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.0038**. Total ≈ **$0.004**.

← fff83e00 Collection hero fix: harden image/no-image switch via body.d  ·  back to Designer Wallcoverings  ·  Tres Tintas rooms regenerated at corrected repeat-driven sca 957660c8 →