// fichaje.eu — Shared UI primitives const Card = ({ children, style, padded = true, onClick, hoverable }) => (
{ e.currentTarget.style.boxShadow = 'var(--shadow-md)'; } : undefined} onMouseLeave={hoverable ? (e) => { e.currentTarget.style.boxShadow = 'var(--shadow-xs)'; } : undefined} >{children}
); const SectionHead = ({ title, subtitle, action }) => (
{title}
{subtitle &&
{subtitle}
}
{action}
); const Btn = ({ children, variant = 'primary', size = 'md', icon, iconRight, onClick, style, disabled, type }) => { const v = { primary: { bg: 'var(--brand-600)', color: '#fff', border: 'transparent', hoverBg: 'var(--brand-700)' }, secondary: { bg: 'var(--white)', color: 'var(--ink)', border: 'var(--slate-200)', hoverBg: 'var(--slate-50)' }, ghost: { bg: 'transparent', color: 'var(--slate-700)', border: 'transparent', hoverBg: 'var(--slate-100)' }, danger: { bg: 'var(--danger-500)', color: '#fff', border: 'transparent', hoverBg: 'var(--danger-600)' }, soft: { bg: 'var(--brand-50)', color: 'var(--brand-600)', border: 'transparent', hoverBg: 'var(--brand-100)' }, success: { bg: 'var(--success-500)', color: '#fff', border: 'transparent', hoverBg: 'var(--success-600)' }, }[variant]; const s = { sm: { pad: '6px 10px', fs: 13, gap: 6 }, md: { pad: '9px 14px', fs: 14, gap: 8 }, lg: { pad: '12px 18px', fs: 15, gap: 10 }, }[size]; return ( ); }; const Badge = ({ children, tone = 'slate', dot, style }) => { const t = { slate: ['var(--slate-100)', 'var(--slate-700)', 'var(--slate-400)'], brand: ['var(--brand-50)', 'var(--brand-600)', 'var(--brand-500)'], success: ['var(--success-50)', 'var(--success-600)', 'var(--success-500)'], warning: ['var(--warning-50)', 'var(--warning-600)', 'var(--warning-500)'], danger: ['var(--danger-50)', 'var(--danger-600)', 'var(--danger-500)'], violet: ['var(--violet-100)', '#6D28D9', 'var(--violet-500)'], teal: ['var(--teal-100)', '#0F766E', 'var(--teal-500)'], pink: ['var(--pink-100)', '#BE185D', 'var(--pink-500)'], }[tone]; return ( {dot && } {children} ); }; const Avatar = ({ name, src, size = 36, color, ring }) => { // Deterministic palette from name const palettes = [ ['#DBEAFE', '#1E40AF'], ['#FCE7F3', '#BE185D'], ['#D1FAE5', '#047857'], ['#FEF3C7', '#B45309'], ['#EDE9FE', '#6D28D9'], ['#CCFBF1', '#0F766E'], ['#FFE4E6', '#BE123C'], ['#E0E7FF', '#3730A3'], ]; const idx = (name || '?').split('').reduce((a, c) => a + c.charCodeAt(0), 0) % palettes.length; const [bg, fg] = color || palettes[idx]; const initials = (name || '?').split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase(); return (
{initials}
); }; const ProgressBar = ({ value, max = 100, color = 'var(--brand-600)', track = 'var(--slate-100)', height = 6 }) => (
); const KV = ({ label, value, mono }) => (
{label}
{value}
); const Divider = ({ vertical, style }) => (
); const Tabs = ({ tabs, value, onChange, style }) => (
{tabs.map(t => ( ))}
); const Field = ({ label, hint, children, required }) => ( ); const Input = ({ icon, ...props }) => (
{icon &&
{icon}
} { e.target.style.borderColor = 'var(--brand-500)'; e.target.style.boxShadow = 'var(--ring-brand)'; }} onBlur={(e) => { e.target.style.borderColor = 'var(--slate-200)'; e.target.style.boxShadow = 'none'; }} />
); const Stat = ({ label, value, delta, icon, tone = 'brand' }) => { const tones = { brand: ['var(--brand-50)', 'var(--brand-600)'], success: ['var(--success-50)', 'var(--success-600)'], warning: ['var(--warning-50)', 'var(--warning-600)'], violet: ['var(--violet-100)', '#6D28D9'], }[tone] || ['var(--slate-100)', 'var(--slate-700)']; return (
{label}
{value}
{delta &&
{delta}
}
{icon}
); }; Object.assign(window, { Card, SectionHead, Btn, Badge, Avatar, ProgressBar, KV, Divider, Tabs, Field, Input, Stat });