// ==========================================================
// VoAIs Call — shared UI: icons, primitives, sample data
// Exposes everything on window so other Babel scripts can use.
// ==========================================================
// ---------- Icon set (stroke-style, 1.6 weight) ----------
const Ic = ({ d, size = 16, fill = "none", stroke = "currentColor", w = 1.6, children, ...rest }) => (
);
const I = {
dashboard: (p) => ,
campaigns: (p) => ,
agents: (p) => ,
flow: (p) => ,
monitor: (p) => ,
history: (p) => ,
contacts: (p) => ,
analytics: (p) => ,
kb: (p) => ,
integrations: (p) => ,
settings: (p) => ,
billing: (p) => ,
search: (p) => ,
bell: (p) => ,
chevD: (p) => ,
chevR: (p) => ,
chevL: (p) => ,
chevU: (p) => ,
plus: (p) => ,
filter: (p) => ,
more: (p) => ,
phone: (p) => ,
phoneIn: (p) => ,
phoneOut: (p) => ,
mic: (p) => ,
micOff: (p) => ,
play: (p) => ,
pause: (p) => ,
upload: (p) => ,
download: (p) => ,
edit: (p) => ,
trash: (p) => ,
copy: (p) => ,
pin: (p) => ,
check: (p) => ,
x: (p) => ,
star: (p) => ,
fire: (p) => ,
bot: (p) => ,
spark: (p) => ,
globe: (p) => ,
shield: (p) => ,
zap: (p) => ,
logout: (p) => ,
sun: (p) => ,
moon: (p) => ,
collapse: (p) => ,
expand: (p) => ,
user: (p) => ,
users: (p) => ,
server: (p) => ,
tag: (p) => ,
arrow_up_right: (p) => ,
arrow_right: (p) => ,
arrow_left: (p) => ,
drag: (p) => ,
link: (p) => ,
brain: (p) => ,
message: (p) => ,
alert: (p) => ,
calendar: (p) => ,
network: (p) => ,
whatsapp: (p) => ,
inbox: (p) => ,
send: (p) => ,
paperclip: (p) => ,
smile: (p) => ,
template: (p) => ,
reply: (p) => ,
email: (p) => ,
archive: (p) => ,
};
// ---------- Primitives ----------
function Badge({ tone = "gray", children, dot }) {
return {dot && }{children};
}
function Btn({ kind = "primary", size, icon, children, onClick, className = "", ...rest }) {
const sizeCls = size === "sm" ? "sm" : size === "lg" ? "lg" : "";
const iconOnly = icon && !children ? "icon-only" : "";
return (
);
}
function Card({ children, className = "", padded = true, ...rest }) {
return
{children}
;
}
function CardHead({ title, subtitle, right, icon }) {
return (
{icon}
{title}
{subtitle &&
{subtitle}
}
{right}
);
}
function Segmented({ value, options, onChange }) {
return (
{options.map(o => {
const v = typeof o === "string" ? o : o.value;
const label = typeof o === "string" ? o : o.label;
return (
);
})}
);
}
function Tabs({ value, options, onChange }) {
return (
{options.map(o => {
const v = typeof o === "string" ? o : o.value;
const label = typeof o === "string" ? o : o.label;
const count = typeof o === "object" ? o.count : null;
return (
onChange?.(v)}>
{label}{count != null && {count}}
);
})}
);
}
function Avatar({ name = "?", src, size = 32, color }) {
const initials = name.split(/\s+/).slice(0, 2).map(s => s[0]).join("").toUpperCase();
const palette = ["linear-gradient(135deg,#FFB199,#C46AFF)","linear-gradient(135deg,#5B8FFF,#00D49F)","linear-gradient(135deg,#FFD27D,#FF6F91)","linear-gradient(135deg,#A78BFA,#3B7BFF)","linear-gradient(135deg,#00D49F,#4DD0E1)","linear-gradient(135deg,#FF8A3D,#F4C53D)"];
const bg = color || palette[(name.charCodeAt(0) || 0) % palette.length];
return (
{initials || "?"}
);
}
function Toggle({ value, onChange }) {
return onChange?.(!value)} role="switch" aria-checked={!!value}/>;
}
function Field({ label, hint, children }) {
return (
{label &&
}
{children}
{hint &&
{hint}
}
);
}
// Sparkline (mini chart for KPI cards)
function Sparkline({ data, color = "var(--accent)", width = 80, height = 28 }) {
if (!data?.length) return null;
const max = Math.max(...data), min = Math.min(...data);
const rng = max - min || 1;
const pts = data.map((v, i) => {
const x = (i / (data.length - 1)) * width;
const y = height - ((v - min) / rng) * (height - 4) - 2;
return `${x},${y}`;
});
const area = `M0,${height} L${pts.join(" L")} L${width},${height} Z`;
return (
);
}
// Donut chart
function Donut({ data, size = 160, thickness = 22, center }) {
const total = data.reduce((a, b) => a + b.value, 0) || 1;
const radius = (size - thickness) / 2;
const circ = 2 * Math.PI * radius;
let offset = 0;
return (
);
}
// Bar chart for revenue/calls
function BarChart({ data, height = 220, accentIndex = null, format = (v) => v.toLocaleString() }) {
const max = Math.max(...data.map(d => d.value));
const yLines = [0, 0.25, 0.5, 0.75, 1].map(p => Math.round(max * p));
return (
{[...yLines].reverse().map((v, i) =>
{v >= 1000 ? (v/1000).toFixed(1)+"k" : v}
)}
{[0, 0.25, 0.5, 0.75, 1].map((p, i) => (
))}
{data.map((d, i) => {
const isAcc = i === accentIndex;
return (
{isAcc && (
▲ {d.delta}
)}
{!isAcc && (
)}
{isAcc && (
{format(d.value)}
)}
{d.label}
);
})}
);
}
// Live waveform (animated)
function Waveform({ count = 36, color = "var(--accent)", height = 36, running = true }) {
return (
{Array.from({ length: count }).map((_, i) => {
const seed = Math.sin(i * 1.3) * 0.5 + 0.5;
const h = 25 + seed * 75;
const delay = (i % 8) * 0.08;
return (
);
})}
);
}
// Empty state
function Empty({ title, sub, action, icon }) {
return (
{icon &&
{icon}
}
{title}
{sub &&
{sub}
}
{action &&
{action}
}
);
}
// expose globally
Object.assign(window, {
I, Ic, Badge, Btn, Card, CardHead, Segmented, Tabs, Avatar, Toggle, Field,
Sparkline, Donut, BarChart, Waveform, Empty
});