← back to Stars of Design
views/public/clients.ejs
114 lines
<%- include('../partials/head', { title: 'DW Designer Clients · Stars of Design' }) %>
<%- include('../partials/header') %>
<main class="home">
<section class="hero-gucci" aria-labelledby="hero-wordmark" style="min-height:42vh">
<div class="hero-gucci-bg" role="img" aria-label="Editorial interior placeholder"></div>
<div class="hero-gucci-stack">
<h1 id="hero-wordmark" class="hero-gucci-wordmark" style="font-size:clamp(40px,5vw,72px)">DW Clients</h1>
<p class="hero-gucci-tagline"><em>The designers and firms who actually buy from Designer Wallcoverings.</em></p>
<div class="hero-gucci-cta">
<a class="btn ghost" href="/designers">Editorial directory →</a>
</div>
</div>
</section>
<section class="section" id="clients">
<div class="wrap">
<div class="section-head">
<h2>Active DW client list</h2>
<span class="muted"><%= clients.length %> of <%= total %> · pulled from George Gmail + DW Shopify orders</span>
</div>
<form class="grid-controls" method="get" action="/clients" data-grid-controls>
<div class="grid-controls-left">
<input type="search" name="q" placeholder="Search name, firm, city" value="<%= (filter.q||'').replace(/"/g,'"') %>" style="background:transparent;border:1px solid var(--line,#2a2620);color:inherit;padding:7px 12px;border-radius:6px;font:inherit;min-width:240px">
<button type="submit" class="btn ghost" style="margin-left:8px">Search</button>
</div>
<div class="grid-controls-right">
<label class="control">
<span>Sort</span>
<select id="sort-select" name="sort" data-sort onchange="this.form.submit()">
<option value="default" <%= sortKey==='default' ? 'selected' : '' %>>Premium first</option>
<option value="name_az" <%= sortKey==='name_az' ? 'selected' : '' %>>Name A→Z</option>
<option value="name_za" <%= sortKey==='name_za' ? 'selected' : '' %>>Name Z→A</option>
<option value="firm" <%= sortKey==='firm' ? 'selected' : '' %>>By firm</option>
<option value="city" <%= sortKey==='city' ? 'selected' : '' %>>By city</option>
<option value="claimed" <%= sortKey==='claimed' ? 'selected' : '' %>>Claimed first</option>
</select>
</label>
<label class="control">
<span>Density</span>
<input id="density-slider" type="range" min="220" max="440" step="20" value="320" data-density>
</label>
</div>
</form>
<% if (!clients.length) { %>
<p class="muted" style="padding:60px 0;text-align:center;font-style:italic">No clients match that filter yet.</p>
<% } %>
<div class="designer-grid" data-designer-grid>
<% clients.forEach(function(c) { %>
<article class="designer-card">
<header>
<span class="card-mark" aria-hidden="true"><%= (c.full_name||'?').split(' ').map(s=>s[0]).join('').slice(0,2).toUpperCase() %></span>
<div>
<h3><a href="/clients/<%= c.slug %>"><%= c.full_name %></a><% if (c.premium_tier) { %> <span class="chip gold" style="margin-left:6px"><%= c.premium_tier.toUpperCase() %></span><% } %></h3>
<p class="muted">
<% if (c.role) { %><%= c.role %><% if (c.firm) { %> · <%= c.firm.name %><% } %>
<% } else if (c.firm) { %><%= c.firm.name %><% } %>
<% if (c.city || c.state) { %> · <%= [c.city, c.state, c.country && c.country !== 'United States' && c.country !== 'USA' ? c.country : null].filter(Boolean).join(', ') %><% } %>
</p>
</div>
</header>
<% if (c.areas && c.areas.length) { %>
<ul class="tags">
<% c.areas.slice(0,6).forEach(function(a) { %><li><%= a %></li><% }); %>
</ul>
<% } %>
<% if (c.links && (c.links.linkedin || c.links['firm-site'] || c.links.instagram)) { %>
<div class="card-links" style="display:flex;gap:10px;margin-top:10px;flex-wrap:wrap">
<% (c.links.linkedin||[]).slice(0,1).forEach(function(u) { %>
<a href="<%= u %>" rel="nofollow noopener noreferrer" target="_blank" class="muted" style="font-size:12px">LinkedIn ↗</a>
<% }); %>
<% (c.links['firm-site']||[]).slice(0,1).forEach(function(u) { %>
<a href="<%= u %>" rel="nofollow noopener noreferrer" target="_blank" class="muted" style="font-size:12px">Website ↗</a>
<% }); %>
<% (c.links.instagram||[]).slice(0,1).forEach(function(u) { %>
<a href="<%= u %>" rel="nofollow noopener noreferrer" target="_blank" class="muted" style="font-size:12px">Instagram ↗</a>
<% }); %>
</div>
<% } %>
</article>
<% }); %>
</div>
</div>
</section>
<section class="section alt">
<div class="wrap">
<h2>How this list is built</h2>
<p class="prose">
We pull DW order notifications, sample requests, trade-program signups,
and project replies from the <code>info@designerwallcoverings.com</code>
inbox via the George Gmail agent. Each contact's email signature is
passed through a local LLM (Ollama gemma3:12b) to extract firm name,
role, city, state, and areas served. <strong>We never extract street
addresses or zip codes</strong> — that's a directory-PII policy.
</p>
<p class="prose">
Designers can <a href="/submit">claim and edit their profile</a> at any
time. Claimed profiles get a Verified badge, real headshot upload, and
full portfolio gallery.
</p>
</div>
</section>
</main>
<%- include('../partials/footer') %>
<script src="/js/grid-controls.js" defer></script>
<script src="/js/hamburger.js" defer></script>