// Executables — Cyberpunk product shop
// Main app
const { useState, useEffect, useMemo, useRef, useCallback } = React;
// ---------- TWEAKABLE DEFAULTS ----------
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accentPrimary": "#00ffd1",
"accentSecondary": "#ff2bd6",
"bgBase": "#0a0a0f",
"scanlines": true,
"glitchHero": true,
"cardDensity": "comfy",
"gridCols": 3,
"showSpotlight": true,
"monoEverything": false,
"noiseTexture": true,
"cornerCuts": true
}/*EDITMODE-END*/;
// ---------- HELPERS ----------
const cls = (...a) => a.filter(Boolean).join(' ');
const fmt = (n) => '$' + Number(n).toFixed(2);
// Pricing helpers — month is the headline price everywhere outside the modal.
const priceFor = (p, tier = 'month') => (p.pricing ? p.pricing[tier] : p.price);
const headlinePrice = (p) => priceFor(p, 'month');
// Image helpers — real screenshots in product.images take priority over
// procedural filler SVGs. Card/spotlight/cart all use the first image;
// the modal gallery uses the full array.
const productCover = (p) =>
(p && p.images && p.images.length > 0)
? p.images[0]
: (window.fillerSrc ? window.fillerSrc(p) : '');
const productGallery = (p, n = 3) =>
(p && p.images && p.images.length > 0)
? p.images
: (window.fillerGallery ? window.fillerGallery(p, n) : []);
// Category label lookup — internal ids (cod, eft, apex, rust, pubg) match
// their display labels uppercase-for-lowercase, but routing through
// EXEC_CATEGORIES keeps any future rename in one place.
const categoryLabel = (id) => {
const cats = window.EXEC_CATEGORIES || [];
const c = cats.find((x) => x.id === id);
return c ? c.label : (id || '').toUpperCase();
};
// Product state — single source of truth. window.ExecStates fetches the
// canonical map from /api/site/product-states once and re-emits when admin
// writes a new value. Components that display a status pill call
// useProductStates() so they re-render on change; one-off readers can use
// productState() directly. Default for any product without a row: 'updating'.
const STATE_LABEL = { online: 'ONLINE', offline: 'OFFLINE', updating: 'UPDATING' };
const productState = (p) =>
(window.ExecStates ? window.ExecStates.get(p.id) : { state: 'updating', note: '' });
const useProductStates = () =>
(window.ExecStates ? window.ExecStates.useStates() : { ready: false });
// Admin shortcuts (re-bound below so this file is order-independent).
const E = (props) => React.createElement(window.EditableText, props);
const Add = (props) => React.createElement(window.AdminAddButton, props);
const Ctl = (props) => React.createElement(window.AdminItemControls, props);
// ---------- ICONS (line, mono) ----------
const Icon = {
Search: () => ,
Cart: () => ,
Plus: () => ,
Minus: () => ,
X: () => ,
Chevron: () => ,
Check: () => ,
Arrow: () => ,
Lock: () => ,
Hash: () => ,
Github: () => ,
Telegram: () => ,
Discord: () => ,
};
// ---------- TERMINAL FRAME / CHROME ----------
function CornerCuts({ size = 10, color }) {
return (
<>
>
);
}
// ---------- HERO ----------
function Hero({ tweaks, onJump, hero, setHero, editing, products }) {
const productStates = useProductStates();
const [bootLines, setBootLines] = useState([]);
const onlineCount = window.ExecStates
? window.ExecStates.counts(products || []).online
: 0;
const fullBoot = [
'> auth_handshake .................. [OK]',
'> mirror://exe.executables.sh ..... [SYNCED]',
'> license_vault ................... [READY]',
`> ${onlineCount} executable${onlineCount === 1 ? '' : 's'} online`,
];
useEffect(() => {
setBootLines([]);
let i = 0;
const t = setInterval(() => {
setBootLines((p) => [...p, fullBoot[i]]);
i++;
if (i >= fullBoot.length) clearInterval(t);
}, 280);
return () => clearInterval(t);
}, [onlineCount, productStates.ready]);
return (
NODE//A7-EAST · LIVE
/
BUILD 26.05.14
setHero({ ...hero, title: v.toUpperCase() })}
editing={editing}
as="span"
maxLength={14}
/>
setHero({ ...hero, sub_a: v })} editing={editing} as="span"/>
setHero({ ...hero, sub_b: v })} editing={editing} as="span"/>
onJump('catalog')}>
BROWSE CATALOG
onJump('faq')}>
READ FAQ
{bootLines.map((l, i) => (
{l}
))}
▌
);
}
// ---------- SPOTLIGHT (cycles through all products) ----------
const SPOTLIGHT_INTERVAL = 4200; // ms per product
function shuffle(arr) {
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function Spotlight({ products, onOpen, onAdd, isInCart }) {
useProductStates();
const orderRef = useRef(null);
if (!orderRef.current) orderRef.current = shuffle(products.map((p) => p.id)).slice(0, 5);
const order = orderRef.current;
const touchRef = useRef({ x: 0, y: 0, swiping: false });
const tiers = window.EXEC_TIERS || [];
const [idx, setIdx] = useState(0);
const [tier, setTier] = useState('month');
const [paused, setPaused] = useState(false);
const [progress, setProgress] = useState(0); // 0..1
// advance + progress ticker
useEffect(() => {
if (paused) return;
setProgress(0);
const started = performance.now();
const tick = () => {
const elapsed = performance.now() - started;
const p = Math.min(1, elapsed / SPOTLIGHT_INTERVAL);
setProgress(p);
if (p < 1) raf = requestAnimationFrame(tick);
else setIdx((i) => (i + 1) % order.length);
};
let raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [idx, paused, order.length]);
const product = products.find((p) => p.id === order[idx]);
if (!product) return null;
const inCart = isInCart(product.id, tier);
const filler = productCover(product);
const next = () => setIdx((i) => (i + 1) % order.length);
const prev = () => setIdx((i) => (i - 1 + order.length) % order.length);
return (
setPaused(true)}
onMouseLeave={() => setPaused(false)}
onTouchStart={(e) => {
setPaused(true);
const t = e.touches[0];
touchRef.current = { x: t.clientX, y: t.clientY, swiping: false };
}}
onTouchMove={(e) => {
const t = e.touches[0];
const dx = t.clientX - touchRef.current.x;
const dy = t.clientY - touchRef.current.y;
if (Math.abs(dx) > 12 && Math.abs(dx) > Math.abs(dy)) touchRef.current.swiping = true;
}}
onTouchEnd={(e) => {
const swiping = touchRef.current.swiping;
const dx = e.changedTouches[0].clientX - touchRef.current.x;
touchRef.current.swiping = false;
setPaused(false);
if (!swiping || order.length < 2 || Math.abs(dx) < 45) return;
if (dx < 0) next(); else prev();
}}
onTouchCancel={() => {
touchRef.current.swiping = false;
setPaused(false);
}}
>
FEATURED
{String(idx + 1).padStart(2, '0')}/{String(order.length).padStart(2, '0')}
{product.tag} {categoryLabel(product.category)}
{product.name}
{product.blurb}
{tiers.map((t) => (
setTier(t.id)}
aria-pressed={tier === t.id}
>
{t.label}
{fmt(priceFor(product, t.id))}
{t.suffix}
))}
onAdd(product, tier)}
disabled={inCart}
>
{inCart ? 'IN CART' : 'ADD TO CART'}
onOpen(product.id)}>
DETAILS
{/* controls */}
←
{order.map((id, i) => (
setIdx(i)}
aria-label={`Show ${id}`}
/>
))}
→
);
}
// ---------- CATEGORY TABS + SEARCH ----------
function Filters({ category, setCategory, query, setQuery, count, categories }) {
const cats = categories || window.EXEC_CATEGORIES;
return (
{cats.map((c) => (
setCategory(c.id)}
>
{c.label}
{c.count}
))}
);
}
// ---------- PRODUCT CARD ----------
function ProductCard({ product, onOpen, onAdd, inCart, editing, onChange, onDelete }) {
useProductStates();
const stop = (e) => { if (editing) { e.preventDefault(); e.stopPropagation(); } };
return (
{editing && }
editing ? stop(e) : onOpen()}>
onChange({ ...product, tag: v })} editing={editing} as="span"/>
{STATE_LABEL[productState(product).state]}
onChange({ ...product, name: v.toUpperCase() })} editing={editing} as="span"/>
onChange({ ...product, blurb: v })} editing={editing} as="span" multiline/>
{editing ? (
<>$ {
const n = Math.max(0, parseInt(v.replace(/[^\d]/g,''), 10) || 0);
onChange({ ...product, pricing: { ...product.pricing, month: n }});
}}
editing={editing}
as="span"
/>>
) : (
fmt(headlinePrice(product))
)}
/mo
/{categoryLabel(product.category)}
{editing ? 'CLICK TEXT TO EDIT' : 'VIEW DETAILS'}
);
}
// ---------- LIGHTBOX (full-size image viewer over the product modal) ----------
const LbCloseIcon = () => (
);
const LbArrow = ({ dir }) => (
{dir === 'left'
?
: }
);
function Lightbox({ images, index, onClose, onPrev, onNext }) {
// Capture keys before ProductModal's listener sees them, so Esc closes
// the lightbox first (not the modal) and arrow keys page within it.
useEffect(() => {
const onKey = (e) => {
if (e.key === 'Escape') { e.stopPropagation(); onClose(); }
if (e.key === 'ArrowLeft') { e.stopPropagation(); onPrev(); }
if (e.key === 'ArrowRight') { e.stopPropagation(); onNext(); }
};
document.addEventListener('keydown', onKey, true);
return () => document.removeEventListener('keydown', onKey, true);
}, [onClose, onPrev, onNext]);
// Every interactive click must stop propagation — the lightbox lives
// inside the ProductModal's .pm-scrim, which has its own click-to-close
// listener that would otherwise close the underlying modal too.
const stopAnd = (fn) => (e) => { e.stopPropagation(); fn(); };
return (
e.stopPropagation()}
/>
{images.length > 1 && (
<>
{String(index + 1).padStart(2, '0')}
/
{String(images.length).padStart(2, '0')}
>
)}
);
}
// ---------- PRODUCT MODAL (frosted glass detail panel) ----------
function ProductModal({ product, onClose, onAdd, isInCart, onViewCart, editing, onChange }) {
useProductStates();
const [tier, setTier] = useState('month');
const [imgIdx, setImgIdx] = useState(0);
const [lightboxIdx, setLightboxIdx] = useState(null); // null when closed
const [featuresExpanded, setFeaturesExpanded] = useState(() => window.innerWidth > 720);
const touchRef = useRef({ x: 0, y: 0, swiping: false });
// Reset gallery + tier + lightbox whenever the product changes.
useEffect(() => {
setTier('month');
setImgIdx(0);
setLightboxIdx(null);
setFeaturesExpanded(window.innerWidth > 720);
}, [product?.id]);
// Trap escape + lock body scroll while open. When the lightbox is open
// it owns the keyboard via a capture-phase listener, so this handler
// never runs in that state — keeping prev/next + Esc from double-firing.
useEffect(() => {
if (!product) return;
const onKey = (e) => {
if (e.key === 'Escape') onClose();
if (e.key === 'ArrowLeft') setImgIdx((i) => (i - 1 + gallery.length) % gallery.length);
if (e.key === 'ArrowRight') setImgIdx((i) => (i + 1) % gallery.length);
};
document.addEventListener('keydown', onKey);
const scrollY = window.scrollY;
const prev = {
overflow: document.body.style.overflow,
position: document.body.style.position,
top: document.body.style.top,
width: document.body.style.width,
};
document.body.style.overflow = 'hidden';
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollY}px`;
document.body.style.width = '100%';
return () => {
document.removeEventListener('keydown', onKey);
document.body.style.overflow = prev.overflow;
document.body.style.position = prev.position;
document.body.style.top = prev.top;
document.body.style.width = prev.width;
window.scrollTo(0, scrollY);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [product, onClose]);
if (!product) return null;
const gallery = productGallery(product, 3);
const tiers = window.EXEC_TIERS || [];
const inCart = isInCart ? isInCart(product.id, tier) : false;
const canEdit = editing && onChange;
const updateFeature = (i, v) => {
const next = product.features.slice();
next[i] = v;
onChange({ ...product, features: next });
};
const addFeature = () => onChange({ ...product, features: [...product.features, 'New feature'] });
const removeFeature = (i) => {
const next = product.features.slice();
next.splice(i, 1);
onChange({ ...product, features: next });
};
return (
e.stopPropagation()} data-screen-label={`modal-${product.id}`}>
{/* header strip */}
{product.tag}
//
{categoryLabel(product.category)}
{STATE_LABEL[productState(product).state]}
{product.version}
{/* LEFT — gallery */}
{
// Don't pop the lightbox when clicking the arrows / meta overlay,
// while admin edit-mode is active (image-slot owns drops then),
// or right after a swipe gesture just changed the image.
if (canEdit) return;
if (e.target.closest('.pm-stage-arrow, .pm-stage-meta')) return;
if (touchRef.current.swiping) { touchRef.current.swiping = false; return; }
setLightboxIdx(imgIdx);
}}
onTouchStart={(e) => {
const t = e.touches[0];
touchRef.current = { x: t.clientX, y: t.clientY, swiping: false };
}}
onTouchMove={(e) => {
const t = e.touches[0];
const dx = t.clientX - touchRef.current.x;
const dy = t.clientY - touchRef.current.y;
if (Math.abs(dx) > 10 && Math.abs(dx) > Math.abs(dy)) touchRef.current.swiping = true;
}}
onTouchEnd={(e) => {
if (!touchRef.current.swiping || gallery.length < 2) return;
const t = e.changedTouches[0];
const dx = t.clientX - touchRef.current.x;
if (Math.abs(dx) < 40) { touchRef.current.swiping = false; return; }
if (dx < 0) setImgIdx((i) => (i + 1) % gallery.length);
else setImgIdx((i) => (i - 1 + gallery.length) % gallery.length);
}}
style={{ cursor: canEdit ? 'default' : 'zoom-in' }}
>
{String(imgIdx + 1).padStart(2, '0')}/{String(gallery.length).padStart(2, '0')}
{gallery.length > 1 && (
<>
setImgIdx((i) => (i - 1 + gallery.length) % gallery.length)}
aria-label="Previous image"
>←
setImgIdx((i) => (i + 1) % gallery.length)}
aria-label="Next image"
>→
>
)}
{gallery.length > 1 && (
{gallery.map((src, i) => (
setImgIdx(i)}
aria-label={`View image ${i + 1}`}
>
0{i + 1}
))}
)}
{/* RIGHT — details */}
canEdit && onChange({ ...product, name: v.toUpperCase() })}
editing={canEdit}
as="span"
/>
canEdit && onChange({ ...product, blurb: v })}
editing={canEdit}
as="span"
multiline
/>
FEATURES
setFeaturesExpanded((expanded) => !expanded)}
>
{featuresExpanded ? 'RETRACT' : 'EXPAND'}
⌄
{product.features.map((f, i) => (
updateFeature(i, v)}
editing={canEdit}
as="span"
/>
{canEdit && (
removeFeature(i)}
title="Remove feature"
>
)}
))}
{canEdit && (
)}
LICENSE · SELECT TIER
{tiers.map((t) => {
const v = priceFor(product, t.id);
const active = tier === t.id;
return (
setTier(t.id)}
>
{t.recommended && BEST }
{t.label}
{canEdit ? (
<>$ {
const n = Math.max(0, parseInt(vv.replace(/[^\d]/g,''), 10) || 0);
onChange({ ...product, pricing: { ...product.pricing, [t.id]: n }});
}}
editing={canEdit}
as="span"
/>>
) : fmt(v)}
{t.suffix}
{t.sub}
);
})}
{fmt(priceFor(product, tier))}
USD {tiers.find((t) => t.id === tier)?.suffix}
{onAdd && (
onAdd(product, tier)}
disabled={inCart}
>
{inCart ? 'IN CART' : 'ADD TO CART'}
)}
{inCart && onViewCart && (
VIEW CART
)}
{lightboxIdx !== null && gallery.length > 0 && (
setLightboxIdx(null)}
onPrev={() => setLightboxIdx((i) => (i - 1 + gallery.length) % gallery.length)}
onNext={() => setLightboxIdx((i) => (i + 1) % gallery.length)}
/>
)}
);
}
// Expose for status.jsx
window.ProductModal = ProductModal;
// ---------- AUTH (Discord login / account pill) ----------
// When logged out → button that kicks the OAuth flow.
// When logged in → link straight to the dedicated /account.html page (the
// in-modal mini-view was replaced with a full page so users can navigate
// order history properly).
function AuthButton({ user }) {
if (!user) {
return (
window.ExecAuth && window.ExecAuth.login()}
title="Log in with Discord"
>
LOG IN
);
}
const name = user.global_name || user.username || 'USER';
return (
{user.avatar_url
?
: {(name[0] || '?').toUpperCase()} }
{name}
);
}
// ---------- CART DRAWER ----------
function Cart({ open, onClose, items, products, onChange, onCheckout, user, pending }) {
const lines = items.map((it) => ({
...it,
product: products.find((p) => p.id === it.id),
})).filter((l) => l.product);
const subtotal = lines.reduce((s, l) => s + priceFor(l.product, l.tier) * l.qty, 0);
const tax = subtotal * 0.08;
const total = subtotal + tax;
return (
<>
{lines.length === 0 ? (
[ ∅ ]
NO EXECUTABLES QUEUED
browse catalog to add
) : lines.map((l) => {
const tierMeta = (window.EXEC_TIERS || []).find((t) => t.id === l.tier) || { suffix: '' };
const unit = priceFor(l.product, l.tier);
return (
{l.product.name}
{l.product.tag} · {l.product.version} · {(l.tier || 'month').toUpperCase()}
onChange(l.id, l.tier, l.qty - 1)}>
{l.qty}
onChange(l.id, l.tier, l.qty + 1)}>
onChange(l.id, l.tier, 0)}>REMOVE
{fmt(unit * l.qty)}
{tierMeta.suffix}
);})}
{lines.length > 0 && (
)}
>
);
}
// ---------- PAYMENT RETURN BANNER ----------
// Shown when the user returns from Stripe with ?paid=ok or ?paid=cancel.
// Auto-dismisses after 8s on success so it doesn't linger.
function PaymentBanner({ kind, onClose }) {
useEffect(() => {
if (kind !== 'ok') return;
const t = setTimeout(onClose, 8000);
return () => clearTimeout(t);
}, [kind, onClose]);
if (kind === 'ok') {
return (
PAYMENT RECEIVED — open your account to see order status & keys
);
}
return (
CHECKOUT CANCELLED — no charge was made
);
}
// ---------- FAQ ----------
function FAQ({ faq, setFaq, editing }) {
const [open, setOpen] = useState(0);
const update = (i, patch) => setFaq(faq.map((f, idx) => idx === i ? { ...f, ...patch } : f));
const remove = (i) => setFaq(faq.filter((_, idx) => idx !== i));
const add = () => {
setFaq([...faq, { q: 'New question?', a: 'New answer — click to edit.' }]);
setOpen(faq.length);
};
return (
{faq.map((f, i) => (
{editing &&
remove(i)}/>}
{
// when editing, clicking the editable text shouldn't toggle
if (editing && e.target.closest('.editable')) return;
setOpen(open === i ? -1 : i);
}}>
0{i + 1}
update(i, { q: v })} editing={editing} as="span"/>
{(open === i || editing) && (
update(i, { a: v })} editing={editing} as="span" multiline/>
)}
))}
{editing && (
)}
);
}
// ---------- FOOTER ----------
function Footer({ footer, setFooter, editing }) {
const EditableUrl = window.EditableUrl;
const socialIcon = {
github: ,
telegram: ,
discord: ,
};
const updateColumn = (ci, patch) => {
setFooter({ ...footer, columns: footer.columns.map((c, i) => i === ci ? { ...c, ...patch } : c) });
};
const updateLink = (ci, li, patch) => {
const cols = footer.columns.map((c, i) => {
if (i !== ci) return c;
return { ...c, links: c.links.map((l, j) => j === li ? { ...l, ...patch } : l) };
});
setFooter({ ...footer, columns: cols });
};
const addLink = (ci) => {
const cols = footer.columns.map((c, i) => i === ci ? { ...c, links: [...c.links, { label: 'New link', url: '#' }] } : c);
setFooter({ ...footer, columns: cols });
};
const removeLink = (ci, li) => {
const cols = footer.columns.map((c, i) => i === ci ? { ...c, links: c.links.filter((_, j) => j !== li) } : c);
setFooter({ ...footer, columns: cols });
};
const updateSocial = (si, patch) => {
setFooter({ ...footer, socials: footer.socials.map((s, i) => i === si ? { ...s, ...patch } : s) });
};
return (
[EXE]CUTABLES
setFooter({ ...footer, tagline: v })} editing={editing} as="span"/>
{footer.socials.map((s, i) => (
editing ? (
updateSocial(i, { label, url })}
editing={editing}
/>
) : (
{socialIcon[s.kind] || }
)
))}
{footer.columns.map((col, ci) => (
updateColumn(ci, { title: v.toUpperCase() })} editing={editing} as="span"/>
{col.links.map((l, li) => (
{editing ? (
updateLink(ci, li, patch)}
editing={editing}
/>
) : (
{l.label}
)}
{editing && (
removeLink(ci, li)}
title="Remove link"
>
)}
))}
{editing && (
addLink(ci)} label="+ LINK"/>
)}
))}
setFooter({ ...footer, copyright: v })} editing={editing} as="span"/>
setFooter({ ...footer, node: v })} editing={editing} as="span"/>
setFooter({ ...footer, build: v })} editing={editing} as="span"/>
);
}
window.Footer = Footer;
// ---------- TWEAKS ----------
function TweaksUI({ tweaks, setTweak }) {
const TweaksPanel = window.TweaksPanel;
const TweakSection = window.TweakSection;
const TweakColor = window.TweakColor;
const TweakToggle = window.TweakToggle;
const TweakRadio = window.TweakRadio;
const TweakSelect = window.TweakSelect;
return (
setTweak('accentPrimary', v)}
/>
setTweak('accentSecondary', v)}
/>
setTweak('bgBase', v)}
/>
setTweak('cardDensity', v)}
/>
setTweak('gridCols', Number(v))}
/>
setTweak('cornerCuts', v)} />
setTweak('showSpotlight', v)} />
setTweak('scanlines', v)} />
setTweak('glitchHero', v)} />
setTweak('noiseTexture', v)} />
setTweak('monoEverything', v)} />
);
}
// ---------- ROOT APP ----------
// Subscribes to window.ExecAuth and re-renders when the logged-in user changes.
// Returns { user, isAdmin } — both null/false until /api/me resolves. Safe if
// auth.js failed to load (returns the resting null/false forever).
function useAuthState() {
const [state, setState] = useState(() => ({
user: window.ExecAuth ? window.ExecAuth.getUser() : null,
isAdmin: window.ExecAuth ? window.ExecAuth.isAdmin() : false,
isMod: window.ExecAuth ? window.ExecAuth.isMod() : false,
}));
useEffect(() => {
if (!window.ExecAuth) return;
return window.ExecAuth.subscribe((user, meta) => setState({
user,
isAdmin: !!(meta && meta.isAdmin),
isMod: !!(meta && (meta.isMod || meta.isAdmin)),
}));
}, []);
return state;
}
function App() {
const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
const [cmsState, setKey] = window.useCMS();
const [editing, setEditing] = window.useEditMode();
const isAdmin = window.CMS.isAdmin();
const { user: authUser } = useAuthState();
const [category, setCategory] = useState('all');
const [query, setQuery] = useState('');
const [openProductId, setOpenProductId] = useState(null);
const [cart, setCart] = useState([]);
const [cartOpen, setCartOpen] = useState(false);
const [navOpen, setNavOpen] = useState(false);
const [scrollMenuVisible, setScrollMenuVisible] = useState(false);
const [scrollMenuOpen, setScrollMenuOpen] = useState(false);
const [checkoutPending, setCheckoutPending] = useState(false);
const [paymentBanner, setPaymentBanner] = useState(null); // 'ok' | 'cancel' | null
// Apply CSS variables from tweaks
useEffect(() => {
const r = document.documentElement;
r.style.setProperty('--accent', tweaks.accentPrimary);
r.style.setProperty('--accent-2', tweaks.accentSecondary);
r.style.setProperty('--bg', tweaks.bgBase);
document.body.classList.toggle('no-scanlines', !tweaks.scanlines);
document.body.classList.toggle('no-noise', !tweaks.noiseTexture);
document.body.classList.toggle('no-cuts', !tweaks.cornerCuts);
document.body.classList.toggle('mono-all', tweaks.monoEverything);
r.style.setProperty('--grid-cols', tweaks.gridCols);
r.style.setProperty('--density', tweaks.cardDensity === 'compact' ? '0.85' : '1');
}, [tweaks]);
// On desktop, replace the full navigation with a compact menu after the
// visitor has scrolled beyond it. Mobile keeps its regular nav behavior.
useEffect(() => {
const syncScrollMenu = () => {
const visible = window.innerWidth > 720 && window.scrollY > 90;
setScrollMenuVisible(visible);
if (!visible) setScrollMenuOpen(false);
};
syncScrollMenu();
window.addEventListener('scroll', syncScrollMenu, { passive: true });
window.addEventListener('resize', syncScrollMenu);
return () => {
window.removeEventListener('scroll', syncScrollMenu);
window.removeEventListener('resize', syncScrollMenu);
};
}, []);
const products = cmsState.products;
const categories = useMemo(() => window.CMS.computeCategories(), [products]);
const filtered = useMemo(() => {
let arr = products;
if (category !== 'all') arr = arr.filter((p) => p.category === category);
if (query.trim()) {
const q = query.trim().toLowerCase();
arr = arr.filter((p) =>
p.name.toLowerCase().includes(q) ||
p.blurb.toLowerCase().includes(q) ||
p.tag.toLowerCase().includes(q)
);
}
return arr;
}, [products, category, query]);
const cartCount = cart.reduce((s, i) => s + i.qty, 0);
const cartTotal = cart.reduce((s, i) => {
const p = products.find((pp) => pp.id === i.id);
return p ? s + priceFor(p, i.tier) * i.qty : s;
}, 0);
const cartTotalTaxed = cartTotal * 1.08;
const inCart = (id, tier) =>
tier ? cart.some((i) => i.id === id && i.tier === tier)
: cart.some((i) => i.id === id);
const addToCart = (p, tier = 'month') => {
if (editing) return; // no shopping while editing
setCart((c) => {
const ex = c.find((i) => i.id === p.id && i.tier === tier);
if (ex) return c.map((i) => i.id === p.id && i.tier === tier ? { ...i, qty: i.qty + 1 } : i);
return [...c, { id: p.id, tier, qty: 1 }];
});
setCartOpen(true);
};
const changeQty = (id, tier, qty) => {
setCart((c) => qty <= 0
? c.filter((i) => !(i.id === id && i.tier === tier))
: c.map((i) => i.id === id && i.tier === tier ? { ...i, qty } : i));
};
const jumpTo = (k) => {
const el = document.querySelector(k === 'catalog' ? '#catalog' : '#faq');
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
// POSTs the cart to the Worker, which creates a Stripe Checkout Session and
// returns its hosted URL. We then hand the browser off — Stripe's page is
// where the user actually pays.
const beginCheckout = async () => {
if (!authUser) { window.ExecAuth && window.ExecAuth.login(); return; }
if (cart.length === 0 || checkoutPending) return;
setCheckoutPending(true);
try {
const res = await fetch('/api/checkout', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
items: cart.map((c) => ({ product_id: c.id, tier: c.tier, qty: c.qty })),
}),
});
const data = await res.json().catch(() => ({}));
if (!res.ok || !data.url) {
alert('Checkout failed: ' + (data.error || res.status));
setCheckoutPending(false);
return;
}
// Clear the cart locally before redirecting — Stripe is the source of
// truth from here on; the order is already stubbed in our DB.
setCart([]);
window.location.href = data.url;
} catch (e) {
alert('Checkout failed: ' + (e && e.message || 'network error'));
setCheckoutPending(false);
}
};
// On page load, surface success/cancel banners from the Stripe redirect,
// then strip the query params so refreshes don't re-show them.
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const paid = params.get('paid');
if (paid === 'ok' || paid === 'cancel') {
setPaymentBanner(paid);
params.delete('paid');
params.delete('sid');
const qs = params.toString();
window.history.replaceState({}, '', window.location.pathname + (qs ? '?' + qs : ''));
}
}, []);
// ---- CMS mutations ----
const updateProduct = (next) => {
setKey('products', products.map((p) => p.id === next.id ? next : p));
};
const deleteProduct = (id) => {
if (!confirm('Delete this product?')) return;
setKey('products', products.filter((p) => p.id !== id));
};
const addProduct = () => {
const p = window.CMS.blankProduct();
setKey('products', [...products, p]);
setOpenProductId(p.id);
};
const setFaq = (faq) => setKey('faq', faq);
const setFooter = (footer) => setKey('footer', footer);
const setHero = (hero) => setKey('hero', hero);
return (
{/* ADMIN BAR */}
{isAdmin && window.AdminBar && (
)}
{/* TOP NAV */}
[EXE] cutables
v26.5
setNavOpen(false)}>CATALOG
setNavOpen(false)}>FAQ
setNavOpen(false)}> STATUS
setNavOpen(false)}>DISCORD
{/* Admin login entry disabled — CMS edits live in the visitor's own localStorage and never reach the server,
so the lock icon was misleading visitors into thinking they could change the public site. login.html and
js/components/admin-controls.jsx are intentionally kept on disk for when a real backend is wired up; to
re-enable, uncomment the line below.
{!isAdmin && }
*/}
setNavOpen(!navOpen)}
>
{navOpen
?
: }
setCartOpen(true)}>
CART
{cartCount > 0 && {cartCount} }
{scrollMenuVisible && (
setScrollMenuOpen((open) => !open)}
>
{scrollMenuOpen ? : }
MENU
)}
{tweaks.showSpotlight && !editing && products.length > 0 && (
setOpenProductId(id)}
onAdd={addToCart}
isInCart={inCart}
/>
)}
// 02
CATALOG / {filtered.length}
SORT BY: NEW · PRICE · NAME
{(() => {
// For single-category views, prepend a decorative banner tile so
// the products visually shift right by one. ALL has no banner
// image and falls through to the normal product grid.
const activeCat = category !== 'all' ? categories.find((c) => c.id === category) : null;
return activeCat && activeCat.image ? (
{/* .category-banner-frame is an inline-block wrapper that shrink-wraps
to the image's rendered size so the hover beam traces the image
edges (not the slot, which letterboxes when ratios don't match). */}
{/* Second img is a difference-blended ghost layer driven by CSS
animations (drift + slice tears) to produce the glitch effect. */}
) : null;
})()}
{filtered.map((p) => (
setOpenProductId(p.id)}
onAdd={addToCart}
inCart={inCart(p.id)}
editing={editing}
onChange={updateProduct}
onDelete={() => deleteProduct(p.id)}
/>
))}
{editing && (
)}
{filtered.length === 0 && !editing && (
[ ∅ ]
NO MATCHES
try a different filter or query
)}
setCartOpen(false)}
items={cart}
products={products}
onChange={changeQty}
user={authUser}
pending={checkoutPending}
onCheckout={() => beginCheckout()}
/>
{paymentBanner && (
setPaymentBanner(null)}/>
)}
p.id === openProductId) || null}
onClose={() => setOpenProductId(null)}
onAdd={addToCart}
isInCart={inCart}
onViewCart={() => setCartOpen(true)}
editing={editing}
onChange={updateProduct}
/>
{!editing && }
);
}
// Only mount when there's an #app element (index.html).
// status.html loads this file to get ProductModal/Footer/Icon helpers,
// but mounts its own React root.
const __mountEl = document.getElementById('app');
if (__mountEl) {
ReactDOM.createRoot(__mountEl).render( );
}
// Expose helpers status.jsx + account.jsx + admin.jsx need
window.Icon = Icon;
window.cls = cls;
window.fmt = fmt;
window.priceFor = priceFor;
window.headlinePrice = headlinePrice;
window.CornerCuts = CornerCuts;
window.categoryLabel = categoryLabel;
window.useAuthState = useAuthState;
window.AuthButton = AuthButton;