← back to Designtradelive
views/index.ejs
217 lines
<!doctype html>
<html lang="en">
<head>
<title>DesignTradeLive — the <%= new Date().getFullYear() %> design trade-show calendar</title>
<% const metaDescription = 'The live ' + new Date().getFullYear() + ' design industry calendar: ICFF, NeoCon, KBIS, High Point Market, BDNY, Salone del Mobile, Maison&Objet, Heimtextil, Decorex, Cersaie. Filter by city, category, season.'; %>
<%- include('partials/head', { GA_ID, metaDescription }) %>
</head>
<body>
<%- include('partials/header') %>
<section class="hero">
<div class="hero-inner">
<p class="kicker"><span class="kicker-rule"></span>Issue · The <%= new Date().getFullYear() %> Trade Calendar</p>
<h1>Where the design trade<br><span class="hero-accent">actually shows up.</span></h1>
<p class="lede">High Point to Salone, ICFF to Heimtextil — every market that moves furniture, textiles, tile, and hospitality design, with the dates, venues, and tier you need to plan the year.</p>
<form class="search-bar" method="get" action="/">
<label for="q" class="visually-hidden">Search events</label>
<input id="q" name="q" type="search" placeholder="Search city, show, country, or category" value="<%= q %>">
<% if (cat) { %><input type="hidden" name="category" value="<%= cat %>"><% } %>
<% if (sort && sort !== 'date') { %><input type="hidden" name="sort" value="<%= sort %>"><% } %>
<button type="submit">Search</button>
</form>
<p class="hero-stats">
<span><strong><%= total %></strong> shows tracked</span>
<span class="hero-dot" aria-hidden="true">·</span>
<span><strong><%= categories.length %></strong> categories</span>
<span class="hero-dot" aria-hidden="true">·</span>
<span>Updated for <strong><%= new Date().getFullYear() %></strong></span>
</p>
</div>
</section>
<section class="field-guide" aria-labelledby="field-guide-title">
<div class="field-guide-inner">
<p class="kicker"><span class="kicker-rule"></span>Field Guide</p>
<h2 id="field-guide-title">How to work the year.</h2>
<div class="field-guide-grid">
<article class="fg-card">
<span class="fg-num">01</span>
<h3>Plan in pairs.</h3>
<p>Design weeks travel in clusters — NYCxDESIGN wraps ICFF and WantedDesign into one trip; Milan stretches Salone, Fuorisalone, and the Rho satellites across nine days. Budget the corridor, not the show.</p>
</article>
<article class="fg-card">
<span class="fg-num">02</span>
<h3>Pick your pass.</h3>
<p>Trade-only shows (NeoCon, BDNY, KBIS) gate the floor with a credential check; consumer-facing markets (Maison&Objet, Heimtextil) sell day passes. Apply early — same-week trade approvals are a coin flip.</p>
</article>
<article class="fg-card">
<span class="fg-num">03</span>
<h3>Work the rooms, not the booths.</h3>
<p>The deals happen at the showroom dinners, the rooftop after-parties, and the off-floor previews — not at the 10×10. Calendar the social side first, then fit the floor walk around it.</p>
</article>
</div>
</div>
</section>
<main class="container">
<div class="filters">
<div class="filter-group">
<span class="filter-label">Categories:</span>
<a class="chip <%= !cat ? 'is-active' : '' %>" href="/?<%= q ? 'q=' + encodeURIComponent(q) + '&' : '' %>sort=<%= sort %>">All <em><%= total %></em></a>
<% categories.forEach(([name, count]) => { %>
<a class="chip <%= cat === name ? 'is-active' : '' %>" href="/?<%= q ? 'q=' + encodeURIComponent(q) + '&' : '' %>category=<%= encodeURIComponent(name) %>&sort=<%= sort %>"><%= name %> <em><%= count %></em></a>
<% }) %>
</div>
<div class="grid-controls">
<label class="control">
<span>Sort</span>
<select id="sort-select" data-sort>
<option value="date" <%= sort === 'date' ? 'selected' : '' %>>Soonest</option>
<option value="name" <%= sort === 'name' ? 'selected' : '' %>>Title A→Z</option>
<option value="city" <%= sort === 'city' ? 'selected' : '' %>>City A→Z</option>
<option value="category" <%= sort === 'category' ? 'selected' : '' %>>Category</option>
<option value="tier" <%= sort === 'tier' ? 'selected' : '' %>>Major first</option>
</select>
</label>
<label class="control">
<span>Density</span>
<input id="density-slider" type="range" min="220" max="460" step="10" value="320" data-density>
</label>
</div>
</div>
<% if (events.length === 0) { %>
<p class="empty">No events match your search. <a href="/">Clear filters</a>.</p>
<% } %>
<ul class="event-grid" data-grid>
<% events.forEach(e => { %>
<li class="event-card">
<a class="card-link" href="/events/<%= e.slug %>">
<div class="card-date">
<% const sd = new Date(e.start_date + 'T00:00:00Z'); const ed = new Date(e.end_date + 'T00:00:00Z'); %>
<span class="card-month"><%= sd.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' }).toUpperCase() %></span>
<span class="card-day"><%= sd.getUTCDate() %><% if (ed.getUTCDate() !== sd.getUTCDate() || ed.getUTCMonth() !== sd.getUTCMonth()) { %>–<%= ed.getUTCDate() %><% } %></span>
<span class="card-year"><%= sd.getUTCFullYear() %></span>
</div>
<div class="card-body">
<h2 class="card-name"><%= e.name %></h2>
<p class="card-loc"><%= e.city %><% if (e.country !== 'USA') { %>, <%= e.country %><% } %></p>
<p class="card-summary"><%= e.summary %></p>
<div class="card-meta">
<span class="tag tag-<%= e.tier %>"><%= e.tier %></span>
<span class="tag tag-cat"><%= e.category %></span>
</div>
</div>
</a>
</li>
<% }) %>
</ul>
</main>
<%- include('partials/footer') %>
<!-- DW-HAMBURGER-NAV v1 (canonical 2026-05-10) -->
<style id="dw-hamburger-styles">
/* Canonical hamburger nav — always visible top-right, all viewports.
Standing rule (Steve, 2026-05-08): hamburger is the primary nav. */
.dw-burger-btn {
position: fixed; top: 18px; right: 18px; z-index: 9999;
width: 44px; height: 44px;
background: rgba(20,20,20,0.78); color: #f5f1e8;
backdrop-filter: blur(8px) saturate(140%);
-webkit-backdrop-filter: blur(8px) saturate(140%);
border: 1px solid rgba(245,241,232,0.18); border-radius: 50%;
cursor: pointer; padding: 0;
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 4px;
box-shadow: 0 6px 20px rgba(0,0,0,0.35);
transition: background 200ms, transform 200ms;
}
.dw-burger-btn:hover { background: rgba(20,20,20,0.92); }
.dw-burger-btn span {
display: block; width: 20px; height: 1.5px; background: currentColor;
transition: transform 220ms, opacity 220ms;
}
.dw-burger-btn[aria-expanded="true"] span:nth-child(1) {
transform: translateY(5.5px) rotate(45deg);
}
.dw-burger-btn[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.dw-burger-btn[aria-expanded="true"] span:nth-child(3) {
transform: translateY(-5.5px) rotate(-45deg);
}
.dw-burger-panel {
position: fixed; top: 72px; right: 18px; z-index: 9998;
min-width: 240px; max-width: 88vw;
background: rgba(15,15,15,0.96);
backdrop-filter: blur(14px) saturate(140%);
-webkit-backdrop-filter: blur(14px) saturate(140%);
border: 1px solid rgba(245,241,232,0.12);
border-radius: 14px;
box-shadow: 0 18px 50px rgba(0,0,0,0.55);
padding: 10px 0;
display: none;
font-family: -apple-system, "SF Pro Text", system-ui, sans-serif;
}
.dw-burger-panel.open { display: block; }
.dw-burger-panel a,
.dw-burger-panel button {
display: block; width: 100%;
padding: 13px 22px;
color: #f5f1e8 !important;
background: transparent; border: 0; cursor: pointer;
text-decoration: none !important;
font-size: 15px; font-weight: 400;
text-align: left;
letter-spacing: 0;
border-bottom: 1px solid rgba(245,241,232,0.06);
transition: background 160ms, color 160ms;
box-sizing: border-box;
}
.dw-burger-panel a:last-child,
.dw-burger-panel button:last-child { border-bottom: 0; }
.dw-burger-panel a:hover,
.dw-burger-panel button:hover {
background: rgba(245,241,232,0.06);
color: #ffffff !important;
}
@media (max-width: 480px) {
.dw-burger-btn { top: 12px; right: 12px; width: 40px; height: 40px; }
.dw-burger-panel { top: 62px; right: 12px; }
}
/* Avoid double-print on sites already adopting a top-of-page header
that overlaps z-index. Reserve safe space near top-right. */
</style>
<button type="button" class="dw-burger-btn" id="dwBurgerBtn"
aria-label="Toggle menu" aria-controls="dwBurgerPanel"
aria-expanded="false">
<span></span><span></span><span></span>
</button>
<nav class="dw-burger-panel" id="dwBurgerPanel" aria-label="Primary">
<a href="/">Home</a>
<a href="/about">About</a>
<a href="mailto:info@designtradelive.com">Contact</a>
</nav>
<script>
(function(){
var btn = document.getElementById('dwBurgerBtn');
var panel = document.getElementById('dwBurgerPanel');
if (!btn || !panel) return;
function close(){ panel.classList.remove('open'); btn.setAttribute('aria-expanded','false'); }
function toggle(){
var open = panel.classList.toggle('open');
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
}
btn.addEventListener('click', function(e){ e.stopPropagation(); toggle(); });
document.addEventListener('click', function(e){
if (panel.classList.contains('open') && !panel.contains(e.target) && e.target !== btn) close();
});
document.addEventListener('keydown', function(e){ if (e.key === 'Escape') close(); });
})();
</script>
<!-- /DW-HAMBURGER-NAV v1 -->
</body>
</html>