[object Object]

← back to Fabricwallpaper

rails: tag-aware via shared rail-match helper + editorial LABELS (fix degenerate single-rail)

bf1ece0458de5c5d59858fdbf5ce44f8b3fad8bc · 2026-05-26 10:26:21 -0700 · Steve Abrams

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files touched

Diff

commit bf1ece0458de5c5d59858fdbf5ce44f8b3fad8bc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 26 10:26:21 2026 -0700

    rails: tag-aware via shared rail-match helper + editorial LABELS (fix degenerate single-rail)
    
    Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
 public/index.html |  2 +-
 server.js         | 12 +++---------
 site.config.json  | 10 +++++-----
 3 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/public/index.html b/public/index.html
index b553851..85678e3 100644
--- a/public/index.html
+++ b/public/index.html
@@ -504,7 +504,7 @@ const HOSTKEY = location.hostname.replace(/\./g, '_');
     document.documentElement.dataset.view = state.view;
   } catch(e){}
 })();
-const LABELS = {"all":"All","commercial":"Commercial-Grade","vinyl":"Performance Vinyl"};
+const LABELS = {"all":"All","commercial":"Commercial-Grade","vinyl":"Performance Vinyl","woven":"Woven & Cloth","textured":"Textured & Tactile","grasscloth":"Grasscloth","contemporary":"Contemporary","beige":"Warm Neutrals","traditional":"Traditional"};
 
 function escAttr(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, c => ({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[c])); }
 // Image-URL allowlist: only DW Shopify CDN + designerwallcoverings.com (defends against XSS via crafted products.json)
diff --git a/server.js b/server.js
index f342645..4ea8545 100644
--- a/server.js
+++ b/server.js
@@ -7,6 +7,7 @@ const express = require('express');
 const helmet = require('helmet');
 const path = require('path');
 const fs = require('fs');
+const { buildRails, railFacets } = require('../_shared/rail-match');
 
 const PORT = process.env.PORT || 9846;
 const DW_SHOPIFY = 'https://designerwallcoverings.com';
@@ -187,12 +188,7 @@ app.get('/api/products', (req, res) => {
 });
 
 app.get('/api/sliders', (req, res) => {
-  const out = [];
-  for (const a of SITE_RAILS) {
-    const items = PRODUCTS_NICHE.filter(p => p.aesthetic === a).slice(0, 12);
-    if (items.length >= 4) out.push({ aesthetic: a, items });
-  }
-  res.json({ rails: out });
+  res.json({ rails: buildRails(PRODUCTS_NICHE, SITE_RAILS) });
 });
 
 // Facet counts reflect the current filtered list (q + optionally aesthetic),
@@ -202,9 +198,7 @@ app.get('/api/sliders', (req, res) => {
 app.get('/api/facets', (req, res) => {
   const { q, aesthetic } = req.query;
   const filtered = applyFilters(PRODUCTS_NICHE, { q, aesthetic });
-  const aesthetics = {};
-  for (const p of filtered) aesthetics[p.aesthetic] = (aesthetics[p.aesthetic] || 0) + 1;
-  res.json({ aesthetics, total: filtered.length });
+  res.json({ aesthetics: railFacets(PRODUCTS_NICHE, SITE_RAILS), total: filtered.length });
 });
 
 app.get('/api/health', (req, res) => res.json({ status: 'ok', count: PRODUCTS_NICHE.length, dropped: DROPPED }));
diff --git a/site.config.json b/site.config.json
index 561d394..98fc4d9 100644
--- a/site.config.json
+++ b/site.config.json
@@ -10,12 +10,12 @@
     "accent": "#b89060"
   },
   "rails": [
-    "commercial",
-    "grasscloth",
-    "vinyl",
-    "architectural",
+    "woven",
     "textured",
-    "woven"
+    "grasscloth",
+    "contemporary",
+    "beige",
+    "traditional"
   ],
   "port": 9846
 }

← ca73a39 rails: editorial labels for firing aesthetic buckets  ·  back to Fabricwallpaper  ·  chore: sync package-lock with declared dotenv dep 2f5dca2 →