[object Object]

← back to Wallco Ai

feat(colorways): clicking a saved colorway chip opens it as a product

1950b743f1a65619b0b2c52283a082f11736cf5c · 2026-05-29 13:51:21 -0700 · Steve Abrams

Chip is now a real <a href="/design/$id?cw=$cwid"> link — right-click
opens in new tab, share/bookmark works. Plain click still applies the
colorway in-place (instant) but also pushes the ?cw= URL via
history.pushState so the browser state reflects the new-product view.

On any /design/$id?cw=<id> load, applyFromUrl() looks up the colorway
and applies it automatically. Modifier/middle clicks fall through to
browser-native open-in-new-tab.

Files touched

Diff

commit 1950b743f1a65619b0b2c52283a082f11736cf5c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri May 29 13:51:21 2026 -0700

    feat(colorways): clicking a saved colorway chip opens it as a product
    
    Chip is now a real <a href="/design/$id?cw=$cwid"> link — right-click
    opens in new tab, share/bookmark works. Plain click still applies the
    colorway in-place (instant) but also pushes the ?cw= URL via
    history.pushState so the browser state reflects the new-product view.
    
    On any /design/$id?cw=<id> load, applyFromUrl() looks up the colorway
    and applies it automatically. Modifier/middle clicks fall through to
    browser-native open-in-new-tab.
---
 public/js/color-dots.js | 42 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 6 deletions(-)

diff --git a/public/js/color-dots.js b/public/js/color-dots.js
index a2fc40c..6cdbf50 100644
--- a/public/js/color-dots.js
+++ b/public/js/color-dots.js
@@ -201,20 +201,50 @@
     host.appendChild(bar);
 
     function chip(cw) {
-      var b = document.createElement('button'); b.type = 'button';
-      b.title = (cw.name || ('Version ' + cw.version)) + ' · ' + new Date(cw.created_at).toLocaleString();
+      // Real <a> link so the chip is a navigable product URL (right-click →
+      // "Open in new tab" works, can be shared/bookmarked, browser shows the
+      // href on hover). Steve 2026-05-29: "click into it as a new product".
+      // Plain click stays in-page (instant preview + URL replace, no reload).
+      // Modifier/middle clicks fall through to browser-native open-in-tab.
+      var b = document.createElement('a');
+      b.href = '/design/' + did + '?cw=' + cw.id;
+      b.title = (cw.name || ('Version ' + cw.version)) + ' · ' + new Date(cw.created_at).toLocaleString() + ' · open as product';
       var stops = (cw.ink_map || []).map(function (m) { return m.to; });
-      b.style.cssText = 'border:1px solid #ccc;border-radius:6px;width:32px;height:22px;cursor:pointer;' +
+      b.style.cssText = 'display:inline-flex;align-items:center;justify-content:center;' +
+        'border:1px solid #ccc;border-radius:6px;width:32px;height:22px;cursor:pointer;text-decoration:none;' +
         (stops.length ? 'background:linear-gradient(90deg,' + stops.join(',') + ')' : 'background:#eee');
       var lab = document.createElement('span'); lab.textContent = 'v' + cw.version;
-      b.appendChild(lab); lab.style.cssText = 'display:block;font:700 8px sans-serif;color:#fff;text-shadow:0 0 2px #000';
-      b.addEventListener('click', function () { applyColorway(img, cw.ink_map); });
+      b.appendChild(lab); lab.style.cssText = 'font:700 8px sans-serif;color:#fff;text-shadow:0 0 2px #000';
+      b.addEventListener('click', function (ev) {
+        if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.button === 1) return;
+        ev.preventDefault();
+        applyColorway(img, cw.ink_map);
+        try {
+          var u = new URL(location.href);
+          u.searchParams.set('cw', cw.id);
+          history.pushState({ cw: cw.id }, '', u);
+        } catch (e) {}
+      });
       return b;
     }
+    // Auto-apply ?cw=<id> from URL on load — makes /design/<id>?cw=<cwid>
+    // behave like a distinct "new product" page that opens in that colorway.
+    function applyFromUrl(cws) {
+      try {
+        var cwid = parseInt(new URLSearchParams(location.search).get('cw'), 10);
+        if (!cwid) return;
+        var hit = (cws || []).filter(function (c) { return c.id === cwid; })[0];
+        if (hit && Array.isArray(hit.ink_map)) applyColorway(img, hit.ink_map);
+      } catch (e) {}
+    }
     function load() {
       fetch('/api/colorways?design_id=' + did, { credentials: 'same-origin' })
         .then(function (r) { return r.json(); })
-        .then(function (j) { vers.innerHTML = ''; (j.colorways || []).forEach(function (cw) { vers.appendChild(chip(cw)); }); })
+        .then(function (j) {
+          vers.innerHTML = '';
+          (j.colorways || []).forEach(function (cw) { vers.appendChild(chip(cw)); });
+          applyFromUrl(j.colorways);
+        })
         .catch(function () {});
     }
     save.addEventListener('click', function () {

← 1ed5276 Age prompt: add 'We are asking to serve the best theme for y  ·  back to Wallco Ai  ·  trade-login: add password sign-in (env-var gated) alongside 759068a →