@arbidocs/blocks 0.3.115 → 0.3.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +400 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -54
- package/dist/index.d.ts +144 -54
- package/dist/index.js +400 -29
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -2298,6 +2298,322 @@ function TestimonialGrid({ items, columns = "3", testId }) {
|
|
|
2298
2298
|
i
|
|
2299
2299
|
)) });
|
|
2300
2300
|
}
|
|
2301
|
+
function NavItemLink({ item, onNavigate }) {
|
|
2302
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2303
|
+
reactRouterDom.NavLink,
|
|
2304
|
+
{
|
|
2305
|
+
to: item.to,
|
|
2306
|
+
end: item.end,
|
|
2307
|
+
onClick: onNavigate,
|
|
2308
|
+
"data-testid": tid("sidebar-nav", item.id),
|
|
2309
|
+
className: ({ isActive }) => react.cn(
|
|
2310
|
+
"group flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
2311
|
+
isActive ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"
|
|
2312
|
+
),
|
|
2313
|
+
children: [
|
|
2314
|
+
/* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: "size-[18px] shrink-0" }),
|
|
2315
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.label }),
|
|
2316
|
+
item.arbi && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-3.5 text-sidebar-primary", "aria-label": "Powered by ARBI" })
|
|
2317
|
+
]
|
|
2318
|
+
}
|
|
2319
|
+
);
|
|
2320
|
+
}
|
|
2321
|
+
function SidebarBody({
|
|
2322
|
+
sections,
|
|
2323
|
+
footerItems,
|
|
2324
|
+
logo,
|
|
2325
|
+
logoHref,
|
|
2326
|
+
logoLabel,
|
|
2327
|
+
sidebarFooter,
|
|
2328
|
+
onNavigate
|
|
2329
|
+
}) {
|
|
2330
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2331
|
+
logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-16 items-center border-b border-sidebar-border px-5", children: logoHref ? /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: logoHref, "aria-label": logoLabel, onClick: onNavigate, children: logo }) : logo }),
|
|
2332
|
+
/* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex-1 space-y-6 overflow-y-auto px-3 py-5", children: sections.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2333
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-sidebar-foreground/55", children: section.heading }),
|
|
2334
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(NavItemLink, { item, onNavigate }, item.id)) })
|
|
2335
|
+
] }, section.heading)) }),
|
|
2336
|
+
(footerItems?.length || sidebarFooter) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-sidebar-border px-3 py-3", children: [
|
|
2337
|
+
footerItems?.map((item) => /* @__PURE__ */ jsxRuntime.jsx(NavItemLink, { item, onNavigate }, item.id)),
|
|
2338
|
+
sidebarFooter
|
|
2339
|
+
] })
|
|
2340
|
+
] });
|
|
2341
|
+
}
|
|
2342
|
+
function AppShell({
|
|
2343
|
+
sections,
|
|
2344
|
+
footerItems,
|
|
2345
|
+
logo,
|
|
2346
|
+
logoHref,
|
|
2347
|
+
logoLabel,
|
|
2348
|
+
sidebarFooter,
|
|
2349
|
+
topbar,
|
|
2350
|
+
rightRail,
|
|
2351
|
+
children,
|
|
2352
|
+
mainClassName,
|
|
2353
|
+
testIdPrefix = "app"
|
|
2354
|
+
}) {
|
|
2355
|
+
const [open, setOpen] = react$1.useState(false);
|
|
2356
|
+
const location = reactRouterDom.useLocation();
|
|
2357
|
+
react$1.useEffect(() => {
|
|
2358
|
+
setOpen(false);
|
|
2359
|
+
}, [location.pathname]);
|
|
2360
|
+
const body = (onNavigate) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2361
|
+
SidebarBody,
|
|
2362
|
+
{
|
|
2363
|
+
sections,
|
|
2364
|
+
footerItems,
|
|
2365
|
+
logo,
|
|
2366
|
+
logoHref,
|
|
2367
|
+
logoLabel,
|
|
2368
|
+
sidebarFooter,
|
|
2369
|
+
onNavigate
|
|
2370
|
+
}
|
|
2371
|
+
);
|
|
2372
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2373
|
+
"div",
|
|
2374
|
+
{
|
|
2375
|
+
className: "flex h-screen overflow-hidden bg-background",
|
|
2376
|
+
"data-testid": `${testIdPrefix}-shell`,
|
|
2377
|
+
children: [
|
|
2378
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2379
|
+
"aside",
|
|
2380
|
+
{
|
|
2381
|
+
className: "hidden h-full w-64 shrink-0 flex-col border-r border-sidebar-border bg-sidebar lg:flex",
|
|
2382
|
+
"data-testid": `${testIdPrefix}-sidebar`,
|
|
2383
|
+
children: body()
|
|
2384
|
+
}
|
|
2385
|
+
),
|
|
2386
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2387
|
+
"div",
|
|
2388
|
+
{
|
|
2389
|
+
className: "fixed inset-0 z-50 lg:hidden",
|
|
2390
|
+
"data-testid": `${testIdPrefix}-sidebar-mobile`,
|
|
2391
|
+
children: [
|
|
2392
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2393
|
+
"div",
|
|
2394
|
+
{
|
|
2395
|
+
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
2396
|
+
onClick: () => setOpen(false),
|
|
2397
|
+
"aria-hidden": true
|
|
2398
|
+
}
|
|
2399
|
+
),
|
|
2400
|
+
/* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "absolute inset-y-0 left-0 flex w-64 max-w-[82%] flex-col border-r border-sidebar-border bg-sidebar shadow-xl", children: [
|
|
2401
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2402
|
+
"button",
|
|
2403
|
+
{
|
|
2404
|
+
type: "button",
|
|
2405
|
+
onClick: () => setOpen(false),
|
|
2406
|
+
className: "absolute right-3 top-4 z-10 flex size-8 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
|
|
2407
|
+
"aria-label": "Close menu",
|
|
2408
|
+
"data-testid": `${testIdPrefix}-sidebar-close`,
|
|
2409
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-5" })
|
|
2410
|
+
}
|
|
2411
|
+
),
|
|
2412
|
+
body(() => setOpen(false))
|
|
2413
|
+
] })
|
|
2414
|
+
]
|
|
2415
|
+
}
|
|
2416
|
+
),
|
|
2417
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
2418
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2419
|
+
"header",
|
|
2420
|
+
{
|
|
2421
|
+
className: "flex h-16 shrink-0 items-center gap-4 border-b border-border bg-card/80 px-6 backdrop-blur",
|
|
2422
|
+
"data-testid": `${testIdPrefix}-topbar`,
|
|
2423
|
+
children: [
|
|
2424
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2425
|
+
"button",
|
|
2426
|
+
{
|
|
2427
|
+
type: "button",
|
|
2428
|
+
onClick: () => setOpen(true),
|
|
2429
|
+
className: "flex size-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground lg:hidden",
|
|
2430
|
+
"data-testid": `${testIdPrefix}-nav-toggle`,
|
|
2431
|
+
"aria-label": "Open menu",
|
|
2432
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
|
|
2433
|
+
}
|
|
2434
|
+
),
|
|
2435
|
+
topbar
|
|
2436
|
+
]
|
|
2437
|
+
}
|
|
2438
|
+
),
|
|
2439
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2440
|
+
"main",
|
|
2441
|
+
{
|
|
2442
|
+
className: react.cn("flex-1 overflow-y-auto", mainClassName),
|
|
2443
|
+
"data-testid": `${testIdPrefix}-main`,
|
|
2444
|
+
children
|
|
2445
|
+
}
|
|
2446
|
+
)
|
|
2447
|
+
] }),
|
|
2448
|
+
rightRail
|
|
2449
|
+
]
|
|
2450
|
+
}
|
|
2451
|
+
);
|
|
2452
|
+
}
|
|
2453
|
+
var LiveDataContext = react$1.createContext(false);
|
|
2454
|
+
function useLiveDataActive() {
|
|
2455
|
+
return react$1.useContext(LiveDataContext);
|
|
2456
|
+
}
|
|
2457
|
+
function LiveDataProvider({ children }) {
|
|
2458
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LiveDataContext.Provider, { value: true, children });
|
|
2459
|
+
}
|
|
2460
|
+
function WidgetPlaceholder({
|
|
2461
|
+
label,
|
|
2462
|
+
icon: Icon = lucideReact.Sparkles,
|
|
2463
|
+
testId
|
|
2464
|
+
}) {
|
|
2465
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2466
|
+
"div",
|
|
2467
|
+
{
|
|
2468
|
+
className: "flex items-center gap-3 rounded-xl border border-dashed border-border bg-muted/30 px-5 py-6 text-sm text-muted-foreground",
|
|
2469
|
+
"data-testid": testId,
|
|
2470
|
+
children: [
|
|
2471
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }),
|
|
2472
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2473
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: label }),
|
|
2474
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: "\xB7 live in the app" })
|
|
2475
|
+
] })
|
|
2476
|
+
]
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
function useActiveWorkspaceId() {
|
|
2481
|
+
const { workspaceId, fallbackWorkspaceId } = useConnection();
|
|
2482
|
+
return workspaceId ?? fallbackWorkspaceId ?? void 0;
|
|
2483
|
+
}
|
|
2484
|
+
function timeAgo(iso) {
|
|
2485
|
+
if (!iso) return "";
|
|
2486
|
+
const then = new Date(iso).getTime();
|
|
2487
|
+
if (Number.isNaN(then)) return "";
|
|
2488
|
+
const s = Math.max(0, Math.round((Date.now() - then) / 1e3));
|
|
2489
|
+
if (s < 60) return "just now";
|
|
2490
|
+
const m = Math.round(s / 60);
|
|
2491
|
+
if (m < 60) return `${m}m ago`;
|
|
2492
|
+
const h = Math.round(m / 60);
|
|
2493
|
+
if (h < 24) return `${h}h ago`;
|
|
2494
|
+
return `${Math.round(h / 24)}d ago`;
|
|
2495
|
+
}
|
|
2496
|
+
var METRIC_SOURCES = {
|
|
2497
|
+
documents: { label: "Documents", icon: lucideReact.FileText },
|
|
2498
|
+
conversations: { label: "Agent threads", icon: lucideReact.Bot }
|
|
2499
|
+
};
|
|
2500
|
+
var asMetricSource = (s) => s in METRIC_SOURCES ? s : "documents";
|
|
2501
|
+
function AgentActivityLive({
|
|
2502
|
+
title,
|
|
2503
|
+
limit,
|
|
2504
|
+
testId
|
|
2505
|
+
}) {
|
|
2506
|
+
const wsId = useActiveWorkspaceId();
|
|
2507
|
+
const { data, isLoading } = react.useConversations(wsId);
|
|
2508
|
+
const rows = [...data ?? []].sort((a, b) => +new Date(b.updated_at ?? 0) - +new Date(a.updated_at ?? 0)).slice(0, limit);
|
|
2509
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Card, { variant: "elevated", className: "rounded-xl p-5", "data-testid": testId, children: [
|
|
2510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex items-center gap-2", children: [
|
|
2511
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bot, { className: "size-4 text-muted-foreground" }),
|
|
2512
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: title })
|
|
2513
|
+
] }),
|
|
2514
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-loading`, children: "Loading agent threads\u2026" }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-empty`, children: "No agent threads yet." }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", "data-testid": `${testId}-list`, children: rows.map((c, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2515
|
+
"li",
|
|
2516
|
+
{
|
|
2517
|
+
className: "flex items-center justify-between gap-3",
|
|
2518
|
+
"data-testid": `${testId}-item-${i}`,
|
|
2519
|
+
children: [
|
|
2520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 truncate", children: [
|
|
2521
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessagesSquare, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
2522
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm text-foreground", children: c.title?.trim() || "Untitled thread" })
|
|
2523
|
+
] }),
|
|
2524
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: timeAgo(c.updated_at) })
|
|
2525
|
+
]
|
|
2526
|
+
},
|
|
2527
|
+
c.external_id ?? i
|
|
2528
|
+
)) })
|
|
2529
|
+
] });
|
|
2530
|
+
}
|
|
2531
|
+
function LiveMetricInner({
|
|
2532
|
+
label,
|
|
2533
|
+
source,
|
|
2534
|
+
accent,
|
|
2535
|
+
testId
|
|
2536
|
+
}) {
|
|
2537
|
+
const wsId = useActiveWorkspaceId();
|
|
2538
|
+
const docs = react.useDocuments(wsId, { enabled: source === "documents" });
|
|
2539
|
+
const convos = react.useConversations(wsId, { enabled: source === "conversations" });
|
|
2540
|
+
const query = source === "documents" ? docs : convos;
|
|
2541
|
+
const count = Array.isArray(query.data) ? query.data.length : 0;
|
|
2542
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2543
|
+
MetricCard,
|
|
2544
|
+
{
|
|
2545
|
+
label: label || METRIC_SOURCES[source].label,
|
|
2546
|
+
value: query.isLoading ? "\u2014" : String(count),
|
|
2547
|
+
accent,
|
|
2548
|
+
icon: METRIC_SOURCES[source].icon,
|
|
2549
|
+
testId
|
|
2550
|
+
}
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
function AgentActivityBlock({
|
|
2554
|
+
title,
|
|
2555
|
+
limit,
|
|
2556
|
+
testId
|
|
2557
|
+
}) {
|
|
2558
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsxRuntime.jsx(AgentActivityLive, { title, limit, testId }) : /* @__PURE__ */ jsxRuntime.jsx(WidgetPlaceholder, { label: String(title || "Agent activity"), icon: lucideReact.Bot, testId });
|
|
2559
|
+
}
|
|
2560
|
+
function LiveMetricBlock({
|
|
2561
|
+
label,
|
|
2562
|
+
source,
|
|
2563
|
+
accent,
|
|
2564
|
+
testId
|
|
2565
|
+
}) {
|
|
2566
|
+
const src = asMetricSource(source);
|
|
2567
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsxRuntime.jsx(LiveMetricInner, { label, source: src, accent, testId }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2568
|
+
WidgetPlaceholder,
|
|
2569
|
+
{
|
|
2570
|
+
label: String(label || METRIC_SOURCES[src].label),
|
|
2571
|
+
icon: METRIC_SOURCES[src].icon,
|
|
2572
|
+
testId
|
|
2573
|
+
}
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
function createLiveWidgets(kit) {
|
|
2577
|
+
const { blockTestId } = kit;
|
|
2578
|
+
const AgentActivityWidget = {
|
|
2579
|
+
label: "Agent activity (live)",
|
|
2580
|
+
fields: {
|
|
2581
|
+
title: { type: "text", label: "Title" },
|
|
2582
|
+
limit: { type: "number", label: "Rows", min: 1, max: 8 }
|
|
2583
|
+
},
|
|
2584
|
+
defaultProps: { title: "Recent agent activity", limit: 4 },
|
|
2585
|
+
render: ({ id, title, limit }) => /* @__PURE__ */ jsxRuntime.jsx(AgentActivityBlock, { title, limit, testId: blockTestId(id) })
|
|
2586
|
+
};
|
|
2587
|
+
const LiveMetricWidget = {
|
|
2588
|
+
label: "Live metric",
|
|
2589
|
+
fields: {
|
|
2590
|
+
label: { type: "text", label: "Label" },
|
|
2591
|
+
source: {
|
|
2592
|
+
type: "select",
|
|
2593
|
+
label: "Source",
|
|
2594
|
+
options: [
|
|
2595
|
+
{ label: "Documents", value: "documents" },
|
|
2596
|
+
{ label: "Agent threads", value: "conversations" }
|
|
2597
|
+
]
|
|
2598
|
+
},
|
|
2599
|
+
accent: {
|
|
2600
|
+
type: "radio",
|
|
2601
|
+
label: "Accent",
|
|
2602
|
+
options: [
|
|
2603
|
+
{ label: "Default", value: "default" },
|
|
2604
|
+
{ label: "Primary", value: "primary" },
|
|
2605
|
+
{ label: "Success", value: "success" }
|
|
2606
|
+
]
|
|
2607
|
+
}
|
|
2608
|
+
},
|
|
2609
|
+
defaultProps: { label: "", source: "documents", accent: "primary" },
|
|
2610
|
+
render: ({ id, label, source, accent }) => /* @__PURE__ */ jsxRuntime.jsx(LiveMetricBlock, { label, source, accent, testId: blockTestId(id) })
|
|
2611
|
+
};
|
|
2612
|
+
return {
|
|
2613
|
+
AgentActivity: AgentActivityWidget,
|
|
2614
|
+
LiveMetric: LiveMetricWidget
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2301
2617
|
|
|
2302
2618
|
// src/studio/publish.ts
|
|
2303
2619
|
function blobToDataUrl(blob) {
|
|
@@ -2572,34 +2888,36 @@ function PageRenderer({
|
|
|
2572
2888
|
live,
|
|
2573
2889
|
slug: slugProp,
|
|
2574
2890
|
emptyState,
|
|
2575
|
-
testIdPrefix = "studio"
|
|
2891
|
+
testIdPrefix = "studio",
|
|
2892
|
+
liveData = false,
|
|
2893
|
+
initialData,
|
|
2894
|
+
applyTheme = true
|
|
2576
2895
|
}) {
|
|
2577
2896
|
const params = reactRouterDom.useParams();
|
|
2578
2897
|
const slug = slugProp ?? params.slug ?? "home";
|
|
2579
2898
|
const arbi = react.useArbi();
|
|
2580
|
-
const [data, setData] = react$1.useState(null);
|
|
2581
|
-
const [loading, setLoading] = react$1.useState(
|
|
2899
|
+
const [data, setData] = react$1.useState(initialData ?? null);
|
|
2900
|
+
const [loading, setLoading] = react$1.useState(!initialData);
|
|
2582
2901
|
react$1.useEffect(() => {
|
|
2583
2902
|
let cancelled = false;
|
|
2584
|
-
setLoading(
|
|
2903
|
+
setLoading(!initialData);
|
|
2585
2904
|
void (async () => {
|
|
2586
|
-
const
|
|
2587
|
-
persistence.loadPublished(arbi, live, slug),
|
|
2588
|
-
persistence.loadTheme(arbi, live)
|
|
2589
|
-
]);
|
|
2905
|
+
const theme = applyTheme ? (await persistence.loadTheme(arbi, live)).data : void 0;
|
|
2590
2906
|
if (cancelled) return;
|
|
2591
|
-
const page =
|
|
2907
|
+
const page = initialData ?? (await persistence.loadPublished(arbi, live, slug)).data ?? (await persistence.loadPage(arbi, live, slug)).data;
|
|
2592
2908
|
if (cancelled) return;
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2909
|
+
if (applyTheme) {
|
|
2910
|
+
applyThemeVars(
|
|
2911
|
+
theme ? { ...defaultTheme, ...theme, colors: { ...defaultTheme.colors, ...theme.colors } } : defaultTheme
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
2596
2914
|
setData(page);
|
|
2597
2915
|
setLoading(false);
|
|
2598
2916
|
})();
|
|
2599
2917
|
return () => {
|
|
2600
2918
|
cancelled = true;
|
|
2601
2919
|
};
|
|
2602
|
-
}, [arbi, live, slug, persistence, defaultTheme]);
|
|
2920
|
+
}, [arbi, live, slug, persistence, defaultTheme, initialData, applyTheme]);
|
|
2603
2921
|
if (loading) {
|
|
2604
2922
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2605
2923
|
"div",
|
|
@@ -2625,7 +2943,8 @@ function PageRenderer({
|
|
|
2625
2943
|
}
|
|
2626
2944
|
);
|
|
2627
2945
|
}
|
|
2628
|
-
|
|
2946
|
+
const rendered = /* @__PURE__ */ jsxRuntime.jsx(puck.Render, { config, data });
|
|
2947
|
+
return /* @__PURE__ */ jsxRuntime.jsx("main", { "data-testid": `page-${testIdPrefix}-render`, children: liveData ? /* @__PURE__ */ jsxRuntime.jsx(LiveDataProvider, { children: rendered }) : rendered });
|
|
2629
2948
|
}
|
|
2630
2949
|
|
|
2631
2950
|
// src/studio/persistence.ts
|
|
@@ -4233,6 +4552,13 @@ function createSiteBlocks(kit) {
|
|
|
4233
4552
|
TestimonialGrid: TestimonialGridBlock
|
|
4234
4553
|
};
|
|
4235
4554
|
}
|
|
4555
|
+
var emptySlot2 = [];
|
|
4556
|
+
var METRIC_COLS = {
|
|
4557
|
+
"2": "sm:grid-cols-2",
|
|
4558
|
+
"3": "sm:grid-cols-2 lg:grid-cols-3",
|
|
4559
|
+
"4": "sm:grid-cols-2 lg:grid-cols-4"
|
|
4560
|
+
};
|
|
4561
|
+
var METRIC_GAP = { sm: "gap-3", md: "gap-4", lg: "gap-6" };
|
|
4236
4562
|
function createArbiBlocksConfig(opts = {}) {
|
|
4237
4563
|
const kit = createBlockKit(opts.aiFields, opts.imageField, opts.eyebrowClassName);
|
|
4238
4564
|
const { textField, textareaField, boolRadio, iconField, resolveIcon, blockTestId } = kit;
|
|
@@ -4270,16 +4596,19 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4270
4596
|
fields: {
|
|
4271
4597
|
title: textField("Title"),
|
|
4272
4598
|
eyebrow: textField("Eyebrow"),
|
|
4273
|
-
description: textareaField("Description", void 0, "description")
|
|
4599
|
+
description: textareaField("Description", void 0, "description"),
|
|
4600
|
+
// `actions` is a slot so the top band can host real buttons/badges authored
|
|
4601
|
+
// as blocks (drop a Button in), while the interactive body stays bespoke.
|
|
4602
|
+
actions: { type: "slot", allow: ["Button", "Badge"] }
|
|
4274
4603
|
},
|
|
4275
|
-
defaultProps: { title: "Page title" },
|
|
4276
|
-
|
|
4277
|
-
render: ({ id, title, eyebrow, description }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4604
|
+
defaultProps: { title: "Page title", actions: emptySlot2 },
|
|
4605
|
+
render: ({ id, title, eyebrow, description, actions: Actions }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4278
4606
|
PageHeader,
|
|
4279
4607
|
{
|
|
4280
4608
|
title,
|
|
4281
4609
|
eyebrow,
|
|
4282
4610
|
description,
|
|
4611
|
+
actions: /* @__PURE__ */ jsxRuntime.jsx(Actions, { className: "flex items-center gap-2" }),
|
|
4283
4612
|
testId: blockTestId(id)
|
|
4284
4613
|
}
|
|
4285
4614
|
)
|
|
@@ -4289,16 +4618,18 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4289
4618
|
fields: {
|
|
4290
4619
|
title: textField("Title"),
|
|
4291
4620
|
description: textareaField("Description", void 0, "description"),
|
|
4292
|
-
icon: iconField()
|
|
4621
|
+
icon: iconField(),
|
|
4622
|
+
// `action` is a slot so an empty state can offer a real call-to-action button.
|
|
4623
|
+
action: { type: "slot", allow: ["Button"] }
|
|
4293
4624
|
},
|
|
4294
|
-
defaultProps: { title: "Nothing here yet" },
|
|
4295
|
-
|
|
4296
|
-
render: ({ id, title, description, icon }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4625
|
+
defaultProps: { title: "Nothing here yet", action: emptySlot2 },
|
|
4626
|
+
render: ({ id, title, description, icon, action: Action }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4297
4627
|
EmptyState,
|
|
4298
4628
|
{
|
|
4299
4629
|
title,
|
|
4300
4630
|
description,
|
|
4301
4631
|
icon: resolveIcon(icon),
|
|
4632
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(Action, {}),
|
|
4302
4633
|
testId: blockTestId(id)
|
|
4303
4634
|
}
|
|
4304
4635
|
)
|
|
@@ -4351,6 +4682,42 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4351
4682
|
}
|
|
4352
4683
|
)
|
|
4353
4684
|
};
|
|
4685
|
+
const MetricRowBlock = {
|
|
4686
|
+
label: "Metric row",
|
|
4687
|
+
fields: {
|
|
4688
|
+
columns: {
|
|
4689
|
+
type: "radio",
|
|
4690
|
+
label: "Columns",
|
|
4691
|
+
options: [
|
|
4692
|
+
{ label: "2", value: "2" },
|
|
4693
|
+
{ label: "3", value: "3" },
|
|
4694
|
+
{ label: "4", value: "4" }
|
|
4695
|
+
]
|
|
4696
|
+
},
|
|
4697
|
+
gap: {
|
|
4698
|
+
type: "radio",
|
|
4699
|
+
label: "Gap",
|
|
4700
|
+
options: [
|
|
4701
|
+
{ label: "S", value: "sm" },
|
|
4702
|
+
{ label: "M", value: "md" },
|
|
4703
|
+
{ label: "L", value: "lg" }
|
|
4704
|
+
]
|
|
4705
|
+
},
|
|
4706
|
+
// Static KPI tiles and (when registered) live metric widgets both belong in a band.
|
|
4707
|
+
items: { type: "slot", allow: ["MetricCard", "LiveMetric"] }
|
|
4708
|
+
},
|
|
4709
|
+
defaultProps: { columns: "3", gap: "md", items: emptySlot2 },
|
|
4710
|
+
render: ({ id, columns, gap, items: Items }) => /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": blockTestId(id), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4711
|
+
Items,
|
|
4712
|
+
{
|
|
4713
|
+
className: react.cn(
|
|
4714
|
+
"grid grid-cols-1",
|
|
4715
|
+
METRIC_COLS[columns] ?? METRIC_COLS["3"],
|
|
4716
|
+
METRIC_GAP[gap] ?? METRIC_GAP.md
|
|
4717
|
+
)
|
|
4718
|
+
}
|
|
4719
|
+
) })
|
|
4720
|
+
};
|
|
4354
4721
|
const DataTableBlockConfig = {
|
|
4355
4722
|
label: "Data table",
|
|
4356
4723
|
fields: {
|
|
@@ -4549,11 +4916,13 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4549
4916
|
};
|
|
4550
4917
|
const website = createWebsiteBlocks(kit);
|
|
4551
4918
|
const site = createSiteBlocks(kit);
|
|
4919
|
+
const widgets = opts.liveWidgets ? createLiveWidgets(kit) : {};
|
|
4552
4920
|
const components = {
|
|
4553
4921
|
SectionHeading: SectionHeadingBlock,
|
|
4554
4922
|
PageHeader: PageHeaderBlock,
|
|
4555
4923
|
EmptyState: EmptyStateBlock,
|
|
4556
4924
|
MetricCard: MetricCardBlock,
|
|
4925
|
+
MetricRow: MetricRowBlock,
|
|
4557
4926
|
DataTable: DataTableBlockConfig,
|
|
4558
4927
|
Section: SectionBlock,
|
|
4559
4928
|
Card: CardBlock,
|
|
@@ -4561,7 +4930,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4561
4930
|
Badge: BadgeBlock,
|
|
4562
4931
|
Separator: SeparatorBlock,
|
|
4563
4932
|
...website,
|
|
4564
|
-
...site
|
|
4933
|
+
...site,
|
|
4934
|
+
...widgets
|
|
4565
4935
|
};
|
|
4566
4936
|
const config = {
|
|
4567
4937
|
categories: {
|
|
@@ -4595,7 +4965,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4595
4965
|
Commerce: { title: "Commerce", components: ["Pricing"] },
|
|
4596
4966
|
Forms: { title: "Forms", components: ["ContactForm"] },
|
|
4597
4967
|
Navigation: { title: "Navigation", components: ["Navbar", "Footer"] },
|
|
4598
|
-
Data: { title: "Data", components: ["MetricCard", "DataTable"] },
|
|
4968
|
+
Data: { title: "Data", components: ["MetricRow", "MetricCard", "DataTable"] },
|
|
4969
|
+
...opts.liveWidgets ? { Widgets: { title: "Widgets", components: ["AgentActivity", "LiveMetric"] } } : {},
|
|
4599
4970
|
Primitives: { title: "Primitives", components: ["Button", "Badge", "Separator"] }
|
|
4600
4971
|
},
|
|
4601
4972
|
components,
|
|
@@ -5119,6 +5490,7 @@ Object.defineProperty(exports, "toRedlineMarkdown", {
|
|
|
5119
5490
|
exports.ASSET_REF_PREFIX = ASSET_REF_PREFIX;
|
|
5120
5491
|
exports.Accordion = Accordion;
|
|
5121
5492
|
exports.AgentsPanel = AgentsPanel;
|
|
5493
|
+
exports.AppShell = AppShell;
|
|
5122
5494
|
exports.AssetResolverProvider = AssetResolverProvider;
|
|
5123
5495
|
exports.AvatarBlock = AvatarBlock;
|
|
5124
5496
|
exports.Banner = Banner;
|
|
@@ -5140,6 +5512,7 @@ exports.GridView = GridView;
|
|
|
5140
5512
|
exports.Hero = Hero;
|
|
5141
5513
|
exports.LegalArbiProvider = LegalArbiProvider;
|
|
5142
5514
|
exports.ListBlock = ListBlock;
|
|
5515
|
+
exports.LiveDataProvider = LiveDataProvider;
|
|
5143
5516
|
exports.LogoCloud = LogoCloud;
|
|
5144
5517
|
exports.MediaText = MediaText;
|
|
5145
5518
|
exports.MetricCard = MetricCard;
|
|
@@ -5164,6 +5537,7 @@ exports.ThemeEditor = ThemeEditor;
|
|
|
5164
5537
|
exports.Toolbar = Toolbar;
|
|
5165
5538
|
exports.VerticalBuilder = VerticalBuilder;
|
|
5166
5539
|
exports.VideoEmbed = VideoEmbed;
|
|
5540
|
+
exports.WidgetPlaceholder = WidgetPlaceholder;
|
|
5167
5541
|
exports.applyStoredTheme = applyStoredTheme;
|
|
5168
5542
|
exports.applyThemeVars = applyThemeVars;
|
|
5169
5543
|
exports.asAssetRef = asAssetRef;
|
|
@@ -5175,6 +5549,7 @@ exports.createArbiBlocksConfig = createArbiBlocksConfig;
|
|
|
5175
5549
|
exports.createArbiMaterializer = createArbiMaterializer;
|
|
5176
5550
|
exports.createBlockKit = createBlockKit;
|
|
5177
5551
|
exports.createImageField = createImageField;
|
|
5552
|
+
exports.createLiveWidgets = createLiveWidgets;
|
|
5178
5553
|
exports.createModuleRegistry = createModuleRegistry;
|
|
5179
5554
|
exports.createModuleStore = createModuleStore;
|
|
5180
5555
|
exports.createPromptLibrary = createPromptLibrary;
|
|
@@ -5203,6 +5578,7 @@ exports.useAssetResolverActive = useAssetResolverActive;
|
|
|
5203
5578
|
exports.useConnection = useConnection;
|
|
5204
5579
|
exports.useFirmAiTask = useFirmAiTask;
|
|
5205
5580
|
exports.useImageGen = useImageGen;
|
|
5581
|
+
exports.useLiveDataActive = useLiveDataActive;
|
|
5206
5582
|
exports.useSemanticSearch = useSemanticSearch;
|
|
5207
5583
|
exports.useWorkspaceDocs = useWorkspaceDocs;
|
|
5208
5584
|
//# sourceMappingURL=index.cjs.map
|