// Shared UI atoms const UiAvatar = ({ avatar, size = 36, ring = false, style }) => { const safeAvatar = avatar || avatarFor("?"); const s = { width: size, height: size, borderRadius: size * 0.32, background: safeAvatar.bg, color: safeAvatar.fg, display: "grid", placeItems: "center", fontSize: size * 0.45, fontWeight: 600, flexShrink: 0, boxShadow: ring ? `0 0 0 2px var(--bg-elev), 0 0 0 3.5px ${safeAvatar.ring}` : "none", fontFamily: "var(--font-cn)", ...style, }; return
{safeAvatar.initial}
; }; const Pill = ({ children, tone = "neutral", style, icon }) => { const tones = { neutral: { bg: "var(--bg-sunk)", fg: "var(--ink-2)", bd: "var(--line)" }, accent: { bg: "var(--accent-soft)", fg: "var(--accent-ink)", bd: "transparent" }, sage: { bg: "var(--sage-soft)", fg: "oklch(0.35 0.06 155)", bd: "transparent" }, amber: { bg: "var(--amber-soft)", fg: "oklch(0.40 0.11 70)", bd: "transparent" }, rose: { bg: "var(--rose-soft)", fg: "oklch(0.40 0.11 20)", bd: "transparent" }, sky: { bg: "var(--sky-soft)", fg: "oklch(0.38 0.08 240)", bd: "transparent" }, violet: { bg: "var(--violet-soft)", fg: "oklch(0.40 0.09 300)", bd: "transparent" }, outline: { bg: "transparent", fg: "var(--ink-2)", bd: "var(--line-strong)" }, }; const t = tones[tone] || tones.neutral; return ( {icon}{children} ); }; const Btn = ({ children, variant = "ghost", size = "md", icon, iconRight, onClick, style, disabled, title }) => { const sizes = { sm: { padding: "5px 10px", fontSize: 12.5, radius: 8, gap: 5 }, md: { padding: "8px 14px", fontSize: 13, radius: 10, gap: 6 }, lg: { padding: "11px 18px", fontSize: 14, radius: 12, gap: 7 }, }; const variants = { primary: { background: "var(--accent)", color: "white", border: "1px solid transparent", boxShadow: "0 1px 2px oklch(0.3 0.02 60 / 0.2), inset 0 1px 0 oklch(1 0 0 / 0.15)", }, soft: { background: "var(--accent-soft)", color: "var(--accent-ink)", border: "1px solid transparent", }, ghost: { background: "transparent", color: "var(--ink-2)", border: "1px solid transparent", }, outline: { background: "var(--bg-elev)", color: "var(--ink)", border: "1px solid var(--line-strong)", }, subtle: { background: "var(--bg-sunk)", color: "var(--ink-2)", border: "1px solid transparent", }, }; const sz = sizes[size]; const v = variants[variant]; return ( ); }; const Card = ({ children, style, as = "div", padded = true, ...rest }) => { const Tag = as; return ( {children} ); }; // progress bar with gradient fill const Progress = ({ value, total, color = "var(--accent)", height = 6, showLabel = false }) => { const pct = total > 0 ? Math.max(0, Math.min(1, value / total)) : 0; return (
{showLabel && ( {Math.round(pct * 100)}% )}
); }; // sparkline const UiSparkline = ({ values, color = "var(--accent)", height = 28, width = 80, fill = true }) => { if (!values || !values.length) return null; const max = Math.max(...values); const min = Math.min(...values); const range = max - min || 1; const step = width / (values.length - 1); const points = values.map((v, i) => { const x = i * step; const y = height - ((v - min) / range) * (height - 4) - 2; return [x, y]; }); const path = points.map((p, i) => `${i ? "L" : "M"}${p[0].toFixed(1)} ${p[1].toFixed(1)}`).join(" "); const area = `${path} L ${width} ${height} L 0 ${height} Z`; return ( {fill && } ); }; // tiny tooltip const Tip = ({ text, children }) => { const [shown, setShown] = React.useState(false); return ( setShown(true)} onMouseLeave={() => setShown(false)}> {children} {shown && ( {text} )} ); }; Object.assign(window, { UiAvatar, Pill, Btn, Card, Progress, UiSparkline, Tip });