in template literal","b":"renderDetail() injects a giant template-literal HTML block via\ninnerHTML; that block contains a nested \nhelper. Browsers' HTML tokenizer doesn't respect JS template literals — when\nit hits the inner , it terminates the OUTER inside backtick template literals."},{"h":"a0cea68","d":"2026-05-06","s":"save+deploy: persist chosen sort to per-site rules; UI pre-populates from server-side rules.sort with localStorage fallback","b":""},{"h":"dd68026","d":"2026-05-06","s":"Hero resolution probe + HD/MED/SD badges + upscale to largest variant","b":"Steve flagged: many hero images look blurry full-page because the source is\na small Shopify variant (e.g. 480x480). Two fixes:\n\n1. largestShopifyImage(url) — strips _NxN size suffix from any\n cdn.shopify.com / designerwallcoverings.com URL so the master is fetched\n for both card thumbnails AND drag-drop hero pins.\n\n2. Resolution probe + badges — every product card now shows a HD/MED/SD\n badge in its top-right after the natural image dimensions are probed\n client-side (concurrency 6, sessionStorage cached). Tier rules:\n ≥ 1500 px largest side → HD (green)\n ≥ 800 px → MED (gold)\n < 800 px → SD (red)\n SD cards fade to 55% opacity to push you toward HD picks.\n\n3. Hero panel banner — when a site is selected, a banner above the assigned-\n collections section reports whether the current hero is HD/MED/SD with\n the actual dimensions; SD shows a 'WILL LOOK BLURRY' warning.\n\n4. 'HD only' filter checkbox in the products bar — hides all non-HD cards.\n\n5. Products-bar count line now shows '23 HD · 12 MED · 4 SD · 8 probing'.\n\nCork live site already pushed with the upscale logic; 45 other sites\nre-patched locally pending deploy."},{"h":"71f7337","d":"2026-05-06","s":"save+deploy: sort selector (textures/newest/title/sku/priceUp/priceDown/random) wired through API → renderSite; per CLAUDE.md grid sort+density rule","b":""},{"h":"aa01c45","d":"2026-05-06","s":"Probe live HTTP status; flag redirected/parked sites in the grid","b":"Steve noticed several site cards showed wrong heroes — they're nginx 301/302\nredirects to consolidation domains, and the admin's screenshot probe was\nshowing the redirect target's hero. Misleading.\n\nThis change adds a HEAD probe + banner so consolidated sites are honest:\n\n- New POST /api/sites/probe — HEAD-checks every site over HTTPS, parallelism 8,\n caches { http_status, redirect_target, probed_at } in data/site-status.json\n- listSites() merges the probe cache into each site row\n- index.html: new 📡 Probe live button in the toolbar; cards with 3xx render\n a gold redirect banner overlaying the hero ('→ (301)') AND fade\n to 0.55 opacity so the redirect chain stops looking like a bug\n- Cards with HTTP 0/5xx render a red 'offline' banner\n\nVerified live: 46 sites probed in one click, 43 ok / 2 redirects (string→\nlinen, embroidered→fabric) / 1 offline. Banners render correctly."},{"h":"3a36c5f","d":"2026-05-06","s":"Drag product → cover image + sort by color/style/SKU + grid-size slider","b":"Three new affordances on the right detail panel:\n\n1. Drag any product card onto the cover image to set it as the hero.\n - .pcard is now draggable=true with a custom MIME (application/x-dwc-product)\n carrying { sku, image, title }\n - .hero-large catches dragover/drop, highlights via existing dropzone-active\n CSS, then POSTs the sku to the existing /api/site/:slug/hero endpoint\n - Optimistic local update + toast confirmation; renderDetail() re-renders\n so the cover swaps without a fetch round-trip\n\n2. Sort dropdown — newest (default), Color (clusters black→white→warm→cool→\n purple buckets via tag matching), Style (Traditional/Modern/Floral/etc.\n buckets), SKU (alpha). Selection persists in localStorage as 'dwc_sort'.\n\n3. Grid card-width slider — 80px to 260px, live-updates\n grid-template-columns:repeat(auto-fill,minmax(N,1fr)) without re-render.\n Persists as 'dwc_size' in localStorage.\n\nVerified end-to-end via headless Playwright: 4-option sort dropdown live,\n50/50 cards draggable, drop simulation flips hero img src as expected."},{"h":"f016e8f","d":"2026-05-06","s":"Click site → show all products as a responsive grid (was horizontal scroll)","b":"Previous .products-slider .row was a horizontal flex with 110px cards and\noverflow-x:auto — only ~6 cards visible at a time, lots of horizontal\nscrolling to see everything.\n\nNow: display:grid, grid-template-columns:repeat(auto-fill,minmax(140px,1fr)),\ngap:10px. Every product visible at once; cards bigger (140-200+ px) and\nlabels can wrap to 2 lines via -webkit-line-clamp:2 with min-height:32px so\nrows align. Selection, bulk-remove, copy SKUs all unchanged."},{"h":"3f6faec","d":"2026-05-06","s":"bulk product remove-from-list (server endpoint + UI button)","b":""},{"h":"8a47889","d":"2026-05-06","s":"press C anywhere to focus collection search input","b":""},{"h":"7455efd","d":"2026-05-06","s":"show SKU + published_at in product card hover tooltip","b":""},{"h":"3b2d32d","d":"2026-05-06","s":"color preview toast green/red by product-count delta","b":""},{"h":"9c53f65","d":"2026-05-06","s":"add Save & Deploy combined button (one-click save + render + deploy)","b":""},{"h":"0b73541","d":"2026-05-06","s":"add inline .env loader + Shopify pagination + all-products page","b":""},{"h":"9a73dc0","d":"2026-05-06","s":"initial scaffold","b":""}]; const q = document.getElementById('q'); const list = document.getElementById('bp-commits'); const tally = document.getElementById('bp-tally'); function applyFilter() { const term = q.value.toLowerCase().trim(); let shown = 0; for (const li of list.children) { const match = !term || li.dataset.blob.includes(term); li.style.display = match ? '' : 'none'; if (match) shown++; } tally.textContent = term ? `${shown} / ${DATA.length} match "${q.value}"` : `${DATA.length} commits indexed`; // Reflect search state in URL so a filtered view is shareable. Use // replaceState so the back button still escapes the project page. const url = new URL(window.location.href); if (term) url.searchParams.set('q', q.value); else url.searchParams.delete('q'); history.replaceState(null, '', url); } q.addEventListener('input', applyFilter); // Apply the initial ?q= from the server-rendered value field. if (q.value) applyFilter();

Dw Collections Viewer

repo: ~/Projects/dw-collections-viewer · 22 commits · 0 in last 24h, 0 in last 7d ·

Search the build

22 commits indexed

  1. 48ca48c 2026-07-13 chore: v0.2.0 — similar-pattern search feature (session close)
  2. 1d1ab8c 2026-07-13 similar-pattern search: per-tile ≈ button → /api/similar proxy to all.dw (creds server-side) → scored live substitutes in a shared panel below the product slider
  3. aa7d928 2026-06-10 snapshot before dep reinstall + pm2 restart
  4. 61f62d9 2026-05-18 Add rel=noopener noreferrer to Open site external link
  5. cd8ae33 2026-05-13 snapshot: 3 file(s) changed, +2 new, ~1 modified
  6. deda82f 2026-05-07 dw-collections-viewer: gold ↕<sort> pill on tiles when persisted sort != default 'textures'; surfaces last_sort_applied at a glance
  7. cbb7a20 2026-05-06 dw-collections-viewer: 'Preview sort' button — re-render with chosen sort but skip deploy/pm2-restart so user can eyeball the order before pushing live
  8. 15a2c8f 2026-05-06 dw-collections-viewer: stale-products pill (>30 days mtime) on each tile + 'Stale' bulk-select option; surfaces last_render_iso/age_days/is_stale via /api/sites
  9. f3e88a0 2026-05-06 Fix HTML tokenizer breaking outer script — escape nested </script> in template literal
  10. a0cea68 2026-05-06 save+deploy: persist chosen sort to per-site rules; UI pre-populates from server-side rules.sort with localStorage fallback
  11. dd68026 2026-05-06 Hero resolution probe + HD/MED/SD badges + upscale to largest variant
  12. 71f7337 2026-05-06 save+deploy: sort selector (textures/newest/title/sku/priceUp/priceDown/random) wired through API → renderSite; per CLAUDE.md grid sort+density rule
  13. aa01c45 2026-05-06 Probe live HTTP status; flag redirected/parked sites in the grid
  14. 3a36c5f 2026-05-06 Drag product → cover image + sort by color/style/SKU + grid-size slider
  15. f016e8f 2026-05-06 Click site → show all products as a responsive grid (was horizontal scroll)
  16. 3f6faec 2026-05-06 bulk product remove-from-list (server endpoint + UI button)
  17. 8a47889 2026-05-06 press C anywhere to focus collection search input
  18. 7455efd 2026-05-06 show SKU + published_at in product card hover tooltip
  19. 3b2d32d 2026-05-06 color preview toast green/red by product-count delta
  20. 9c53f65 2026-05-06 add Save & Deploy combined button (one-click save + render + deploy)
  21. 0b73541 2026-05-06 add inline .env loader + Shopify pagination + all-products page
  22. 9a73dc0 2026-05-06 initial scaffold

Authors

  • Steve22

Agents used

  • debate-team-fast1

Skills used

  • /script5
  • /sites2
  • /similar1
  • /pm2-restart1
  • /newest1
  • /title1
  • /sku1
  • /random1
  • /parked1
  • /probe1
  • /site-status1
  • /style1
  • /x-dwc-product1
  • /drop1
  • /site1
  • /hero1
  • /red1

Creative ideas + design notes

Commits with substantial prose (≥120 chars) — the rationale behind each move.

f3e88a0 · 2026-05-06 · Fix HTML tokenizer breaking outer script — escape nested </script> in template literal
renderDetail() injects a giant template-literal HTML block via
innerHTML; that block contains a nested <script>(restore deploy-sort)</script>
helper. Browsers' HTML tokenizer doesn't respect JS template literals — when
it hits the inner </script>, it terminates the OUTER <script> block too.
Everything after that closing tag (including the outer template's closing
backtick) became raw HTML, leaving the main JS body unterminated:
'Unexpected end of input'. Page rendered shell only, no site cards.

Fix: split the open tag as <` + `script> and escape the close as <\/script>
inside the template literal. Tokenizer no longer sees a script boundary.

Verified via debate-team-fast (Claude + Kimi + Qwen3 all 3/3): correct fix.
Future refactor (ticket): move the inline restore script OUT of the template
literal entirely (data-attribute + DOMContentLoaded hook). Add a pre-commit
grep for unescaped </script> inside backtick template literals.
dd68026 · 2026-05-06 · Hero resolution probe + HD/MED/SD badges + upscale to largest variant
Steve flagged: many hero images look blurry full-page because the source is
a small Shopify variant (e.g. 480x480). Two fixes:

1. largestShopifyImage(url) — strips _NxN size suffix from any
   cdn.shopify.com / designerwallcoverings.com URL so the master is fetched
   for both card thumbnails AND drag-drop hero pins.

2. Resolution probe + badges — every product card now shows a HD/MED/SD
   badge in its top-right after the natural image dimensions are probed
   client-side (concurrency 6, sessionStorage cached). Tier rules:
     ≥ 1500 px largest side → HD (green)
     ≥ 800  px              → MED (gold)
     <  800  px             → SD (red)
   SD cards fade to 55% opacity to push you toward HD picks.

3. Hero panel banner — when a site is selected, a banner above the assigned-
   collections section reports whether the current hero is HD/MED/SD with
   the actual dimensions; SD shows a 'WILL LOOK BLURRY' warning.

4. 'HD only' filter checkbox in the products bar — hides all non-HD cards.

5. Products-bar count line now shows '23 HD · 12 MED · 4 SD · 8 probing'.

Cork live site already pushed with the upscale logic; 45 other sites
re-patched locally pending deploy.
aa01c45 · 2026-05-06 · Probe live HTTP status; flag redirected/parked sites in the grid
Steve noticed several site cards showed wrong heroes — they're nginx 301/302
redirects to consolidation domains, and the admin's screenshot probe was
showing the redirect target's hero. Misleading.

This change adds a HEAD probe + banner so consolidated sites are honest:

- New POST /api/sites/probe — HEAD-checks every site over HTTPS, parallelism 8,
  caches { http_status, redirect_target, probed_at } in data/site-status.json
- listSites() merges the probe cache into each site row
- index.html: new 📡 Probe live button in the toolbar; cards with 3xx render
  a gold redirect banner overlaying the hero ('→ <target> (301)') AND fade
  to 0.55 opacity so the redirect chain stops looking like a bug
- Cards with HTTP 0/5xx render a red 'offline' banner

Verified live: 46 sites probed in one click, 43 ok / 2 redirects (string→
linen, embroidered→fabric) / 1 offline. Banners render correctly.
3a36c5f · 2026-05-06 · Drag product → cover image + sort by color/style/SKU + grid-size slider
Three new affordances on the right detail panel:

1. Drag any product card onto the cover image to set it as the hero.
   - .pcard is now draggable=true with a custom MIME (application/x-dwc-product)
     carrying { sku, image, title }
   - .hero-large catches dragover/drop, highlights via existing dropzone-active
     CSS, then POSTs the sku to the existing /api/site/:slug/hero endpoint
   - Optimistic local update + toast confirmation; renderDetail() re-renders
     so the cover swaps without a fetch round-trip

2. Sort dropdown — newest (default), Color (clusters black→white→warm→cool→
   purple buckets via tag matching), Style (Traditional/Modern/Floral/etc.
   buckets), SKU (alpha). Selection persists in localStorage as 'dwc_sort'.

3. Grid card-width slider — 80px to 260px, live-updates
   grid-template-columns:repeat(auto-fill,minmax(N,1fr)) without re-render.
   Persists as 'dwc_size' in localStorage.

Verified end-to-end via headless Playwright: 4-option sort dropdown live,
50/50 cards draggable, drop simulation flips hero img src as expected.
f016e8f · 2026-05-06 · Click site → show all products as a responsive grid (was horizontal scroll)
Previous .products-slider .row was a horizontal flex with 110px cards and
overflow-x:auto — only ~6 cards visible at a time, lots of horizontal
scrolling to see everything.

Now: display:grid, grid-template-columns:repeat(auto-fill,minmax(140px,1fr)),
gap:10px. Every product visible at once; cards bigger (140-200+ px) and
labels can wrap to 2 lines via -webkit-line-clamp:2 with min-height:32px so
rows align. Selection, bulk-remove, copy SKUs all unchanged.

File tree

10 files tracked. Click any to browse the source at HEAD.

Other build journals

← Dw Cert Renewal Canary  ·  all 4 projects  ·  Dw Color Image Audit →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 0ms