[object Object]

← back to Wallco Ai

PDP: explicit Wallpaper/Wall Mural format toggle on every design

47468513c500f97b00b4682b152c6f3d5564b847 · 2026-06-01 16:31:53 -0700 · Steve Abrams

Every design now shows a prominent two-way segmented toggle (Wallpaper ·
seamless tile per roll  /  Wall Mural · one image across the entire wall)
at the top of the live wall preview. Drives the existing mural-stepper
level mechanism (Mural=level 0, Wallpaper=tiling level) so spec rows,
sold-by, preview, dots and the price estimate all follow. Default follows
design.kind (seamless_tile->Wallpaper, mural_panel->Mural) but BOTH are
always offered. Relabeled the dot-stepper 'Tile repeat' and hide it in
Mural mode.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 47468513c500f97b00b4682b152c6f3d5564b847
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 16:31:53 2026 -0700

    PDP: explicit Wallpaper/Wall Mural format toggle on every design
    
    Every design now shows a prominent two-way segmented toggle (Wallpaper ·
    seamless tile per roll  /  Wall Mural · one image across the entire wall)
    at the top of the live wall preview. Drives the existing mural-stepper
    level mechanism (Mural=level 0, Wallpaper=tiling level) so spec rows,
    sold-by, preview, dots and the price estimate all follow. Default follows
    design.kind (seamless_tile->Wallpaper, mural_panel->Mural) but BOTH are
    always offered. Relabeled the dot-stepper 'Tile repeat' and hide it in
    Mural mode.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 server.js | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index ed4c193..fbf6338 100644
--- a/server.js
+++ b/server.js
@@ -14857,6 +14857,28 @@ try {
         ` : ''}
 
         <div class="scale-preview" style="margin-top:18px">
+          <!-- FORMAT TOGGLE (Steve 2026-06-01): EVERY design is purchasable
+               two ways — as a seamless WALLPAPER (tile, sold per roll) or as a
+               single WALL MURAL (one continuous image scaled across the whole
+               wall, printed from the full-size TIF). This is the explicit
+               customer-facing choice; it drives the same mural-stepper level
+               mechanism below (Mural = level 0, Wallpaper = a tiling level).
+               The default follows design.kind, but BOTH are ALWAYS offered. -->
+          <div class="format-toggle" role="tablist" aria-label="Choose format" style="display:flex;gap:0;margin-bottom:18px;border:1px solid var(--line);border-radius:10px;overflow:hidden">
+            <button type="button" class="format-tab" data-mode="wallpaper" role="tab" aria-selected="false" style="flex:1;padding:14px 16px;border:0;background:transparent;color:var(--ink);cursor:pointer;text-align:left;border-right:1px solid var(--line)">
+              <span style="display:block;font:600 14px var(--sans);letter-spacing:.02em">Wallpaper</span>
+              <span style="display:block;font:11px var(--sans);color:var(--ink-faint);margin-top:2px">Seamless tile · sold per roll (27&nbsp;ft)</span>
+            </button>
+            <button type="button" class="format-tab" data-mode="mural" role="tab" aria-selected="false" style="flex:1;padding:14px 16px;border:0;background:transparent;color:var(--ink);cursor:pointer;text-align:left">
+              <span style="display:block;font:600 14px var(--sans);letter-spacing:.02em">Wall Mural</span>
+              <span style="display:block;font:11px var(--sans);color:var(--ink-faint);margin-top:2px">One image across the entire wall</span>
+            </button>
+          </div>
+          <style>
+            .format-toggle .format-tab.active { background: var(--ink,#1a1816); }
+            .format-toggle .format-tab.active span { color: #f0eadc !important; }
+            .format-toggle .format-tab:focus-visible { outline:2px solid var(--gold,#c9a14b); outline-offset:-2px; }
+          </style>
           <!-- "Pattern scale 24" repeat" applies only to tile-mode previews
                (levels 1-4); a mural is a single un-repeated 20 ft × 11 ft canvas
                where "repeat distance" is meaningless. The mural-stepper apply()
@@ -14875,7 +14897,7 @@ try {
                pan the image, scroll to zoom, double-click to reset.
                Patterned after grahambrown.com and rebelwalls.com mural tools. -->
           <div class="mural-stepper" style="display:flex;align-items:center;gap:12px;margin-bottom:10px;flex-wrap:wrap">
-            <span style="font:11px var(--sans);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-faint)">Mural repeat</span>
+            <span style="font:11px var(--sans);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-faint)">Tile repeat</span>
             <div id="mural-dots" style="display:flex;gap:6px">
               <span class="mural-dot active" data-level="0" title="Mural — full 20 ft × 11 ft canvas · drag to position"></span>
               <span class="mural-dot" data-level="1" title="2×2"></span>
@@ -14937,9 +14959,18 @@ try {
             const SLIDER = document.getElementById('scale-slider');
             const DESIGN_ID = ${JSON.stringify(design.id || '')};
             const LS_LEVEL = 'wallco.detail.mural-level';
+            // Explicit Wallpaper/Wall Mural format toggle (Steve 2026-06-01).
+            // Both formats are offered on every design; the default follows the
+            // design's native kind. Mural = level 0; Wallpaper = a tiling level.
+            const KIND = ${JSON.stringify(design.kind || 'seamless_tile')};
+            const IS_MURAL_KIND = (KIND === 'mural_panel' || KIND === 'mural');
+            const fmtTabs = document.querySelectorAll('.format-tab');
+            const muralStepperRow = document.querySelector('.mural-stepper');
+            const WALLPAPER_LEVEL = 2;            // default tile density in Wallpaper mode
+            let lastWallpaperLevel = WALLPAPER_LEVEL;
             const LS_CROP  = 'wallco.detail.mural-crop.' + DESIGN_ID;
             const MURAL_AR = 20 / 11; // physical mural: 20 ft × 11 ft
-            let level = 0;
+            let level = IS_MURAL_KIND ? 0 : WALLPAPER_LEVEL;
             // mural crop state — per-design. zoom=1 means "cover the 20×11
             // canvas once" (source image fills the canvas, no stretch);
             // zoom>1 zooms further in. px/py are % anchor positions.
@@ -15054,6 +15085,16 @@ try {
               if (soldBy) soldBy.innerHTML = isMural ? 'Per panel (36"&nbsp;×&nbsp;11&nbsp;ft)' : 'Per roll (27&nbsp;ft)';
               const widthHint = document.getElementById('scale-width-hint');
               if (widthHint) widthHint.textContent = isMural ? '36" panel × 11 ft, sold per panel' : '24" wide, sold per roll (27 ft)';
+              // Sync the explicit Wallpaper / Wall Mural format toggle, remember
+              // the last wallpaper density so toggling back restores it, and
+              // hide the fine "Tile repeat" stepper in Mural mode (no repeat).
+              if (level > 0) lastWallpaperLevel = level;
+              fmtTabs.forEach(t => {
+                const on = (t.dataset.mode === 'mural') === isMural;
+                t.classList.toggle('active', on);
+                t.setAttribute('aria-selected', on ? 'true' : 'false');
+              });
+              if (muralStepperRow) muralStepperRow.style.display = isMural ? 'none' : 'flex';
               // N×M tiles textual readout (UX-designer panel review 2026-05-21):
               // at zoom != 0.5× the viewport shows a magnified excerpt, not the
               // full wall — customer cannot count tiles visually. This text
@@ -15080,6 +15121,13 @@ try {
             }
             if (btn) btn.addEventListener('click', () => { level = (level + 1) % LEVELS.length; apply(); });
             dots.forEach(d => d.addEventListener('click', (e) => { level = parseInt(e.currentTarget.dataset.level,10) || 0; apply(); }));
+            // Explicit format toggle → Wall Mural = level 0; Wallpaper = restore
+            // the last chosen tile density (default 4×4). Reuses apply() so the
+            // spec rows, sold-by, preview and price block all follow.
+            fmtTabs.forEach(t => t.addEventListener('click', () => {
+              level = (t.dataset.mode === 'mural') ? 0 : (lastWallpaperLevel || WALLPAPER_LEVEL);
+              apply();
+            }));
             // Pattern-scale slider adjusts the vertical repeat in WALLPAPER
             // modes (levels 1-4). In MURAL mode (level 0) the slider is
             // hidden anyway, so this listener is a no-op there.

← de244a8 elements admin: click element image to use it in a new patte  ·  back to Wallco Ai  ·  add read-only color-name vs dominant-hex drift audit (10171 5713b85 →