// SATMELI — primitivos de UI. Usan las CSS vars definidas en el HTML. // ── Botón ──────────────────────────────────────────────────────────────── function Btn({ children, variant = 'primary', size = 'md', icon, iconRight, onClick, style, full, type = 'button', title }) { const sizes = { sm: { padding: '8px 14px', fontSize: 13, gap: 6, h: 34 }, md: { padding: '11px 18px', fontSize: 14.5, gap: 8, h: 42 }, lg: { padding: '14px 22px', fontSize: 16, gap: 9, h: 50 }, }; const s = sizes[size]; const variants = { primary: { background: 'var(--signal)', color: 'var(--signal-ink)', boxShadow: 'var(--btn-pop)', fontWeight: 600 }, dark: { background: 'var(--ink)', color: 'var(--bg)', fontWeight: 600 }, outline: { background: 'transparent', color: 'var(--ink)', border: '1.5px solid var(--line-strong)', fontWeight: 600 }, ghost: { background: 'transparent', color: 'var(--muted)', fontWeight: 600 }, soft: { background: 'var(--surface-2)', color: 'var(--ink)', fontWeight: 600 }, alert: { background: 'var(--alert)', color: '#fff', fontWeight: 600 }, danger: { background: 'transparent', color: 'var(--alert)', border: '1.5px solid color-mix(in srgb, var(--alert) 35%, transparent)', fontWeight: 600 }, }; return ( ); } // ── Toggle switch ───────────────────────────────────────────────────────── function Toggle({ on, onChange, size = 'md' }) { const w = size === 'sm' ? 38 : 46, h = size === 'sm' ? 22 : 26, k = h - 6; return ( ); } // ── Segmented control ────────────────────────────────────────────────────── function Segmented({ options, value, onChange, full, size = 'md' }) { const pad = size === 'sm' ? '7px 10px' : '9px 14px'; const fs = size === 'sm' ? 12.5 : 13.5; return (
{options.map((o) => { const v = typeof o === 'string' ? o : o.value; const lab = typeof o === 'string' ? o : o.label; const active = v === value; return ( ); })}
); } // ── Chip de metadata (mono) ──────────────────────────────────────────────── function Chip({ icon, children, tone = 'neutral', style }) { const tones = { neutral: { background: 'var(--surface-2)', color: 'var(--muted-2)', border: '1px solid var(--line)' }, line: { background: 'transparent', color: 'var(--muted-2)', border: '1px solid var(--line-strong)' }, signal: { background: 'var(--signal-soft)', color: 'var(--signal-ink-2)', border: '1px solid var(--signal-line)' }, alert: { background: 'var(--alert-soft)', color: 'var(--alert-ink)', border: '1px solid var(--alert-line)' }, }; return ( {icon && } {children} ); } // ── Punto de estado con pulso ────────────────────────────────────────────── function StatusDot({ active, size = 8 }) { return ( {active && } ); } // ── Sparkline ────────────────────────────────────────────────────────────── function Sparkline({ data, w = 96, h = 30, color = 'var(--signal-ink-2)', fill = true, strokeW = 1.75 }) { const max = Math.max(1, ...data); const n = data.length; const stepX = w / (n - 1); const pts = data.map((v, i) => [i * stepX, h - 3 - (v / max) * (h - 6)]); const line = pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(' '); const area = `${line} L${w},${h} L0,${h} Z`; const gid = 'sg' + Math.round(w + h + n + data[0]); return ( {fill && ( <> )} ); } // ── Placeholder de foto de producto ──────────────────────────────────────── function ProductThumb({ cat, size = 64, radius = 'var(--r-md)', tag = true }) { const c = SAT_CATS[cat] || SAT_CATS.tech; return (
{/* watermark grande */}
{tag && ( FOTO )}
); } // ── Eyebrow mono ─────────────────────────────────────────────────────────── function Eyebrow({ children, color = 'var(--muted-2)', style }) { return
{children}
; } Object.assign(window, { Btn, Toggle, Segmented, Chip, StatusDot, Sparkline, ProductThumb, Eyebrow });