/* VE GAMERZ — shared chrome, hooks, and layout primitives. Exports to window.VG. */
const { Button, Badge, Eyebrow } = window.VEGAMERZDesignSystem_63bcb5;
const D = window.VG_DATA;
const wrap = { maxWidth: 'var(--wrap-max)', margin: '0 auto', padding: '0 var(--wrap-pad)', position: 'relative', zIndex: 1 };
const NOTCH = 'polygon(10px 0,100% 0,100% calc(100% - 10px),calc(100% - 10px) 100%,0 100%,0 10px)';
const ROUTES = [
{ id: 'home', label: 'Home' },
{ id: 'about', label: 'About' },
{ id: 'videos', label: 'Videos' },
{ id: 'membership', label: 'Membership' },
{ id: 'contact', label: 'Contact' }
];
/* ── Hooks ─────────────────────────────────────────── */
function useReducedMotion() {
const [rm, setRm] = React.useState(() =>
typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches);
React.useEffect(() => {
const m = matchMedia('(prefers-reduced-motion: reduce)');
const on = () => setRm(m.matches);
m.addEventListener ? m.addEventListener('change', on) : m.addListener(on);
return () => { m.removeEventListener ? m.removeEventListener('change', on) : m.removeListener(on); };
}, []);
return rm;
}
function useInView(opts) {
const ref = React.useRef(null);
const [seen, setSeen] = React.useState(false);
React.useEffect(() => {
const el = ref.current; if (!el) return;
if (typeof IntersectionObserver === 'undefined') { setSeen(true); return; }
const io = new IntersectionObserver((es) => {
es.forEach(e => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
}, { threshold: (opts && opts.threshold) || 0.18, rootMargin: '0px 0px -8% 0px' });
io.observe(el);
return () => io.disconnect();
}, []);
return [ref, seen];
}
/* Fade + rise reveal wrapper. Honors reduced motion. */
function Reveal({ children, delay = 0, y = 22, style = {}, as = 'div' }) {
const rm = useReducedMotion();
const [ref, seen] = useInView();
const El = as;
const on = rm || seen;
return (
{children}
);
}
function useCountUp(target, { decimals = 0, duration = 1400, run = true } = {}) {
const rm = useReducedMotion();
const [val, setVal] = React.useState(rm ? target : 0);
React.useEffect(() => {
if (!run) return;
if (rm) { setVal(target); return; }
let raf, t0;
const ease = (t) => 1 - Math.pow(1 - t, 3);
const step = (t) => {
if (!t0) t0 = t;
const p = Math.min(1, (t - t0) / duration);
setVal(target * ease(p));
if (p < 1) raf = requestAnimationFrame(step);
};
raf = requestAnimationFrame(step);
return () => cancelAnimationFrame(raf);
}, [run, target, rm]);
return decimals ? val.toFixed(decimals) : Math.round(val).toString();
}
/* ── Brand marks ───────────────────────────────────── */
function LogoMark({ size = 40 }) {
return (
);
}
function Wordmark({ size = 20 }) {
return (
VE GAMERZ
);
}
/* ── Nav ───────────────────────────────────────────── */
function NavLink({ label, active, onClick }) {
const [hover, setHover] = React.useState(false);
return (
);
}
function Hamburger({ open, onClick }) {
const bar = { display: 'block', width: 22, height: 2, background: 'var(--c-primary)', transition: 'transform .25s var(--ease), opacity .2s var(--ease)' };
return (
);
}
function NavBar({ route, go }) {
const [open, setOpen] = React.useState(false);
React.useEffect(() => { setOpen(false); }, [route]);
const nav = (id) => { go(id); setOpen(false); };
return (
Live Now
setOpen(o => !o)} />
);
}
/* ── Section head + breadcrumbs ────────────────────── */
function SectionHead({ eyebrow, title, sub, align = 'left', style = {} }) {
return (
{eyebrow ?
{eyebrow}
: null}
{title}
{sub ?
{sub}
: null}
);
}
function Breadcrumbs({ trail, go }) {
return (
);
}
/* ── Carousel (arrows + drag + snap) ───────────────── */
function Carousel({ children, ariaLabel = 'Carousel' }) {
const ref = React.useRef(null);
const drag = React.useRef({ down: false, x: 0, left: 0, moved: 0 });
const [atStart, setAtStart] = React.useState(true);
const [atEnd, setAtEnd] = React.useState(false);
const update = React.useCallback(() => {
const el = ref.current; if (!el) return;
setAtStart(el.scrollLeft <= 2);
setAtEnd(el.scrollLeft + el.clientWidth >= el.scrollWidth - 2);
}, []);
React.useEffect(() => { update(); const el = ref.current; if (!el) return; el.addEventListener('scroll', update, { passive: true }); window.addEventListener('resize', update); return () => { el.removeEventListener('scroll', update); window.removeEventListener('resize', update); }; }, [update]);
const step = (dir) => { const el = ref.current; if (!el) return; const card = el.querySelector('[data-slide]'); const d = (card ? card.offsetWidth + 20 : el.clientWidth * 0.8) * dir; el.scrollBy({ left: d, behavior: 'smooth' }); };
const onDown = (e) => { const el = ref.current; drag.current = { down: true, x: e.clientX, left: el.scrollLeft, moved: 0 }; el.setPointerCapture && el.setPointerCapture(e.pointerId); };
const onMove = (e) => { if (!drag.current.down) return; const dx = e.clientX - drag.current.x; drag.current.moved = Math.abs(dx); ref.current.scrollLeft = drag.current.left - dx; };
const onUp = () => { drag.current.down = false; };
const arrow = (side, disabled, onClick) => (
);
return (
{arrow('l', atStart, () => step(-1))}
{arrow('r', atEnd, () => step(1))}
{ if (drag.current.moved > 6) { e.preventDefault(); e.stopPropagation(); } }}
style={{ display: 'grid', gridAutoFlow: 'column', gridAutoColumns: 'minmax(300px,1fr)', gap: 20, overflowX: 'auto', scrollSnapType: 'x mandatory', scrollbarWidth: 'none', padding: '6px 2px 18px', cursor: 'grab', touchAction: 'pan-y' }} className="vg-carousel-track">
{React.Children.map(children, (ch, i) =>
{ch}
)}
);
}
/* ── Stat counter (count-up on view) ───────────────── */
function StatCounter({ value, suffix = '', decimals = 0, label }) {
const { StatCard } = window.VEGAMERZDesignSystem_63bcb5;
const [ref, seen] = useInView({ threshold: 0.4 });
const n = useCountUp(value, { decimals, run: seen });
return {n}{suffix}} label={label} />
;
}
/* ── Social row ────────────────────────────────────── */
function SocialRow({ size = 'md' }) {
const big = size === 'lg';
return (
);
}
/* ── Background + footer ───────────────────────────── */
function SiteBackground() {
return ;
}
function Footer({ go }) {
return (
);
}
/* Notched panel helper used across pages. */
function Panel({ children, style = {}, glow = false, hover = false }) {
const [h, setH] = React.useState(false);
return (
hover && setH(true)} onMouseLeave={() => hover && setH(false)}
style={{ background: 'var(--grad-panel)', border: `1px solid ${h ? 'var(--c-line-strong)' : 'var(--c-line)'}`, clipPath: 'polygon(var(--notch) 0,100% 0,100% calc(100% - var(--notch)),calc(100% - var(--notch)) 100%,0 100%,0 var(--notch))', padding: 24, boxShadow: h ? 'var(--glow-md)' : (glow ? 'var(--glow-sm)' : 'none'), transform: h ? 'translateY(-4px)' : 'none', transition: 'all var(--dur-card) var(--ease)', ...style }}>
{children}
);
}
window.VG = {
wrap, NOTCH, ROUTES, useReducedMotion, useInView, Reveal, useCountUp,
LogoMark, Wordmark, NavBar, SectionHead, Breadcrumbs, Carousel, StatCounter,
SocialRow, SiteBackground, Footer, Panel
};