// Componentes principales: Topbar, ProductCard, Hero, Tabbar, etc. const { useState, useEffect, useRef } = React; // ====================== TOPBAR ====================== function Topbar({ cartCount, wishCount, activeTab, onNavigate, onOpenSearch, onOpenCart, onOpenWish, transparent }) { const navItems = [ { id: "home", label: "Inicio" }, { id: "shop", label: "Tienda" }, { id: "wish", label: "Deseos" }, { id: "account", label: "Cuenta" }, ]; return (
mima edit
); } // ====================== TABBAR ====================== function Tabbar({ active, onChange }) { const tabs = [ { id: "home", label: "Inicio", icon: I.Home }, { id: "shop", label: "Tienda", icon: I.Compass }, { id: "wish", label: "Deseos", icon: I.Heart }, { id: "account", label: "Cuenta", icon: I.User }, ]; return ( ); } // ====================== PRODUCT CARD ====================== function ProductCard({ product, currency, rates, onOpen, onAdd, onFav, isFav }) { const cardRef = useRef(null); const handleAdd = (e) => { e.stopPropagation(); if (product.stock === 0) return; onAdd(product, cardRef.current); }; const out = product.stock === 0; const low = product.stock > 0 && product.stock < 10; return (
onOpen(product)} ref={cardRef}>
{product.isNew && Nuevo} {out && Sin stock} {!product.isNew && !out && product.compareAt && Oferta}
{product.name}
{product.tagline}
{formatPrice(product.price, currency, rates)} {product.compareAt && {formatPrice(product.compareAt, currency, rates)}}
); } // ====================== HERO ====================== function Hero({ variant, onCta, brand }) { const heroRef = useRef(null); // parallax useEffect(() => { const scrollEl = heroRef.current?.closest(".body-scroll"); if (!scrollEl) return; const onScroll = () => { const bg = heroRef.current?.querySelector(".hero-bg"); if (bg) bg.style.transform = `translateY(${scrollEl.scrollTop * 0.3}px) scale(1.05)`; }; scrollEl.addEventListener("scroll", onScroll, { passive: true }); return () => scrollEl.removeEventListener("scroll", onScroll); }, []); if (variant === "editorial") { return (
Belleza elegida con cuidado

El ritual
vuelve a casa.

Seleccion cuidada de belleza para rutinas simples, calidas y confiables.

); } if (variant === "mono") { return (
mima edit

Pequeños rituales,
grandes cambios.

Una boutique digital con productos seleccionados a mano.

); } // default: warm gradient hero return (
Belleza elegida con cuidado

Aromas que
te abrazan.

Perfumeria y cuidado personal con productos seleccionados de Natura, Avon y marcas elegidas.

); } // ====================== CATEGORÍAS RAIL ====================== function CategoryRail({ cats, active, onChange }) { return (
{cats.map(c => ( ))}
); } // ====================== BANNER CARRUSEL ====================== function BannerRail() { const banners = [ { cls: "b1", eyebrow: "Hasta 30% off", title: "Liquidación de invierno" }, { cls: "b2", eyebrow: "Edición limitada", title: "Sérum Vit. C, ahora con niacinamida" }, { cls: "b3", eyebrow: "Envío gratis", title: "En compras desde $ 35.000" }, ]; return (
{banners.map((b, i) => (
{b.eyebrow}

{b.title}

))}
); } // ====================== LOYALTY CARD ====================== function LoyaltyCard({ points, target = 1000 }) { const pct = Math.min(100, Math.round((points / target) * 100)); return (
mima edit - beneficios
{points}/ {target} puntos
Te faltan {target - points} puntos para tu próxima recompensa.
); } // ====================== TOAST ====================== function Toast({ message, onClose }) { useEffect(() => { const t = setTimeout(onClose, 2200); return () => clearTimeout(t); }, [message, onClose]); if (!message) return null; return (
{message}
); } Object.assign(window, { Topbar, Tabbar, ProductCard, Hero, CategoryRail, BannerRail, LoyaltyCard, Toast });