// ui.jsx — Superstar Peptides shared atoms (light, brand-matched)
// Tiny, composable bits. NEVER name a styles object `styles`.
const { useState, useEffect, useRef, useMemo } = React;
// ─── Icons ────────────────────────────────────────────────
function Icon({ name, size = 18, stroke = 1.7 }) {
const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round" };
switch (name) {
case "back": return ;
case "check": return ;
case "arrow": return ;
case "menu": return ;
case "shield": return ;
case "rx": return ;
case "spark": return ;
case "flame": return ;
case "moon": return ;
case "brain": return ;
case "heart": return ;
case "muscle": return ;
case "scale": return ;
case "drop": return ;
case "leaf": return ;
case "fork": return ;
case "stethoscope": return ;
case "calendar": return ;
case "lightning": return ;
case "warning": return ;
case "x": return ;
case "info": return ;
case "syringe": return ;
case "lock": return ;
case "star": return ;
case "user": return ;
case "mail": return ;
case "clock": return ;
case "dollar": return ;
case "plus": return ;
case "trend": return ;
case "atom": return ;
case "gym": return ;
case "home": return ;
case "play": return ;
default: return null;
}
}
// ─── Brand star (4-point burst — matches site brandmark) ──
function BrandStar({ size = 18 }) {
return (
);
}
// ─── Wordmark ─────────────────────────────────────────────
function Wordmark() {
return (
SUPERSTAR/PEPTIDES
);
}
// ─── Top app bar (back · wordmark · help/lang/menu) ───────
function SPHeader({ step, total, onBack, canBack = true }) {
const pct = total > 0 ? Math.max(2, Math.min(100, (step / total) * 100)) : 0;
return (
);
}
// ─── Body silhouette (clinical SVG — light-bg palette) ─────
function BodySilhouette({ fat = 0.3, muscle = 0.4, gender = 'm', size = 240, selected = false }) {
// Interpolate torso width based on fat & muscle
const torsoW = 36 + fat * 32 + muscle * 8;
const waistW = 28 + fat * 34;
const armW = 10 + muscle * 8 + fat * 4;
const chestY = gender === 'f' ? 92 : 86;
const skin = '#D9C4A6';
const skinShade = '#B89878';
const shorts = '#3A4A5C';
return (
);
}
// ─── Body region map (selectable areas) ────────────────────
function BodyMap({ value = [], onToggle }) {
const isOn = (k) => value.includes(k);
const fill = (k) => isOn(k) ? 'var(--accent-deep)' : '#D9C4A6';
const opa = (k) => isOn(k) ? 0.92 : 0.7;
return (
);
}
// ─── Footer / CTA wrap ────────────────────────────────────
function SPFooter({ children }) {
return (
);
}
// ─── Banner ────────────────────────────────────────────────
function SuccessBanner({ children }) {
return (
);
}
// ─── Option card (horizontal row with icon + title + sub) ──
function OptionCard({ icon, title, sub, selected, onClick, trailing, multi = false, single = false, accentIcon = false, image }) {
return (
);
}
// ─── Portrait card (silhouette + label bar) ───────────────
// NOTE: the design handoff used a drag-to-fill here. For the live
// page we render the silhouette directly so cards look complete out of the box.
// Swap in a real
(or re-add image-slot) when brand body photos exist.
function PortraitCard({ label, selected, onClick, gender = 'm', fat = 0.3, muscle = 0.4, height = 240, slotId, placeholder }) {
return (
);
}
Object.assign(window, { Icon, BrandStar, Wordmark, SPHeader, SPFooter, BodySilhouette, BodyMap, SuccessBanner, OptionCard, PortraitCard });