// Showcase: section headers, game cards grid, product grid, mystery packs, events, vault feed
const { useState: useSt, useEffect: useEf } = React;
function SectionHead({ eyebrow, title, italicWord, unified, desc, link }) {
return (
);
}
function GameCardGrid() {
const cards = [
{ cls: 'mtg', Sigil: window.SigilMagic, tag: '5,400+ Singles', title: 'Magic: The Gathering', desc: 'Standard, Pioneer, Modern, Commander — and every set back to Alpha.', stats: [['All','Formats'],['Daily','Restocks']] },
{ cls: 'poke', Sigil: window.SigilPokemon, tag: '3,800+ Singles', title: 'Pokémon TCG', desc: 'From base set Charizard to the latest Scarlet & Violet pulls.', stats: [['S&V','Current format'],['Vintage','In stock']] },
{ cls: 'rift', Sigil: window.SigilRiftbound, tag: '1,200+ Singles', title: 'Riftbound', desc: 'The rising star in TCG. Get in early — we stock every set on day one.', stats: [['Day 1','Releases'],['Free','Starter w/ entry']] },
{ cls: 'onepiece', Sigil: window.SigilOnePiece, tag: '2,100+ Singles', title: 'One Piece TCG', desc: 'All Ops, all leaders, every alt-art. Build your dream crew.', stats: [['OP1-9','All sets'],['Weekly','Tournaments']] },
];
return (
);
}
function ProductCard({ p, onAdd }) {
const game = window.WW_DATA.games[p.game];
const [src, setSrc] = useSt(null);
const SigilFallback = ({
mtg: window.SigilMagic,
poke: window.SigilPokemon,
rift: window.SigilRiftbound,
op: window.SigilOnePiece,
})[p.game];
useEf(() => {
let cancelled = false;
// — Magic via Scryfall
if (p.scryfall) {
const q = `https://api.scryfall.com/cards/named?exact=${encodeURIComponent(p.scryfall.name)}${p.scryfall.set ? '&set=' + p.scryfall.set : ''}`;
fetch(q).then(r => r.ok ? r.json() : Promise.reject())
.then(card => {
if (cancelled) return;
const url = (card.image_uris && card.image_uris.normal) ||
(card.card_faces && card.card_faces[0].image_uris && card.card_faces[0].image_uris.normal);
if (url) setSrc(url);
}).catch(() => {});
}
// — Pokémon via pokemontcg.io direct CDN (instant; falls back to API)
else if (p.pokemon) {
const [setId, num] = p.pokemon.id.split('-');
const direct = `https://images.pokemontcg.io/${setId}/${num}_hires.png`;
const img = new Image();
img.onload = () => !cancelled && setSrc(direct);
img.onerror = () => {};
img.src = direct;
}
// — One Piece via weserv-proxied Bandai EN cardlist
else if (p.onepiece) {
const id = p.onepiece.id;
const sources = [
`https://images.weserv.nl/?url=en.onepiece-cardgame.com/images/cardlist/card/${id}.png`,
`https://images.weserv.nl/?url=en.onepiece-cardgame.com/images/cardlist/card/${id}_p1.png`,
`https://en.onepiece-cardgame.com/images/cardlist/card/${id}.png`,
];
let i = 0;
const tryNext = () => {
if (cancelled || i >= sources.length) return;
const probe = new Image();
probe.onload = () => !cancelled && setSrc(sources[i]);
probe.onerror = () => { i++; tryNext(); };
probe.src = sources[i];
};
tryNext();
}
return () => { cancelled = true; };
}, [p.id]);
return (
{p.badges.includes('hot') && Hot }
{p.badges.includes('new') && New }
{p.badges.includes('rare') && Rare }
{p.badges.includes('sale') && Sale }
{p.badges.includes('foil') && Foil }
{/* Sigil fallback — always rendered; image overlays on load */}
{SigilFallback ? : null}
{src &&
}
onAdd(p)}>
{game.label}
{p.name}
{p.set}
{p.was && ${p.was.toFixed(2)} }
${p.price.toFixed(2)}
{p.stock}
);
}
function TrendingSection({ onAdd }) {
const [filter, setFilter] = useSt('all');
const list = filter === 'all' ? window.WW_DATA.products : window.WW_DATA.products.filter(p => p.game === filter);
const tabs = [
['all', '✦ Trending'],
['mtg', '⚔️ Magic'],
['poke','⚡ Pokémon'],
['rift','🌊 Riftbound'],
['op', '☠️ One Piece'],
];
return (
{tabs.map(([k, l]) => (
setFilter(k)}>{l}
))}
);
}
// ── MYSTERY PACKS — preview/cards-mystery.html port ─────────────────
// Tier ladder strip on top, rich art-deco card grid with arcane circles,
// constellations, spacedust, smoke wisps, gilded corners + crest.
const MYSTERY_TIER_CLS = {
common: 't-common',
uncommon: 't-uncommon',
rare: 't-rare',
'very-rare': 't-very-rare',
legendary: 't-legendary',
};
const MYSTERY_TIER_CONFIG = {
common: { wisps: 2, density: 22, bright: 3, circle: 'small', constellation: 'triangle' },
uncommon: { wisps: 2, density: 28, bright: 4, circle: 'small', constellation: 'triangle' },
rare: { wisps: 3, density: 34, bright: 6, circle: 'medium', constellation: 'pentagram' },
'very-rare': { wisps: 3, density: 44, bright: 10, circle: 'medium', constellation: 'pentagram' },
legendary: { wisps: 4, density: 55, bright: 14, circle: 'large', constellation: 'heptagram' },
};
function MysteryCard({ pack, onOpen }) {
const game = window.WW_DATA.games[pack.game];
const tierCls = MYSTERY_TIER_CLS[pack.tier] || '';
const cfg = MYSTERY_TIER_CONFIG[pack.tier] || MYSTERY_TIER_CONFIG.common;
return (
{pack.tierLabel}
{game.label.toUpperCase()}
{pack.name}
{pack.sub} · min ${pack.min}
Conjure
${pack.price.toFixed(2)}
onOpen(pack)}>Unseal
);
}
function TierLadder() {
const rungs = [
['t-common', 'Common', '$4.99'],
['t-uncommon', 'Uncommon', '$9.99'],
['t-rare', 'Rare', '$24.99'],
['t-very-rare', 'Very Rare', '$49.99'],
['t-legendary', 'Legendary', '$99.99'],
];
return (
{rungs.map(([cls, name, price]) => (
{name}
{price}
))}
);
}
function MysterySection({ onOpen }) {
const rootRef = useEf ? React.useRef(null) : null;
React.useEffect(() => {
const root = rootRef && rootRef.current;
if (!root) return;
// Art-deco corner + crest SVGs
const cornerSvg = (cls) => `
`;
const crestSvg = `
`;
root.querySelectorAll('.mystery .gilded-corners').forEach(el => {
el.innerHTML = cornerSvg('tl') + cornerSvg('tr') + cornerSvg('bl') + cornerSvg('br');
});
root.querySelectorAll('.mystery .gilded-crest').forEach(el => {
el.innerHTML = crestSvg;
});
// Spacedust particle clouds
root.querySelectorAll('.mystery .spacedust').forEach(box => {
const card = box.closest('.mystery');
if (!card) return;
const cs = getComputedStyle(card);
const tierBright = cs.getPropertyValue('--tier-bright').trim();
const total = parseInt(box.dataset.density || '24', 10);
const bright = parseInt(box.dataset.bright || '4', 10);
const frag = document.createDocumentFragment();
for (let i = 0; i < total; i++) {
const p = document.createElement('div');
p.className = 'p';
const r = Math.pow(Math.random(), 0.55) * 38;
const a = Math.random() * Math.PI * 2;
const sz = Math.random() * 1.4 + 0.4;
p.style.left = (50 + Math.cos(a) * r) + '%';
p.style.top = (50 + Math.sin(a) * r) + '%';
p.style.width = sz + 'px';
p.style.height = sz + 'px';
p.style.background = i < bright ? tierBright : 'white';
p.style.color = tierBright;
if (i < bright) p.classList.add('bright');
p.style.setProperty('--dur', (1.6 + Math.random() * 4) + 's');
p.style.setProperty('--delay', (Math.random() * 4) + 's');
p.style.setProperty('--min', (Math.random() * 0.1 + 0.05).toFixed(2));
p.style.setProperty('--max', (Math.random() * 0.4 + 0.6).toFixed(2));
frag.appendChild(p);
}
box.appendChild(frag);
});
// Smoke wisps rising from base
root.querySelectorAll('.mystery .smoke').forEach(s => {
const n = parseInt(s.dataset.wisps || '3', 10);
const frag = document.createDocumentFragment();
for (let i = 0; i < n; i++) {
const w = document.createElement('div');
w.className = 'w';
w.style.left = (30 + Math.random() * 40) + '%';
w.style.setProperty('--drift', (Math.random() * 20 - 10) + '%');
w.style.setProperty('--dur', (6 + Math.random() * 4) + 's');
w.style.setProperty('--delay', (Math.random() * 6) + 's');
const sz = 60 + Math.random() * 60;
w.style.width = sz + 'px';
w.style.height = sz + 'px';
frag.appendChild(w);
}
s.appendChild(frag);
});
// Arcane summoning circle
const SVGNS = 'http://www.w3.org/2000/svg';
root.querySelectorAll('.mystery .arcane-circle').forEach(box => {
const svg = document.createElementNS(SVGNS, 'svg');
svg.setAttribute('viewBox', '0 0 100 100');
const ring = document.createElementNS(SVGNS, 'circle');
ring.setAttribute('cx', '50'); ring.setAttribute('cy', '50'); ring.setAttribute('r', '46');
ring.setAttribute('stroke-dasharray', '1.6 3');
svg.appendChild(ring);
const ring2 = document.createElementNS(SVGNS, 'circle');
ring2.setAttribute('cx', '50'); ring2.setAttribute('cy', '50'); ring2.setAttribute('r', '40');
ring2.setAttribute('stroke-opacity', '0.4');
svg.appendChild(ring2);
for (let i = 0; i < 12; i++) {
const angle = (i * 30) * Math.PI / 180;
const x1 = 50 + Math.cos(angle) * 42;
const y1 = 50 + Math.sin(angle) * 42;
const x2 = 50 + Math.cos(angle) * 46;
const y2 = 50 + Math.sin(angle) * 46;
const tick = document.createElementNS(SVGNS, 'line');
tick.setAttribute('x1', x1); tick.setAttribute('y1', y1);
tick.setAttribute('x2', x2); tick.setAttribute('y2', y2);
svg.appendChild(tick);
}
const glyphs = [['M',50,8],['☆',92,50],['M',50,92],['☆',8,50]];
glyphs.forEach(([ch,x,y]) => {
const t = document.createElementNS(SVGNS, 'text');
t.setAttribute('class', 'glyph');
t.setAttribute('x', x); t.setAttribute('y', y + 2.5);
t.setAttribute('text-anchor', 'middle');
t.textContent = ch;
svg.appendChild(t);
});
[[28,28],[72,28],[28,72],[72,72]].forEach(([x,y]) => {
const c = document.createElementNS(SVGNS, 'circle');
c.setAttribute('class', 'dot');
c.setAttribute('cx', x); c.setAttribute('cy', y); c.setAttribute('r', '0.8');
svg.appendChild(c);
});
box.appendChild(svg);
});
// Constellations inside the orb
const constellations = {
triangle: [[50,18],[18,72],[82,72]],
pentagram: [[50,12],[78,80],[10,42],[90,42],[22,80]],
heptagram: [[50,8],[88,32],[78,82],[22,82],[12,32],[68,90],[32,90]],
};
root.querySelectorAll('.mystery .constellation').forEach(box => {
const pattern = box.dataset.pattern || 'triangle';
const pts = constellations[pattern] || constellations.triangle;
const svg = document.createElementNS(SVGNS, 'svg');
svg.setAttribute('viewBox', '0 0 100 100');
const path = document.createElementNS(SVGNS, 'path');
let d = `M ${pts[0][0]} ${pts[0][1]} `;
for (let i = 1; i < pts.length; i++) d += `L ${pts[i][0]} ${pts[i][1]} `;
d += 'Z';
path.setAttribute('d', d);
path.setAttribute('stroke-opacity', '0.8');
svg.appendChild(path);
pts.forEach(([x,y]) => {
const c = document.createElementNS(SVGNS, 'circle');
c.setAttribute('cx', x); c.setAttribute('cy', y); c.setAttribute('r', '1.4');
svg.appendChild(c);
});
box.appendChild(svg);
});
}, []);
return (
{window.WW_DATA.mysteryPacks.map(pack => (
))}
✦ Every pack guarantees a hit. Declared minimum values are real — if your pack falls short, we'll make it right. Cards inspected, sleeved, and shipped with care.
);
}
function VaultFeed() {
const [items, setItems] = useSt(() => window.WW_DATA.vaultEvents.slice(0, 5).map((e, i) => ({ ...e, id: i, t: 'just now' })));
useEf(() => {
const id = setInterval(() => {
setItems(prev => {
const next = window.WW_DATA.vaultEvents[Math.floor(Math.random() * window.WW_DATA.vaultEvents.length)];
return [{ ...next, id: Date.now(), t: 'just now' }, ...prev.slice(0, 4).map(it => ({ ...it, t: typeof it.t === 'string' && it.t === 'just now' ? '12s' : it.t }))];
});
}, 4200);
return () => clearInterval(id);
}, []);
return (
Live From the Vault
Real cards. Real pulls. right now.
Watch the vault breathe in real-time. Every sale, every new listing, every trade — pulled live from our inventory feed.
{items.map(it => (
{it.who.slice(0,2).toUpperCase()}
{it.who} {it.action} {it.product}
{it.t}
))}
);
}
function BuylistBanner({ onClick }) {
return (
Buylist Open Now
Turn your collection into store credit or cash.
We pay top dollar for singles, bulk, sealed product, and entire collections. Get an instant quote online — or bring 'em into the shop. Yes, we want that binder.
✦ Instant online quotes
✦ 30% bonus in store credit
✦ Free shipping label
{ e.preventDefault(); onClick(); }}>✦ Get a Quote
);
}
function EventsSection() {
return (
{window.WW_DATA.events.map((ev, i) => (
))}
);
}
function Newsletter() {
const [email, setEmail] = useSt('');
const [done, setDone] = useSt(false);
return (
Join the Inner Circle
First access to new singles, restocks, tournament announcements, and members-only deals.
Early restocks
Event alerts
Member deals
No spam — ever
);
}
Object.assign(window, { SectionHead, GameCardGrid, ProductCard, TrendingSection, MysteryCard, MysterySection, VaultFeed, BuylistBanner, EventsSection, Newsletter });