/* global React */
const { useState, useEffect, useRef, useMemo } = React;
// ── Icons (inline Lucide stroke SVGs) ─────────────────────────────────
const Icon = ({ d, size = 14, sw = 1.75 }) => (
);
const IPlus = (p) => ;
const ICopy = (p) => ;
const ICheck = (p) => ;
const IArrowL = (p) => ;
const IArrowDL = (p) => ;
const IArrowUR = (p) => ;
const IZap = (p) => ;
const IShield = (p) => ;
const IEye = (p) => ;
const IExt = (p) => ;
const IPause = (p) => ;
const ISettings = (p) => ;
const ILogout = (p) => ;
const IChevron = (p) => ;
const IKey = (p) => ;
// ── Primitives ────────────────────────────────────────────────────────
const Button = ({ variant = 'primary', size = 'md', children, className = '', style, ...p }) => {
const sizes = { sm: 'h-[30px] px-3 text-[11px]', md: 'h-[36px] px-3.5 text-[12px]', lg: 'h-[42px] px-5 text-[13px]' };
const variants = {
primary: { className: 'text-white font-medium', style: { background: 'var(--ks-coral-gradient)' } },
secondary: { className: 'text-[var(--ks-fg-2)] border', style: { background: 'var(--ks-surface-input)', borderColor: 'var(--ks-border)' } },
deposit: { className: 'font-medium border', style: { background: 'var(--ks-success-glow)', color: 'var(--ks-success)', borderColor: 'rgba(74,222,128,0.15)' } },
withdraw: { className: 'font-medium border', style: { background: 'var(--ks-danger-glow)', color: 'var(--ks-danger)', borderColor: 'rgba(248,113,113,0.15)' } },
skill: { className: 'font-medium border', style: { background: 'var(--ks-special-glow)', color: 'var(--ks-special)', borderColor: 'rgba(167,139,250,0.15)' } },
ghost: { className: 'text-[var(--ks-fg-2)]', style: {} },
};
const v = variants[variant];
return (
{children}
);
};
const Label = ({ children, className = '' }) => (
{children}
);
const StatusPill = ({ status }) => {
if (status === 'active') return (
Active
);
return (
Paused
);
};
const SpendingBar = ({ spent, deposited, showLabel = true }) => {
const pct = deposited > 0 ? Math.min((spent / deposited) * 100, 100) : 0;
const color = pct >= 80 ? 'var(--ks-danger)' : pct > 50 ? 'var(--ks-warning)' : 'var(--ks-coral)';
return (
{showLabel &&
80 ? 'var(--ks-danger)' : 'var(--ks-fg-3)' }}>{Math.round(pct)}% spent }
);
};
const Card = ({ variant = 'default', className = '', style, children, onClick }) => {
const styles = {
default: { background: 'linear-gradient(145deg, #151a24, #121620)', border: '1px solid #1e2438', boxShadow: '0 0 0 1px rgba(255,255,255,0.02) inset' },
glow: { background: 'linear-gradient(145deg, #161c28, #111620)', border: '1px solid #283048', boxShadow: '0 0 0 1px rgba(255,255,255,0.03) inset, 0 0 24px rgba(238,96,85,0.04)' },
accent: { background: 'linear-gradient(145deg, #1a1619, #141012)', border: '1px solid rgba(238,96,85,0.22)', boxShadow: '0 0 0 1px rgba(238,96,85,0.04) inset, 0 0 30px rgba(238,96,85,0.08)', position: 'relative', overflow: 'hidden' },
};
return (
{variant === 'accent' &&
}
{children}
);
};
// ── TopBar ─────────────────────────────────────────────────────────────
const TopBar = ({ currentPath, onNav, authed }) => {
const tabs = [
{ href: 'dashboard', label: 'Agent Wallets' },
{ href: 'skills', label: 'Skills' },
{ href: 'why', label: 'Why' },
{ href: 'security', label: 'Security' },
];
return (
{authed && (
onNav('login')} className="w-8 h-8 rounded-full border flex items-center justify-center cursor-pointer hover:text-[var(--ks-danger)] transition-colors" style={{ borderColor: 'var(--ks-border)', color: 'var(--ks-fg-3)' }} title="Logout">
)}
);
};
const BalanceChip = () => (
Base
12,450.32
USDC
);
// ── Sidebar ────────────────────────────────────────────────────────────
const Sidebar = ({ wallets, activeId, onSelect, onCreate }) => (
);
// ── Stat card, Wallet card, Tx row ────────────────────────────────────
const StatCard = ({ label, value, color }) => (
);
const WalletCard = ({ wallet, onClick, index = 0 }) => {
const daysLeft = Math.max(0, Math.ceil((new Date(wallet.expires_at).getTime() - Date.now()) / 86400000));
return (
{wallet.emoji}
{wallet.name}
${wallet.balance.toLocaleString(undefined, { minimumFractionDigits: 2 })}
USDC
{daysLeft}d left
{wallet.id}
{[['Deposited', `$${wallet.deposited.toLocaleString()}`, 'var(--ks-fg-1)'], ['Spent', `$${wallet.spent.toLocaleString()}`, 'var(--ks-fg-1)'], ['Max/tx', `$${wallet.max_per_tx}`, 'var(--ks-warning)']].map(([l, v, c]) => (
))}
{wallet.last_active &&
Last active: {new Date(wallet.last_active).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
}
);
};
const TxRow = ({ tx, isLast }) => {
const isIn = tx.type === 'fund' || tx.type === 'deposit';
const isRej = tx.status === 'rejected';
const cfg = isRej
? { Icn: IZap, bg: 'var(--ks-danger-glow)', fg: 'var(--ks-danger)' }
: isIn
? { Icn: IArrowDL, bg: 'var(--ks-success-glow)', fg: 'var(--ks-success)' }
: { Icn: IZap, bg: 'var(--ks-warning-glow)', fg: 'var(--ks-warning)' };
return (
{tx.description || tx.type}
{tx.timeAgo}
{isIn ? '+' : '-'}${tx.amount}
USDC
);
};
// ── Modals ─────────────────────────────────────────────────────────────
const Modal = ({ open, onClose, children, width = 420 }) => {
if (!open) return null;
return (
e.stopPropagation()} className="rounded-2xl p-6 ks-scale-in" style={{ background: 'var(--ks-ink-raised)', border: '1px solid var(--ks-border)', boxShadow: 'var(--sh-modal)', width, maxWidth: '90vw' }}>
{children}
);
};
const SignModal = ({ open, onClose, message, onSuccess, wallet }) => {
const [phase, setPhase] = useState('idle');
useEffect(() => { if (!open) setPhase('idle'); }, [open]);
const sign = () => {
setPhase('signing');
setTimeout(() => { setPhase('done'); setTimeout(() => { onSuccess?.(); onClose(); }, 700); }, 1200);
};
return (
{phase === 'done' ? : }
{phase === 'done' ? 'Signed' : phase === 'signing' ? 'Waiting for passkey…' : 'Sign message'}
{phase === 'idle' && 'Authenticate with Face ID or Touch ID to continue.'}
{phase === 'signing' && 'Complete the prompt in your browser.'}
{phase === 'done' && 'Authentication complete.'}
{phase === 'idle' && (
<>
{message}
Origin connect.keysmith.ai
Wallet {wallet}
Network Base
Reject
Passkey
>
)}
{phase === 'signing' && (
)}
);
};
Object.assign(window, { Button, Label, StatusPill, SpendingBar, Card, TopBar, Sidebar, StatCard, WalletCard, TxRow, Modal, SignModal, IPlus, ICopy, ICheck, IArrowL, IArrowDL, IArrowUR, IZap, IShield, IEye, IExt, IPause, ISettings, ILogout, IChevron, IKey });