← back to Dw Yolo Loop
Vendor-landing template: config-driven + links to live Shopify (not a competing store)
8489a632bad383f148e32e35cc2237467548e498 · 2026-06-12 10:51:31 -0700 · Steve Abrams
- site.config.js: per-line config (vendor, copy, palette, data paths, storeBase) — clone block for other lines
- server reads VENDOR env + config; /api/config endpoint; attaches store_url per product (mfr_sku→live handle map)
- PDP CTAs ('Shop on Designer Wallcoverings', sample) + bottom shopbar link OUT to live store; rel=canonical→live PDP (SEO: complement not compete, per DTD Codex dissent)
- replaces preview-flag with shopbar; removes newwall source link
Files touched
M artmura-site/public/index.htmlM artmura-site/public/product.htmlM artmura-site/public/styles.cssM artmura-site/server.jsA artmura-site/site.config.jsA scripts/artmura-onboard/data/artmura-store-handles.json
Diff
commit 8489a632bad383f148e32e35cc2237467548e498
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Jun 12 10:51:31 2026 -0700
Vendor-landing template: config-driven + links to live Shopify (not a competing store)
- site.config.js: per-line config (vendor, copy, palette, data paths, storeBase) — clone block for other lines
- server reads VENDOR env + config; /api/config endpoint; attaches store_url per product (mfr_sku→live handle map)
- PDP CTAs ('Shop on Designer Wallcoverings', sample) + bottom shopbar link OUT to live store; rel=canonical→live PDP (SEO: complement not compete, per DTD Codex dissent)
- replaces preview-flag with shopbar; removes newwall source link
---
artmura-site/public/index.html | 2 +-
artmura-site/public/product.html | 9 +-
artmura-site/public/styles.css | 8 +-
artmura-site/server.js | 29 +++-
artmura-site/site.config.js | 22 +++
.../data/artmura-store-handles.json | 163 +++++++++++++++++++++
6 files changed, 217 insertions(+), 16 deletions(-)
diff --git a/artmura-site/public/index.html b/artmura-site/public/index.html
index 972c777..3036845 100644
--- a/artmura-site/public/index.html
+++ b/artmura-site/public/index.html
@@ -87,7 +87,7 @@
</div>
</footer>
-<div class="preview-flag">STAGING PREVIEW · 161 Artmura products · pricing set at website price, <b>no trade discount</b> · not yet deployed</div>
+<a class="shopbar" href="https://www.designerwallcoverings.com/search?q=Artmura" target="_blank" rel="noopener">The Artmura collection is live at <b>Designer Wallcoverings</b> — shop all 161 designs →</a>
<script>
const $=s=>document.querySelector(s), grid=$('#grid');
diff --git a/artmura-site/public/product.html b/artmura-site/public/product.html
index 16a972f..6fda7dc 100644
--- a/artmura-site/public/product.html
+++ b/artmura-site/public/product.html
@@ -19,7 +19,7 @@
<main class="pdp" id="pdp"><div class="crumbs">Loading…</div></main>
-<div class="preview-flag">STAGING PREVIEW · 161 Artmura products · pricing set at website price, <b>no trade discount</b> · not yet deployed</div>
+<a class="shopbar" href="https://www.designerwallcoverings.com/search?q=Artmura" target="_blank" rel="noopener">Shop the full Artmura collection at <b>Designer Wallcoverings</b> →</a>
<script>
const handle=location.pathname.split('/').pop();
@@ -47,8 +47,8 @@ function specRow(k,v){return v?`<div class="row"><span class="k">${k}</span><spa
<h1>${esc(p.color||p.title)}</h1>
<div class="colr">${esc(p.sku)} · ${esc(p.substrate||'Non-Woven')}</div>
<div class="price">$${(p.price||0).toFixed(0)} <small>per yard</small></div>
- <button class="cta" id="sample">Order Sample · $${(p.sample_price||5).toFixed(0)}</button>
- <a class="cta ghost" href="${esc(p.product_url)}" target="_blank" rel="noopener noreferrer">View source reference ↗</a>
+ <a class="cta" href="${esc(p.store_url)}" target="_blank" rel="noopener">Shop on Designer Wallcoverings →</a>
+ <a class="cta ghost" href="${esc(p.store_url)}" target="_blank" rel="noopener">Order a sample · $${(p.sample_price||5).toFixed(0)}</a>
<div class="spec">
${specRow('Item code',p.sku)}
${specRow('Grade',p.grade)}
@@ -96,7 +96,8 @@ function specRow(k,v){return v?`<div class="row"><span class="k">${k}</span><spa
document.getElementById('main').style.backgroundImage=`url('${t.dataset.s}')`;
document.querySelectorAll('.thumbs .t').forEach(x=>x.classList.remove('on'));t.classList.add('on');
});
- document.getElementById('sample').onclick=()=>alert('Sample ordering is disabled in this preview build.');
+ // SEO: canonical → the live Shopify product (this landing complements, not competes)
+ if(p.store_url){const c=document.createElement('link');c.rel='canonical';c.href=p.store_url;document.head.appendChild(c);}
})();
</script>
</body>
diff --git a/artmura-site/public/styles.css b/artmura-site/public/styles.css
index 7083110..a280627 100644
--- a/artmura-site/public/styles.css
+++ b/artmura-site/public/styles.css
@@ -164,9 +164,11 @@ footer{border-top:1px solid var(--line);background:var(--paper)}
.pc-n{display:block;font-family:var(--serif);font-size:16px;line-height:1.1;margin-top:2px}
@media(max-width:1080px){.pair-grid{grid-template-columns:repeat(3,1fr)}}
@media(max-width:560px){.pair-grid{grid-template-columns:repeat(2,1fr)}}
-.preview-flag{position:fixed;bottom:0;left:0;right:0;z-index:50;background:#211d18;color:#f6f2ec;
- font-size:11px;letter-spacing:.05em;text-align:center;padding:7px 14px}
-.preview-flag b{color:#caa45f}
+.shopbar{position:fixed;bottom:0;left:0;right:0;z-index:50;background:#211d18;color:#f6f2ec;
+ font-size:12px;letter-spacing:.06em;text-align:center;padding:11px 14px;display:block;
+ text-decoration:none;transition:background .2s}
+.shopbar:hover{background:#2f2920}
+.shopbar b{color:#caa45f;font-weight:600}
@media(max-width:1080px){:root{--cols:3}.pdp-top{grid-template-columns:1fr;gap:30px}.story{grid-template-columns:1fr;gap:26px}}
@media(max-width:720px){:root{--cols:2}.hero h1{font-size:64px}.grid{gap:14px}}
diff --git a/artmura-site/server.js b/artmura-site/server.js
index 64b349a..02aa1f5 100644
--- a/artmura-site/server.js
+++ b/artmura-site/server.js
@@ -1,13 +1,19 @@
-/* Artmura microsite — serves the staged catalog as an editorial storefront.
- PREVIEW ONLY: pricing is newwall retail reference; not deployed/customer-facing
- until Artmura wholesale cost + trade discount land (see artmura-onboard-gated memory). */
+/* DW vendor-landing — editorial brand lookbook over a vendor's catalog.
+ Read-only: links OUT to the live Shopify store for purchase (no commerce duplication).
+ Config-driven (site.config.js) so other DW lines reuse the same template. */
const express = require('express');
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
-const PKG = path.join(ROOT, 'scripts/artmura-onboard/data/artmura.json');
-const IMG_DIR = path.join(ROOT, '.newwall-ref/artmura/images');
+const VENDOR = process.env.VENDOR || 'artmura';
+const CFG = require('./site.config.js')[VENDOR];
+if (!CFG) { console.error(`No site.config for VENDOR=${VENDOR}`); process.exit(1); }
+
+const PKG = path.join(ROOT, CFG.dataFile);
+const COLORS_PATH = path.join(ROOT, CFG.colorsFile);
+const HANDLES_PATH = path.join(ROOT, 'scripts/artmura-onboard/data/artmura-store-handles.json');
+const IMG_DIR = path.join(ROOT, CFG.imagePrefix);
const PORT = process.env.PORT || 9921;
const app = express();
@@ -20,16 +26,18 @@ function localImages(r) {
return `/images/${r.mfr_sku}-${i + 1}${ext}`;
});
}
-const COLORS_PATH = path.join(ROOT, 'scripts/artmura-onboard/data/artmura-colors.json');
let CATALOG = [];
function load() {
const d = JSON.parse(fs.readFileSync(PKG, 'utf8'));
- let colors = {};
+ let colors = {}, handles = {};
try { colors = JSON.parse(fs.readFileSync(COLORS_PATH, 'utf8')); } catch {}
+ try { handles = JSON.parse(fs.readFileSync(HANDLES_PATH, 'utf8')); } catch {}
CATALOG = d.products.map(r => {
const imgs = localImages(r);
const c = colors[r.mfr_sku] || {};
+ const liveHandle = handles[(r.mfr_sku || '').toUpperCase()] || null;
return {
+ store_url: liveHandle ? `${CFG.storeBase}/products/${liveHandle}` : CFG.storeBase,
hex: c.hex || null, hue: c.hue ?? null, color_bucket: c.bucket || null,
sat: c.sat ?? null, val: c.val ?? null,
handle: r.handle,
@@ -56,11 +64,16 @@ function load() {
published_at: r.published_at,
};
});
- console.log(`loaded ${CATALOG.length} Artmura products`);
+ console.log(`[${VENDOR}] loaded ${CATALOG.length} products`);
}
load();
// --- API ---
+app.get('/api/config', (_req, res) => res.json({
+ vendor: CFG.vendor, wordmark: CFG.wordmark, kicker: CFG.kicker, tagline: CFG.tagline,
+ booksHeading: CFG.booksHeading, title: CFG.title, metaDescription: CFG.metaDescription,
+ storeBase: CFG.storeBase, palette: CFG.palette,
+}));
app.get('/api/products', (_req, res) => res.json({ count: CATALOG.length, products: CATALOG }));
app.get('/api/product/:handle', (req, res) => {
const p = CATALOG.find(x => x.handle === req.params.handle);
diff --git a/artmura-site/site.config.js b/artmura-site/site.config.js
new file mode 100644
index 0000000..f727f0b
--- /dev/null
+++ b/artmura-site/site.config.js
@@ -0,0 +1,22 @@
+/**
+ * Per-line config for the DW vendor-landing template.
+ * Clone this block for another line (Schumacher, Arte, etc.) → new config + a data snapshot,
+ * and the same template renders a branded editorial landing that links into the live store.
+ */
+module.exports = {
+ artmura: {
+ vendor: 'Artmura',
+ title: 'Artmura — Italian Non-Woven Wallcoverings',
+ wordmark: 'Artmura',
+ kicker: 'Made in Italy · Non-Woven Wallcoverings',
+ tagline: 'Architectural surfaces, hand-finished.',
+ booksHeading: 'Opera & La Scala Milano',
+ metaDescription: 'Artmura: architectural, hand-finished non-woven wallcoverings made in Italy. 161 designs across the Opera and La Scala Milano collections.',
+ dataFile: 'scripts/artmura-onboard/data/artmura.json',
+ colorsFile: 'scripts/artmura-onboard/data/artmura-colors.json',
+ imagePrefix: '.newwall-ref/artmura/images',
+ // live store: cards/PDP CTAs link OUT to the real Shopify product for purchase
+ storeBase: 'https://www.designerwallcoverings.com',
+ palette: { bg: '#f6f2ec', ink: '#211d18', accent: '#8c7a5f', gold: '#a98c54' },
+ },
+};
diff --git a/scripts/artmura-onboard/data/artmura-store-handles.json b/scripts/artmura-onboard/data/artmura-store-handles.json
new file mode 100644
index 0000000..37b42c2
--- /dev/null
+++ b/scripts/artmura-onboard/data/artmura-store-handles.json
@@ -0,0 +1,163 @@
+{
+ "MAT340": "materia-pearl-artmura-1",
+ "MAT343": "materia-silver-artmura-1",
+ "MAT344": "materia-taupe-artmura",
+ "ORI442": "origami-gold-artmura",
+ "ORI446": "origami-brown-artmura",
+ "ORI452": "origami-grey-artmura",
+ "COM240": "composizione-off-white-artmura",
+ "COM241": "composizione-black-artmura",
+ "COM242": "composizione-navy-artmura",
+ "COM560": "composizione-off-white-artmura-1",
+ "COM561": "composizione-silver-artmura",
+ "3702": "diapason-silver-artmura",
+ "3204": "flux-copper-artmura",
+ "3301": "pentagram-pearl-artmura",
+ "WOOD N-001": "natural-wood-simply-white-artmura",
+ "WOOD N-002": "natural-wood-sea-salt-artmura",
+ "WOOD M-004": "metal-wood-storm-artmura",
+ "WOOD F-001": "fluo-wood-light-coral-artmura",
+ "TABL-002": "tabula-lacca-pink-artmura",
+ "TABM-001": "tabula-mica-white-artmura",
+ "TABM-003": "tabula-mica-brown-artmura",
+ "TABC-001": "tabula-corten-orange-artmura",
+ "ARC553": "architecture-beige-artmura",
+ "COM603": "composizione-brown-artmura-2",
+ "COM600": "composizione-gold-artmura-1",
+ "COM601": "composizione-red-artmura",
+ "COM562": "composizione-white-artmura",
+ "COM246": "composizione-yellow-artmura",
+ "3705": "diapason-purple-artmura",
+ "CO800": "contemporary-brown-artmura",
+ "WOOD F-009": "fluo-wood-mulberry-artmura",
+ "3203": "flux-pink-artmura",
+ "LAC702": "lacca-white-artmura",
+ "MAT266": "materia-black-artmura",
+ "MAT342": "materia-off-white-artmura",
+ "WOOD N-008": "natural-wood-classic-gray-artmura",
+ "WOOD N-009": "natural-wood-denim-artmura",
+ "WOOD N-004": "natural-wood-peach-artmura",
+ "NY820": "new-york-silver-artmura",
+ "ORI444": "origami-black-artmura",
+ "ORI455": "origami-gold-artmura-1",
+ "3001": "pure-off-white-artmura",
+ "ORI456": "origami-green-artmura",
+ "WOOD N-006": "natural-wood-terracotta-artmura",
+ "TABW-006": "tabula-wax-green-artmura",
+ "OAK754": "oak-blue-artmura",
+ "OAK753": "oak-grey-artmura",
+ "MAT346": "materia-brown-artmura",
+ "OT890": "oriente-gold-artmura",
+ "GOL854": "golden-grey-artmura",
+ "3004": "pure-beige-artmura",
+ "3305": "pentagram-pink-artmura",
+ "ARD921": "ardesia-silver-artmura",
+ "GOL851": "golden-gold-artmura-1",
+ "CO802": "contemporary-beige-artmura",
+ "ARC551": "architecture-grey-artmura",
+ "ARC554": "architecture-silver-artmura",
+ "COM602": "composizione-blue-artmura",
+ "COM564": "composizione-brown-artmura-1",
+ "COM566": "composizione-charcoal-artmura",
+ "COM565": "composizione-green-artmura",
+ "COM604": "composizione-pearl-artmura-1",
+ "LAC700": "lacca-red-artmura",
+ "COM605": "composizione-silver-artmura-1",
+ "3100": "crystal-gold-artmura",
+ "3101": "crystal-silver-artmura",
+ "3104": "crystal-pink-artmura",
+ "WOOD F-006": "fluo-wood-chameleon-artmura",
+ "WOOD F-005": "fluo-wood-hortensia-artmura",
+ "WOOD F-007": "fluo-wood-emerald-artmura",
+ "WOOD F-002": "fluo-wood-wisteria-artmura",
+ "3201": "flux-pearl-artmura",
+ "TABL-001": "tabula-lacca-beige-artmura",
+ "KR902": "kromo-black-artmura-2",
+ "3007": "pure-gold-artmura",
+ "KR900": "kromo-black-artmura-1",
+ "LAC701": "lacca-grey-artmura",
+ "LAC704": "lacca-black-artmura",
+ "LAC703": "lacca-beige-artmura",
+ "MAT345": "materia-gold-artmura-1",
+ "MAT260": "materia-pearl-artmura",
+ "MAT264": "materia-turquoise-artmura",
+ "MAT263": "materia-silver-artmura",
+ "WOOD M-001": "metal-wood-ice-artmura",
+ "WOOD M-003": "metal-wood-steel-artmura",
+ "WOOD N-003": "natural-wood-lime-artmura",
+ "NY821": "new-york-gold-artmura",
+ "WOOD N-005": "natural-wood-salmon-artmura",
+ "OAK751": "oak-yellow-artmura",
+ "OAK752": "oak-off-white-artmura",
+ "OAK750": "oak-brown-artmura",
+ "ORI453": "origami-beige-artmura",
+ "ORI445": "origami-red-artmura",
+ "3303": "pentagram-gold-artmura",
+ "3300": "pentagram-purple-artmura",
+ "TABC-002": "tabula-corten-stone-artmura",
+ "3003": "pure-pink-artmura",
+ "3000": "pure-white-artmura",
+ "TABL-005": "tabula-lacca-teal-artmura",
+ "TABL-003": "tabula-lacca-off-white-artmura",
+ "TABL-006": "tabula-lacca-red-artmura",
+ "TABM-006": "tabula-mica-pink-artmura",
+ "TABM-005": "tabula-mica-blue-artmura",
+ "TABM-007": "tabula-mica-black-artmura",
+ "TABW-001": "tabula-wax-off-white-artmura",
+ "TABW-004": "tabula-wax-purple-artmura",
+ "TABW-007": "tabula-wax-charcoal-artmura",
+ "ARC555": "architecture-gold-artmura",
+ "ARC556": "architecture-red-artmura",
+ "COM245": "composizione-brown-artmura",
+ "COM563": "composizione-gold-artmura",
+ "COM243": "composizione-pearl-artmura",
+ "COM606": "composizione-grey-artmura",
+ "COM244": "composizione-stone-artmura",
+ "CO804": "contemporary-black-artmura",
+ "CO803": "contemporary-grey-artmura",
+ "WOOD F-003": "fluo-wood-seahorse-artmura",
+ "WOOD F-008": "fluo-wood-discus-artmura",
+ "WOOD F-004": "fluo-wood-butterfly-artmura",
+ "3200": "flux-purple-artmura",
+ "GOL852": "golden-brown-artmura",
+ "GOL850": "golden-gold-artmura",
+ "GOL853": "golden-off-white-artmura",
+ "MAT262": "materia-gold-artmura",
+ "MAT341": "materia-grey-artmura",
+ "MAT265": "materia-copper-artmura",
+ "MAT261": "materia-white-artmura",
+ "WOOD M-002": "metal-wood-pearl-artmura",
+ "WOOD M-005": "metal-wood-carbon-artmura",
+ "WOOD N-007": "natural-wood-mint-artmura",
+ "3002": "pure-pearl-artmura",
+ "NY824": "new-york-red-artmura",
+ "NY823": "new-york-copper-artmura",
+ "NY822": "new-york-pearl-artmura",
+ "OT894": "oriente-teal-artmura",
+ "OT892": "oriente-brown-artmura",
+ "OT891": "oriente-terracotta-artmura",
+ "ORI440": "origami-blue-artmura",
+ "ORI441": "origami-copper-artmura",
+ "ORI454": "origami-brown-artmura-1",
+ "ORI443": "origami-stone-artmura",
+ "ORI450": "origami-taupe-artmura",
+ "ORI451": "origami-off-white-artmura",
+ "TABL-004": "tabula-lacca-yellow-artmura",
+ "TABM-002": "tabula-mica-beige-artmura",
+ "TABL-007": "tabula-lacca-black-artmura",
+ "TABM-004": "tabula-mica-silver-artmura",
+ "TABW-002": "tabula-wax-yellow-artmura",
+ "TABW-005": "tabula-wax-teal-artmura",
+ "TABW-003": "tabula-wax-terracotta-artmura",
+ "ARD920": "ardesia-off-white-artmura",
+ "ARD922": "ardesia-brown-artmura",
+ "ARD923": "ardesia-black-artmura",
+ "ARD924": "ardesia-grey-artmura",
+ "CO801": "contemporary-terracotta-artmura",
+ "KR901": "kromo-black-artmura",
+ "KR903": "kromo-black-artmura-3",
+ "KR904": "kromo-black-artmura-4",
+ "OT893": "oriente-black-artmura",
+ "ARC550": "architecture-off-white-artmura",
+ "ARC552": "architecture-grey-artmura-1"
+}
\ No newline at end of file
← 8f441ef Artmura go-live: inventory=2026 both variants + publish to a
·
back to Dw Yolo Loop
·
Vendor-landing factory: build-line.js generates a branded la 5af2df5 →