// Agora shared components: nav, footer, product tile, route line, badges.
const { useState, useEffect, useRef, useMemo } = React;
// ---------- ICONS (Lucide-style, inline SVG, 1.5 stroke) ----------
const Icon = ({ name, size = 18, stroke = 1.5, ...rest }) => {
const props = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round', ...rest };
switch (name) {
case 'search': return ;
case 'heart': return ;
case 'heart-fill': return ;
case 'bag': return ;
case 'user': return ;
case 'globe': return ;
case 'chevron-down': return ;
case 'chevron-left': return ;
case 'chevron-right': return ;
case 'arrow-right': return ;
case 'plus': return ;
case 'minus': return ;
case 'x': return ;
case 'check': return ;
case 'filter': return ;
case 'sliders': return ;
case 'shield': return ;
case 'sparkles': return ;
case 'plane': return ;
case 'gavel': return ;
case 'box': return ;
case 'tag': return ;
case 'star': return ;
case 'star-fill': return ;
case 'eye': return ;
case 'clock': return ;
case 'map-pin': return ;
case 'truck': return ;
case 'menu': return ;
case 'grid': return ;
case 'list': return ;
case 'external': return ;
case 'send': return ;
case 'message': return ;
case 'edit': return ;
case 'trash': return ;
case 'cards': return ;
case 'spark': return ;
case 'circle-check': return ;
case 'pause': return ;
case 'arrow-up-right': return ;
default: return null;
}
};
// ---------- LUXURY PRODUCT TILE (CSS placeholder w/ subtle gradient + hardware glint) ----------
const ProductTile = ({ item, square = false, showWatermark = true, children, style }) => {
const p = item?.palette || { a: '#E8E4DD', b: '#BDB7AC', hw: '#9A9590', label: '—' };
// Subtle vignette + radial highlight + hardware metallic dot
const bg = {
backgroundColor: p.b,
backgroundImage: [
`radial-gradient(ellipse at 30% 25%, ${p.a} 0%, ${p.a} 18%, transparent 55%)`,
`radial-gradient(ellipse at 70% 80%, ${p.b} 10%, transparent 70%)`,
`linear-gradient(135deg, ${p.a} 0%, ${p.b} 100%)`,
].join(', '),
};
return (
{/* Hardware glint */}
{/* Stitching arc — purely suggestive */}
{showWatermark && item?.brand && (
{item.brand.split(' ')[0].toLowerCase()}
)}
{children}
);
};
// ---------- PRODUCT CARD (catalog grid) ----------
const ProductCard = ({ item, onClick, dense = false }) => {
const [hover, setHover] = useState(false);
const [liked, setLiked] = useState(false);
return (
setHover(true)} onMouseLeave={()=>setHover(false)}
onClick={onClick}
style={{ cursor:'pointer', borderRadius: 0, border:0, borderTop:'1px solid var(--ap-border)' }}
>
{item.new && New}
{item.acceptOffers && Offers}
{ e.stopPropagation(); setLiked(!liked); }}
title={liked ? 'Saved' : 'Save'}
>
Auth
{item.city}
{item.brand}
€{item.eur.toLocaleString()}
{item.title}
{item.cond}
);
};
// ---------- ROUTE LINE (Tokyo → Berlin) ----------
const RouteLine = ({ from, to = 'Berlin', compact = false }) => (
{from}
→
{to}
);
// ---------- AGORA WORDMARK ----------
const Wordmark = ({ size = 22, compact = false }) => (
{/* Brand mark — circle with serif "a" */}
a
{!compact && (
agora
)}
);
// ---------- TOP NAV ----------
const TopNav = ({ route, setRoute, onSearch, watchlistCount = 0, cartCount = 0 }) => {
const [searchOpen, setSearchOpen] = useState(false);
const isActive = (r) => route?.name === r;
return (
<>
{/* Thin promo strip — quiet trust promises, Apple-style */}
{/* LEFT: wordmark + search */}
setRoute({ name:'home' })} style={{ cursor:'pointer' }}>
{/* CENTER: categories */}
{/* RIGHT: utility icons */}
setRoute({ name:'watchlist' })} style={{ cursor:'pointer', position:'relative' }}>
{watchlistCount > 0 && {watchlistCount}}
LK
{/* Sub-nav: categories — clean, centered, just categories */}
{window.AG_DATA.categories.map(c => (
setRoute({ name:'browse', cat: c.id })}
style={{ cursor:'pointer', fontSize: 10, color: route?.name==='browse' && route?.cat===c.id ? 'var(--ag-ink)':'var(--ap-fg-muted)' }}>
{c.label}
))}
{searchOpen && setSearchOpen(false)} setRoute={(r)=>{ setRoute(r); setSearchOpen(false); }}/>}
>
);
};
// ---------- PROMO STRIP (above main nav) ----------
const PROMO_MESSAGES = [
{ icon: 'shield', text: 'Every piece authenticated at one of three hubs. Free, always.' },
{ icon: 'truck', text: 'DDP shipping included — customs & duties pre-cleared to your door.' },
{ icon: 'box', text: '14-day returns from delivery. Buyer protection on every transaction.' },
{ icon: 'globe', text: '1,284 sellers across Tokyo, Paris, Milan, Seoul, New York & more.' },
];
const PromoStrip = () => {
const [idx, setIdx] = useState(0);
useEffect(() => {
const t = setInterval(() => setIdx(i => (i + 1) % PROMO_MESSAGES.length), 5000);
return () => clearInterval(t);
}, []);
return (
{PROMO_MESSAGES.map((m, i) => (
))}
{PROMO_MESSAGES.map((_, i) => (
))}
);
};
// ---------- COMMAND PALETTE (Cmd+K search-led nav) ----------
const CommandPalette = ({ onClose, setRoute }) => {
const [q, setQ] = useState('');
const inputRef = useRef();
useEffect(()=>{ inputRef.current?.focus(); const esc = (e)=>{ if (e.key==='Escape') onClose(); }; window.addEventListener('keydown', esc); return ()=>window.removeEventListener('keydown', esc); }, []);
const data = window.AG_DATA;
const ql = q.toLowerCase();
const items = data.items.filter(it => !q || it.brand.toLowerCase().includes(ql) || it.title.toLowerCase().includes(ql)).slice(0, 8);
const brands = data.brands.filter(b => !q || b.toLowerCase().includes(ql)).slice(0, 6);
return (
e.stopPropagation()} style={{ width: 720, background:'#fff', borderRadius: 4, boxShadow:'var(--ap-shadow-modal)', overflow:'hidden' }} className="ag-fade-in">
setQ(e.target.value)} placeholder="Search brands, items, sellers…" style={{ flex:1, border:0, outline:'none', fontSize: 16, fontFamily:'var(--ag-font-sans)' }}/>
Esc
Items
{items.map(it => (
setRoute({ name:'product', id: it.id })} className="ag-flex ag-gap-3"
style={{ padding:'10px 22px', cursor:'pointer', alignItems:'center' }}
onMouseEnter={(e)=>e.currentTarget.style.background='var(--ap-bg-2)'} onMouseLeave={(e)=>e.currentTarget.style.background='transparent'}>
€{it.eur.toLocaleString()}
))}
Brands
{brands.map(b => setRoute({ name:'browse', cat:'all', brand: b })}>{b})}
);
};
// ---------- FOOTER ----------
const Footer = ({ setRoute }) => (
);
// ---------- EXPORTS ----------
Object.assign(window, { Icon, ProductTile, ProductCard, RouteLine, Wordmark, TopNav, Footer, CommandPalette });