(() => { const { Icon, Badge } = window.TaskFlowDesignSystem_dd53c2; /* Chart primitives for the dashboards. Same shapes as the product's analytics reference — capsule bars, a time heat grid, a segmented category bar and KPI tiles with an open-arrow. */ function KpiTile({ label, value, icon, delta, tone = "teal", onOpen }) { const [hover, setHover] = React.useState(false); const tint = { teal: ["var(--teal-100)", "var(--teal-600)"], mint: ["var(--mint-100)", "var(--mint-600)"], gold: ["var(--gold-100)", "var(--gold-600)"], coral: ["var(--coral-100)", "var(--coral-600)"], leaf: ["var(--leaf-100)", "var(--leaf-600)"], }[tone]; const up = (delta || "").trim().startsWith("+"); return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ display: "flex", flexDirection: "column", gap: 12, padding: 16, borderRadius: "var(--radius-xl)", background: "var(--surface-glass)", backdropFilter: "var(--blur-glass)", WebkitBackdropFilter: "var(--blur-glass)", border: "1px solid var(--border-glass)", boxShadow: hover ? "var(--glow-teal)" : "var(--shadow-glass)", transform: hover ? "var(--lift-hover)" : "none", transition: "var(--transition-float)", minWidth: 0, }}>
{label}
{value}
{delta && (
{delta} vs bulan lalu
)}
); } /* Capsule bar chart. series: [{ label, value, secondary }] */ function CapsuleBars({ series = [], max, height = 210, unit = "", legend = [] }) { const phone = useBreakpoint() === "mobile"; const [active, setActive] = React.useState(null); const raw = max || Math.max(1, ...series.map((s) => s.value)); const top = Math.ceil(raw / 4) * 4; // keeps the four axis steps even const peak = series.reduce((a, b) => (b.value > (a ? a.value : -1) ? b : a), null); const shown = active != null ? series[active] : peak; return (
{legend.length > 0 && (
{legend.map(([label, color]) => ( {label} ))}
)}
{[4, 3, 2, 1, 0].map((i) => ( {Math.round((top / 4) * i)}{unit} ))}
{shown && !phone && (
{shown.label} {shown.value}{unit} {shown.note && {shown.note}}
)} {series.map((s, i) => { const h = Math.max(4, Math.round(((s.value / top) * (height - 34)))); const on = active === i || (active == null && shown === s); return (
setActive(i)} onMouseLeave={() => setActive(null)} style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", alignItems: "center", gap: 8, cursor: "default" }}>
{on && }
{s.label}
); })}
); } /* Time-of-day × weekday heat grid. cells: { [row]: number[] } */ function HeatGrid({ rows = [], cols = [], values = [], max }) { const top = max || Math.max(1, ...values.flat()); const shade = (v) => { if (!v) return ["var(--neutral-100)", "transparent"]; const r = v / top; if (r > 0.75) return ["var(--teal-600)", "0 4px 12px -4px rgba(19,168,140,.6)"]; if (r > 0.5) return ["var(--teal-500)", "none"]; if (r > 0.25) return ["var(--leaf-400)", "none"]; return ["var(--teal-200)", "none"]; }; return (
{rows.map((label, r) => (
{label}
{cols.map((c, i) => { const v = (values[r] || [])[i] || 0; const [bg, sh] = shade(v); return ; })}
))}
{cols.map((c, i) => ( {c} ))}
); } /* Segmented share bar with a legend underneath. parts: [{label,value,color}] */ function ShareBar({ parts = [], total }) { const sum = total || parts.reduce((a, p) => a + p.value, 0) || 1; return (
{parts.map((p) => ( ))}
{parts.map((p) => ( {p.label} {Math.round((p.value / sum) * 100)}% ))}
); } /* Two-endpoint route strip (pipeline hand-off). */ function RouteStrip({ fromLabel, fromMeta, toLabel, toMeta, progress = 50 }) { return (
{fromLabel} {fromMeta} {toLabel} {toMeta}
); } Object.assign(window, { KpiTile, CapsuleBars, HeatGrid, ShareBar, RouteStrip }); })();