/* Escala — shared UI atoms */
const { useState, useEffect, useRef, useMemo, useCallback } = React;
// ============ Icons (hand-tuned line set, matches Apple/Mango feel) ============
const Icon = {
Search: (p) => ,
User: (p) => ,
Bag: (p) => ,
Menu: (p) => ,
Close: (p) => ,
Arrow: (p) => ,
ArrowLeft: (p) => ,
Heart: (p) => ,
Check: (p) => ,
Plus: (p) => ,
Minus: (p) => ,
Truck: (p) => ,
Globe: (p) => ,
Stripe: (p) => ,
Google: (p) => ,
};
// ============ Site Header ============
function SiteHeader({ route, navigate, onCart, onSearch, cartCount, user }) {
const T = window.t || (k => k);
const accountLabel = user ? T('nav.account.in') : T('nav.account.out');
const accountTarget = user ? '/account' : '/login';
React.useEffect(() => {
const h = () => { /* re-render via parent on i18n change handled by switcher */ };
window.addEventListener('escala:i18n', h);
return () => window.removeEventListener('escala:i18n', h);
}, []);
return (
);
}
// ============ Footer ============
function SiteFooter({ navigate }) {
return (
);
}
// ============ Product card ============
function ProductCard({ product, onClick }) {
const img = product.images[0];
return (
{product.newIn &&
Nuevo}
{img ?

:
{product.name}
}
{product.name}
{window.ESCALA_FORMAT(product.price)}
{product.type}
{product.colors.includes('white') && }
{product.colors.includes('black') && }
{product.embroideryColors.length} bordados
);
}
// ============ Cart Drawer ============
function CartDrawer({ open, onClose, navigate }) {
const [, force] = useState(0);
useEffect(() => window.ESCALA_CART.subscribe(() => force(v => v+1)), []);
const lines = window.ESCALA_CART.get();
const subtotal = window.ESCALA_CART.subtotal();
return (
<>
>
);
}
// ============ Search overlay ============
function SearchOverlay({ open, onClose, navigate }) {
const [q, setQ] = useState('');
const inputRef = useRef(null);
useEffect(() => { if (open) setTimeout(() => inputRef.current?.focus(), 100); }, [open]);
const products = window.ESCALA_DATA.products;
const results = q ? products.filter(p =>
p.name.toLowerCase().includes(q.toLowerCase()) ||
p.type.toLowerCase().includes(q.toLowerCase())
) : products.slice(0, 4);
if (!open) return null;
return (
{q ? `${results.length} resultados` : 'Populares'}
{results.map(p => (
{ onClose(); navigate('/product/' + p.slug); }}/>
))}
);
}
Object.assign(window, {
Icon, SiteHeader, SiteFooter, ProductCard, CartDrawer, SearchOverlay,
});