← back to Marketing Command Center

drafts/glitter-sequin-exclusive/build-email.mjs

219 lines

// Build the send-ready "Glitter & Sequin — Exclusive Collection" email HTML.
// Reuses the DW email design system (Cormorant Garamond wordmark, ink/cream/gold
// palette, centered hero image block, 2-col product grid, gold CTA button,
// CAN-SPAM footer). Real glitterwalls product imagery + product URLs.
// $0 (local render, no paid API).
import { writeFileSync } from 'node:fs';

const BRAND = {
  name: 'Designer Wallcoverings',
  ink: '#14110f', cream: '#f4efe7', gold: '#b8925a', paper: '#ffffff',
  muted: '#6b6259',
  display: "'Cormorant Garamond', Georgia, 'Times New Roman', serif",
  body: "Inter, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif",
};

// CAN-SPAM physical mailing address (real DW/Glitter Walls address, Sherman Oaks).
const ADDRESS = '15442 Ventura Blvd #102, Sherman Oaks, CA 91403';
const PHONE = '(888) 373-4564';
// www is the canonical host the live store serves (non-www 301→www) — link to www
// directly to avoid a redirect hop on every click.
const SITE = 'https://www.designerwallcoverings.com';
// Real, live collection: "Glitter + Sequins" (663 products). The earlier
// /collections/glitter-sequin was invented and 404'd — verified fix.
const COLLECTION_URL = 'https://www.designerwallcoverings.com/collections/glitter-wallpaper';

// Hero — Hollywood Sequin (White). Verified LIVE (200) + image resolves.
const HERO = {
  title: 'Hollywood Sequin — White',
  img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/products/96899f7e4f23e376b65ddb07bbdd3af7.jpg?v=1572309253',
  url: 'https://www.designerwallcoverings.com/products/hollywood-sequin-wallcoverings-hsw-51526',
};

// Grid — sequin + glass-bead, mixed colorways. EVERY url + image verified LIVE 200
// against the live store (rebuilt off the collection feed, not stale local data).
// Note: some handles carry "wall-paper" in the SLUG (unavoidable, live URL) — the
// banned word never appears in any visible copy or alt text.
const GRID = [
  { title: 'Sexy Sequin — Silver',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/sexy-sequin-wallcovering--silver-mirror_161dfd81-3134-498e-a6cf-9f7188cf989b.jpg',
    url: 'https://www.designerwallcoverings.com/products/sexy-sequin-wallcovering-silver-mirror-gls-102' },
  { title: 'Sequin — Black',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/products/371c9614029653c869b8980b744600fa.jpg',
    url: 'https://www.designerwallcoverings.com/products/sequin-wall-paper-black-gls-417' },
  { title: 'Venezia Glass Beads — Gold',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/936928828518ebf09a70d136c7642b7a.jpg',
    url: 'https://www.designerwallcoverings.com/products/venezia-glass-beads-wall-paper-gold-gls-111-glass-beads-gold' },
  { title: 'Venezia Glass Beads — Silver',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/venezia-tm-glass-beads-silver-gls-112-glass-beads-silver-clean.jpg',
    url: 'https://www.designerwallcoverings.com/products/venezia-tm-glass-beads-silver-gls-112-glass-beads-silver' },
  { title: 'Sexy Sequin — Pink',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/e7ad686e70a8478d4c42390e86b37863.jpg',
    url: 'https://www.designerwallcoverings.com/products/sexy-sequin-wallcovering-miami-beach-gls-107' },
  { title: 'Hollywood Glamour Sequin — Silver Multi-Color',
    img: 'https://cdn.shopify.com/s/files/1/0015/4117/7456/files/glm-still-GLM-52009-SAMPLE.jpg',
    url: 'https://www.designerwallcoverings.com/products/hollywood-glamour-sequin-silver-multi-color-glm-52009' },
];

const SUBJECT = 'By invitation: the Glitter & Sequin collection';
const PREHEADER = 'A private release of shimmer, sequin, and metallic, reserved for our trade list first.';

const gridCells = GRID.map((p) => `
              <td width="50%" valign="top" style="padding:8px;">
                <a href="${p.url}" style="text-decoration:none;color:${BRAND.ink};">
                  <img src="${p.img}" width="252" alt="${p.title}"
                       style="width:100%;max-width:252px;height:auto;display:block;border:0;border-radius:2px;" />
                  <div style="font-family:${BRAND.body};font-size:12px;line-height:1.4;color:${BRAND.ink};padding:10px 2px 0;letter-spacing:.2px;">${p.title}</div>
                </a>
              </td>`);

// pair grid cells into rows of 2
const gridRows = [];
for (let i = 0; i < gridCells.length; i += 2) {
  gridRows.push(`<tr>${gridCells[i] || ''}${gridCells[i + 1] || '<td width="50%"></td>'}</tr>`);
}

const html = `<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="color-scheme" content="light" />
  <title>${SUBJECT}</title>
  <style>
    @media only screen and (max-width:600px){
      .container{width:100% !important;}
      .px{padding-left:20px !important;padding-right:20px !important;}
      .h1{font-size:34px !important;}
    }
    a{color:${BRAND.gold};}
  </style>
</head>
<body style="margin:0;padding:0;background:${BRAND.cream};">
  <!-- preheader (hidden preview text) -->
  <div style="display:none;max-height:0;overflow:hidden;opacity:0;color:${BRAND.cream};font-size:1px;line-height:1px;">${PREHEADER}&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;</div>

  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:${BRAND.cream};">
    <tr><td align="center" style="padding:28px 12px;">

      <table role="presentation" class="container" width="600" cellpadding="0" cellspacing="0" style="width:600px;max-width:600px;background:${BRAND.paper};border:1px solid #e7ddcd;">

        <!-- Wordmark header -->
        <tr>
          <td align="center" class="px" style="padding:34px 40px 10px;">
            <a href="${SITE}" style="text-decoration:none;">
              <div style="font-family:${BRAND.display};font-size:26px;letter-spacing:4px;color:${BRAND.ink};text-transform:uppercase;font-weight:600;">Designer Wallcoverings</div>
            </a>
            <div style="height:1px;background:${BRAND.gold};width:52px;margin:14px auto 0;"></div>
            <div style="font-family:${BRAND.body};font-size:10px;letter-spacing:3px;color:${BRAND.gold};text-transform:uppercase;padding-top:14px;">Private Release &nbsp;·&nbsp; By Invitation</div>
          </td>
        </tr>

        <!-- Headline -->
        <tr>
          <td align="center" class="px" style="padding:16px 40px 6px;">
            <div class="h1" style="font-family:${BRAND.display};font-size:44px;line-height:1.05;color:${BRAND.ink};font-weight:600;">Glitter &amp; Sequin</div>
            <div style="font-family:${BRAND.body};font-size:14px;line-height:1.6;color:${BRAND.muted};padding-top:14px;max-width:420px;margin:0 auto;">A private release of shimmer, sequin, and metallic, reserved for our trade list first.</div>
          </td>
        </tr>

        <!-- Hero image -->
        <tr>
          <td align="center" class="px" style="padding:22px 40px 6px;">
            <a href="${HERO.url}" style="text-decoration:none;">
              <img src="${HERO.img}" width="520" alt="${HERO.title}" style="width:100%;max-width:520px;height:auto;display:block;border:0;border-radius:2px;" />
            </a>
            <div style="font-family:${BRAND.body};font-size:11px;letter-spacing:.4px;color:${BRAND.muted};padding-top:8px;">${HERO.title}</div>
          </td>
        </tr>

        <!-- Body copy — exclusivity -->
        <tr>
          <td class="px" style="padding:22px 48px 6px;">
            <p style="font-family:${BRAND.body};font-size:15px;line-height:1.75;color:${BRAND.ink};margin:0 0 16px;">
              Some surfaces are not meant for the open floor. The Glitter &amp; Sequin collection is a private release: hand-selected shimmer, sequin, and beaded metallic wallcoverings we are opening to our trade list before anyone else. These are the pieces we hold back for a jewel-box powder room, a private dining room, a client who wants a wall to catch the light and keep it.
            </p>
            <p style="font-family:${BRAND.body};font-size:15px;line-height:1.75;color:${BRAND.ink};margin:0 0 8px;">
              Allocation is limited. Each pattern is chosen by hand, and several colorways are held for our designers and members first. You will not find this edit merchandised anywhere else on the site.
            </p>
          </td>
        </tr>

        <!-- CTA -->
        <tr>
          <td align="center" style="padding:14px 40px 22px;">
            <table role="presentation" cellpadding="0" cellspacing="0"><tr>
              <td align="center" bgcolor="${BRAND.ink}" style="border-radius:2px;">
                <a href="${COLLECTION_URL}" style="display:inline-block;font-family:${BRAND.body};font-size:12px;letter-spacing:2px;text-transform:uppercase;color:${BRAND.cream};text-decoration:none;padding:15px 34px;">See the private collection</a>
              </td>
            </tr></table>
          </td>
        </tr>

        <!-- Product grid -->
        <tr>
          <td class="px" style="padding:6px 32px 8px;">
            <div style="font-family:${BRAND.display};font-size:20px;color:${BRAND.ink};text-align:center;padding-bottom:6px;">The edit</div>
            <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
              ${gridRows.join('\n              ')}
            </table>
          </td>
        </tr>

        <!-- Sensory line -->
        <tr>
          <td class="px" style="padding:18px 48px 6px;">
            <p style="font-family:${BRAND.body};font-size:14px;line-height:1.7;color:${BRAND.muted};margin:0;text-align:center;font-style:italic;">
              Sequins that read like light: sequin in silver and disco pink, Venezia glass beads pressed by hand, metallic that shifts as you cross the room.
            </p>
          </td>
        </tr>

        <!-- Secondary CTAs -->
        <tr>
          <td align="center" class="px" style="padding:18px 40px 30px;">
            <a href="${COLLECTION_URL}" style="font-family:${BRAND.body};font-size:12px;letter-spacing:1px;color:${BRAND.gold};text-decoration:none;">See the collection</a>
            <span style="color:#d8ccb8;padding:0 8px;">·</span>
            <a href="${SITE}/pages/samples" style="font-family:${BRAND.body};font-size:12px;letter-spacing:1px;color:${BRAND.gold};text-decoration:none;">Request memo samples</a>
            <span style="color:#d8ccb8;padding:0 8px;">·</span>
            <a href="${SITE}/pages/trade" style="font-family:${BRAND.body};font-size:12px;letter-spacing:1px;color:${BRAND.gold};text-decoration:none;">Book a trade consultation</a>
          </td>
        </tr>

        <!-- CAN-SPAM footer -->
        <tr>
          <td style="background:${BRAND.cream};border-top:1px solid #e7ddcd;padding:24px 40px 30px;">
            <div style="font-family:${BRAND.display};font-size:15px;letter-spacing:2px;color:${BRAND.ink};text-transform:uppercase;text-align:center;">Designer Wallcoverings</div>
            <p style="font-family:${BRAND.body};font-size:11px;line-height:1.7;color:${BRAND.muted};text-align:center;margin:10px 0 0;">
              ${ADDRESS}<br/>
              ${PHONE} &nbsp;·&nbsp; <a href="mailto:info@glitterwalls.com" style="color:${BRAND.muted};text-decoration:underline;">info@glitterwalls.com</a>
            </p>
            <p style="font-family:${BRAND.body};font-size:11px;line-height:1.7;color:${BRAND.muted};text-align:center;margin:12px 0 0;">
              You are receiving this because you are on the Designer Wallcoverings trade and design list.<br/>
              <a href="[[trackingUnsubscribe]]" style="color:${BRAND.muted};text-decoration:underline;">Unsubscribe</a>
              &nbsp;·&nbsp;
              <a href="[[updateProfile]]" style="color:${BRAND.muted};text-decoration:underline;">Update your preferences</a>
            </p>
          </td>
        </tr>

      </table>
    </td></tr>
  </table>
</body>
</html>`;

writeFileSync(new URL('./campaign.html', import.meta.url), html);

const payload = {
  name: 'Glitter & Sequin — Exclusive Collection',
  subject: SUBJECT,
  from: 'info@designerwallcoverings.com',
  html,
};
writeFileSync(new URL('./draft-payload.json', import.meta.url), JSON.stringify(payload, null, 2));
console.log('wrote campaign.html', html.length, 'bytes; draft-payload.json', JSON.stringify(payload).length, 'bytes');
console.log('subject:', SUBJECT);
console.log('preheader:', PREHEADER);