← back to Patterndesignlab

scripts/build-trends.js

78 lines

// build-trends.js — editorial Trend Boards from OWNED catalog designs only.
// Each board: title, blurb, palette hexes, motif direction, price band, and 2-3 REAL
// representative designs pulled live from the DB (so every link/thumb is valid).
// Graceful-empty by design: writes an explicit shape trends.html renders without 500s.
// $0 (local) — pure DB read + file write.
const fs = require('fs');
const path = require('path');
const { Client } = require('pg');

const OUT = path.join(__dirname, '..', 'data', 'trend-board.json');

// lane definition → SQL predicate that selects representative OWNED designs
const LANES = [
  {
    title: 'Romantic Maximalist Heritage Florals',
    blurb: 'The single biggest wallcovering trend of 2026 — dense heritage botanicals, trellis work and vines in saturated, layered color. Maximalism has fully replaced gray minimalism.',
    palette: ['#3e603c', '#6b8e5a', '#e8dcc0', '#8a5a2b'],
    motif: 'Botanical / trellis / vine — dense, layered, open ground',
    priceBand: '$149–$495',
    where: `style ILIKE '%Heritage%' OR style ILIKE '%Botanical%' OR motif='floral'`,
  },
  {
    title: 'Dark Moody Nocturne Florals',
    blurb: 'Saturated blooms on ink, aubergine and forest grounds — the drama-forward end of the floral trend. Reads as luxe-textile for dining rooms, studies and hospitality.',
    palette: ['#17141d', '#4a1f2b', '#7a2f45', '#c9a24a'],
    motif: 'Camellia / magnolia / rose on near-black ground',
    priceBand: '$149–$495',
    where: `style ILIKE '%Moody%' OR style ILIKE '%Noir%' OR title ILIKE '%Nocturne%'`,
  },
  {
    title: 'Characterful Animal Whimsy',
    blurb: 'Conversation-piece patterns with a story — illustrative animals kept polite enough for grown-up neutrals. Our clearest signature lane and a consistent Etsy/Spoonflower seller.',
    palette: ['#938f85', '#3e603c', '#76443a', '#e3ded4'],
    motif: 'Illustrative animal characters — not skin-print',
    priceBand: '$149–$495',
    where: `motif='animal' OR category ILIKE '%animal%' OR category ILIKE '%zoo%' OR category ILIKE '%dog%'`,
  },
  {
    title: 'Warm Neutral Grounds — Chamois & Greige',
    blurb: 'Pantone-2026 warm-white territory: quiet, textural patterns on chamois and greige that flatter furniture instead of fighting it. The everyday bread-and-butter of a licensing catalog.',
    palette: ['#e3ded4', '#c9b99c', '#938f85', '#f1e5c9'],
    motif: 'Low-contrast texture, damask & lattice on warm neutral',
    priceBand: '$149–$795',
    where: `colorway IN ('Greige','Chamois','Cream','Neutral') OR title ILIKE '%Greige%' OR title ILIKE '%Chamois%'`,
  },
];

(async () => {
  const db = new Client({ host: '127.0.0.1', user: 'dw_admin', database: 'patterndesignlab' });
  await db.connect();
  const trends = [];
  for (const lane of LANES) {
    const r = await db.query(
      `SELECT slug, title, img, dominant_hex, style, colorway, price_min
         FROM designs WHERE ${lane.where}
         ORDER BY created_at DESC LIMIT 3`);
    if (!r.rowCount) continue;                       // skip empty lanes — never fabricate
    trends.push({
      title: lane.title, blurb: lane.blurb, palette: lane.palette,
      motif: lane.motif, priceBand: lane.priceBand,
      designs: r.rows.map(d => ({
        slug: d.slug, title: d.title, img: d.img,
        dominant_hex: d.dominant_hex, style: d.style, colorway: d.colorway,
        priceFrom: d.price_min,
      })),
    });
  }
  const board = {
    scannedAt: new Date().toISOString(),
    source: 'patterndesignlab editorial + owned catalog',
    market: 'US wallcovering ~$12B in 2026, +3.56%/yr. Maximalism has replaced gray minimalism; wallpaper sales up every year since 2020.',
    trends,
  };
  fs.writeFileSync(OUT, JSON.stringify(board, null, 2));
  console.log(`Wrote ${trends.length} trend boards referencing ${trends.reduce((n, t) => n + t.designs.length, 0)} owned designs → ${path.relative(path.join(__dirname, '..'), OUT)}`);
  await db.end();
})().catch(e => { console.error(e); process.exit(1); });