[object Object]

← back to Wallco Ai

PDP theme switcher: admin-only — hide .switcher bar from shoppers, gate dropdown+stepper on localStorage.dwAdmin

aa2d6d6b7cc0c99e064d896d428aacc081a6302c · 2026-06-01 20:55:02 -0700 · Steve Abrams

Files touched

Diff

commit aa2d6d6b7cc0c99e064d896d428aacc081a6302c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 1 20:55:02 2026 -0700

    PDP theme switcher: admin-only — hide .switcher bar from shoppers, gate dropdown+stepper on localStorage.dwAdmin
---
 public/theme-variants/theme-variant-nav.js | 59 +++++++++++++++++-------------
 1 file changed, 34 insertions(+), 25 deletions(-)

diff --git a/public/theme-variants/theme-variant-nav.js b/public/theme-variants/theme-variant-nav.js
index be201ae..ca5acc4 100644
--- a/public/theme-variants/theme-variant-nav.js
+++ b/public/theme-variants/theme-variant-nav.js
@@ -1,17 +1,18 @@
-/* theme-variant-nav.js — PDP theme switchers for the 17 variants.
+/* theme-variant-nav.js — ADMIN-ONLY PDP theme switchers for the 17 variants.
  *
  * Drop-in (ABSOLUTE path — variants are served at /design/:id/:slug):
  *   <script src="/theme-variants/theme-variant-nav.js" defer></script>
  *
- * Two switchers:
- *  (1) PUBLIC theme dropdown — turns each variant's static .switcher bar
- *      ("Theme: X  ← Classic") into a working <select> of Classic + all 17
- *      variants. Runs for everyone (the bar is already public). Also fixes the
- *      broken "← Classic" link (its inline href points at the bare /design/:id
- *      which serves the LIVE theme, so when a variant is the live default it
- *      loops back to itself — we route Classic through ?classic=1).
- *  (2) ADMIN ‹ prev / next › stepper pill (upper-right) — shows ONLY when
- *      localStorage.dwAdmin === '1' (set via ?admin=1). Alt+←/→ also step.
+ * ADMIN GATE: everything below shows ONLY when localStorage.dwAdmin === '1'
+ * (set via ?admin=1, cleared via ?admin=0). For shoppers we HIDE the static
+ * .switcher bar entirely so the internal theme machinery is never exposed.
+ *
+ * For admins, two switchers:
+ *  (1) theme dropdown — turns each variant's .switcher bar ("Theme: X ← Classic")
+ *      into a working <select> of Classic + all 17 variants. Classic routes via
+ *      ?classic=1 (server forces the monolith) so it works even when a variant
+ *      is the live default; variants route via /design/:id/<slug>.
+ *  (2) ‹ prev / next › stepper pill (upper-right). Alt+←/→ also step.
  * Marks the LIVE theme (from /api/pdp-theme). Self-styled · idempotent · 0 deps.
  */
 (function () {
@@ -19,8 +20,27 @@
   if (window.__themeVariantNavLoaded) return;
   window.__themeVariantNavLoaded = true;
 
-  // NOTE: the admin gate is DOWN below — it wraps ONLY the ‹ › stepper pill.
-  // The public dropdown runs for everyone.
+  // ── ADMIN GATE ─────────────────────────────────────────────────────────
+  // Resolve admin first. Shoppers get the .switcher bar hidden and nothing else.
+  var isAdmin = false;
+  try {
+    var q = new URLSearchParams(location.search);
+    if (q.get('admin') === '1') localStorage.setItem('dwAdmin', '1');
+    if (q.get('admin') === '0') localStorage.removeItem('dwAdmin');
+    isAdmin = localStorage.getItem('dwAdmin') === '1';
+  } catch (e) { isAdmin = false; }
+
+  if (!isAdmin) {
+    // Hide the internal theme-switcher bar from shoppers (it's static HTML in
+    // every variant). Injected as early as the deferred script runs.
+    try {
+      var hide = document.createElement('style');
+      hide.id = 'tvn-hide-switcher';
+      hide.textContent = '.switcher{display:none !important}';
+      (document.head || document.documentElement).appendChild(hide);
+    } catch (e) {}
+    return;
+  }
 
   // ordered route slugs (match server /design/:id/:slug + smoke test) → display name
   var THEMES = [
@@ -75,11 +95,7 @@
 
   var LIVE_IDX = -1;
 
-  // ───────────────────────────────────────────────────────────────────────
-  // (1) PUBLIC theme dropdown (everyone). Classic routes through ?classic=1
-  // (server forces the monolith) so it works even when a variant is the live
-  // default; variants route through /design/:id/<slug> (always that variant).
-  // ───────────────────────────────────────────────────────────────────────
+  // ───────────────────────── (1) theme dropdown (admin) ─────────────────────
   function classicUrl() {
     if (mode !== 'route') return '/';                 // file-mode dev: no monolith
     var p = new URLSearchParams(location.search);
@@ -141,14 +157,7 @@
   if (document.body) tvnInit();
   else document.addEventListener('DOMContentLoaded', tvnInit);
 
-  // ───────────── (2) ADMIN ‹ prev / next › stepper pill (admin-only) ─────────────
-  try {
-    var q = new URLSearchParams(location.search);
-    if (q.get('admin') === '1') localStorage.setItem('dwAdmin', '1');
-    if (q.get('admin') === '0') localStorage.removeItem('dwAdmin');
-    if (localStorage.getItem('dwAdmin') !== '1') return;
-  } catch (e) { return; }
-
+  // ───────────────── (2) ‹ prev / next › stepper pill (admin) ────────────────
   // ---- styles ----
   var css = document.createElement('style');
   css.textContent = [

← f78404f follow-up #1 (two-master, /dtd Option B): disjoint id ranges  ·  back to Wallco Ai  ·  la-toile: fix prompt — gate off conflicting tone-on-tone pal dcdb679 →