@arbidocs/blocks 0.3.114 → 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 +432 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +158 -55
- package/dist/index.d.ts +158 -55
- package/dist/index.js +432 -32
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
2
|
import { persist } from 'zustand/middleware';
|
|
3
3
|
import { createContext, useState, useEffect, useCallback, useMemo, useContext, useRef } from 'react';
|
|
4
|
-
import { MessageSquare, Cpu, Code, Cloud, Layers, Target, Award, MapPin, Phone, Mail, Lock, Globe, Heart, Star, Rocket, Shield, Zap, Sparkles, Gavel, Scale, Bell, Activity, BarChart3, DollarSign, TrendingUp, Info, AlertCircle, CheckCircle, Clock, Calendar, Briefcase, Users, Folder, FileText, RotateCcw, Palette, Search, ArrowUpRight, ArrowDownRight, ImageIcon, ArrowRight, Quote, ChevronDown, XCircle, AlertTriangle, CheckCircle2, Check, ArrowLeft, Loader2, ChevronUp, BrainCircuit, Bot, LayoutGrid, FileJson, Save, Download, ImagePlus, Upload, Link2 } from 'lucide-react';
|
|
5
|
-
import { Input, Card, CardHeader, CardTitle, CardContent, useArbi, ArbiProvider, useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, cn, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Button, Avatar, AvatarImage, AvatarFallback, AiMarkdown, Badge, Switch, useConfigs, useAgents, Checkbox, Tabs as Tabs$1, TabsList, TabsTrigger, TabsContent, Separator, ArbiWebSocketProvider, useDocuments, useThumbnails } from '@arbidocs/react';
|
|
4
|
+
import { MessageSquare, Cpu, Code, Cloud, Layers, Target, Award, MapPin, Phone, Mail, Lock, Globe, Heart, Star, Rocket, Shield, Zap, Sparkles, Gavel, Scale, Bell, Activity, BarChart3, DollarSign, TrendingUp, Info, AlertCircle, CheckCircle, Clock, Calendar, Briefcase, Users, Folder, FileText, RotateCcw, Palette, Search, ArrowUpRight, ArrowDownRight, ImageIcon, ArrowRight, Quote, ChevronDown, XCircle, AlertTriangle, CheckCircle2, Check, X, Menu, ArrowLeft, Loader2, ChevronUp, BrainCircuit, Bot, LayoutGrid, FileJson, Save, Download, ImagePlus, Upload, Link2, MessagesSquare } from 'lucide-react';
|
|
5
|
+
import { Input, Card, CardHeader, CardTitle, CardContent, useArbi, ArbiProvider, useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, cn, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Button, Avatar, AvatarImage, AvatarFallback, AiMarkdown, Badge, Switch, useConfigs, useAgents, Checkbox, Tabs as Tabs$1, TabsList, TabsTrigger, TabsContent, Separator, ArbiWebSocketProvider, useDocuments, useThumbnails, useConversations } from '@arbidocs/react';
|
|
6
6
|
export { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, redlineStats, textToArtifact, toRedlineMarkdown } from '@arbidocs/react';
|
|
7
7
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
9
9
|
import { AgGridReact } from 'ag-grid-react';
|
|
10
10
|
import { themeQuartz, AllCommunityModule } from 'ag-grid-community';
|
|
11
|
-
import { Link, useParams } from 'react-router-dom';
|
|
11
|
+
import { useLocation, Link, useParams, NavLink } from 'react-router-dom';
|
|
12
12
|
import { Puck, Render } from '@measured/puck';
|
|
13
13
|
|
|
14
14
|
// src/prompts.ts
|
|
@@ -2297,6 +2297,322 @@ function TestimonialGrid({ items, columns = "3", testId }) {
|
|
|
2297
2297
|
i
|
|
2298
2298
|
)) });
|
|
2299
2299
|
}
|
|
2300
|
+
function NavItemLink({ item, onNavigate }) {
|
|
2301
|
+
return /* @__PURE__ */ jsxs(
|
|
2302
|
+
NavLink,
|
|
2303
|
+
{
|
|
2304
|
+
to: item.to,
|
|
2305
|
+
end: item.end,
|
|
2306
|
+
onClick: onNavigate,
|
|
2307
|
+
"data-testid": tid("sidebar-nav", item.id),
|
|
2308
|
+
className: ({ isActive }) => cn(
|
|
2309
|
+
"group flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
2310
|
+
isActive ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"
|
|
2311
|
+
),
|
|
2312
|
+
children: [
|
|
2313
|
+
/* @__PURE__ */ jsx(item.icon, { className: "size-[18px] shrink-0" }),
|
|
2314
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: item.label }),
|
|
2315
|
+
item.arbi && /* @__PURE__ */ jsx(Sparkles, { className: "size-3.5 text-sidebar-primary", "aria-label": "Powered by ARBI" })
|
|
2316
|
+
]
|
|
2317
|
+
}
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2320
|
+
function SidebarBody({
|
|
2321
|
+
sections,
|
|
2322
|
+
footerItems,
|
|
2323
|
+
logo,
|
|
2324
|
+
logoHref,
|
|
2325
|
+
logoLabel,
|
|
2326
|
+
sidebarFooter,
|
|
2327
|
+
onNavigate
|
|
2328
|
+
}) {
|
|
2329
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2330
|
+
logo && /* @__PURE__ */ jsx("div", { className: "flex h-16 items-center border-b border-sidebar-border px-5", children: logoHref ? /* @__PURE__ */ jsx(Link, { to: logoHref, "aria-label": logoLabel, onClick: onNavigate, children: logo }) : logo }),
|
|
2331
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 space-y-6 overflow-y-auto px-3 py-5", children: sections.map((section) => /* @__PURE__ */ jsxs("div", { children: [
|
|
2332
|
+
/* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-sidebar-foreground/55", children: section.heading }),
|
|
2333
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(NavItemLink, { item, onNavigate }, item.id)) })
|
|
2334
|
+
] }, section.heading)) }),
|
|
2335
|
+
(footerItems?.length || sidebarFooter) && /* @__PURE__ */ jsxs("div", { className: "border-t border-sidebar-border px-3 py-3", children: [
|
|
2336
|
+
footerItems?.map((item) => /* @__PURE__ */ jsx(NavItemLink, { item, onNavigate }, item.id)),
|
|
2337
|
+
sidebarFooter
|
|
2338
|
+
] })
|
|
2339
|
+
] });
|
|
2340
|
+
}
|
|
2341
|
+
function AppShell({
|
|
2342
|
+
sections,
|
|
2343
|
+
footerItems,
|
|
2344
|
+
logo,
|
|
2345
|
+
logoHref,
|
|
2346
|
+
logoLabel,
|
|
2347
|
+
sidebarFooter,
|
|
2348
|
+
topbar,
|
|
2349
|
+
rightRail,
|
|
2350
|
+
children,
|
|
2351
|
+
mainClassName,
|
|
2352
|
+
testIdPrefix = "app"
|
|
2353
|
+
}) {
|
|
2354
|
+
const [open, setOpen] = useState(false);
|
|
2355
|
+
const location = useLocation();
|
|
2356
|
+
useEffect(() => {
|
|
2357
|
+
setOpen(false);
|
|
2358
|
+
}, [location.pathname]);
|
|
2359
|
+
const body = (onNavigate) => /* @__PURE__ */ jsx(
|
|
2360
|
+
SidebarBody,
|
|
2361
|
+
{
|
|
2362
|
+
sections,
|
|
2363
|
+
footerItems,
|
|
2364
|
+
logo,
|
|
2365
|
+
logoHref,
|
|
2366
|
+
logoLabel,
|
|
2367
|
+
sidebarFooter,
|
|
2368
|
+
onNavigate
|
|
2369
|
+
}
|
|
2370
|
+
);
|
|
2371
|
+
return /* @__PURE__ */ jsxs(
|
|
2372
|
+
"div",
|
|
2373
|
+
{
|
|
2374
|
+
className: "flex h-screen overflow-hidden bg-background",
|
|
2375
|
+
"data-testid": `${testIdPrefix}-shell`,
|
|
2376
|
+
children: [
|
|
2377
|
+
/* @__PURE__ */ jsx(
|
|
2378
|
+
"aside",
|
|
2379
|
+
{
|
|
2380
|
+
className: "hidden h-full w-64 shrink-0 flex-col border-r border-sidebar-border bg-sidebar lg:flex",
|
|
2381
|
+
"data-testid": `${testIdPrefix}-sidebar`,
|
|
2382
|
+
children: body()
|
|
2383
|
+
}
|
|
2384
|
+
),
|
|
2385
|
+
open && /* @__PURE__ */ jsxs(
|
|
2386
|
+
"div",
|
|
2387
|
+
{
|
|
2388
|
+
className: "fixed inset-0 z-50 lg:hidden",
|
|
2389
|
+
"data-testid": `${testIdPrefix}-sidebar-mobile`,
|
|
2390
|
+
children: [
|
|
2391
|
+
/* @__PURE__ */ jsx(
|
|
2392
|
+
"div",
|
|
2393
|
+
{
|
|
2394
|
+
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
2395
|
+
onClick: () => setOpen(false),
|
|
2396
|
+
"aria-hidden": true
|
|
2397
|
+
}
|
|
2398
|
+
),
|
|
2399
|
+
/* @__PURE__ */ 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: [
|
|
2400
|
+
/* @__PURE__ */ jsx(
|
|
2401
|
+
"button",
|
|
2402
|
+
{
|
|
2403
|
+
type: "button",
|
|
2404
|
+
onClick: () => setOpen(false),
|
|
2405
|
+
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",
|
|
2406
|
+
"aria-label": "Close menu",
|
|
2407
|
+
"data-testid": `${testIdPrefix}-sidebar-close`,
|
|
2408
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-5" })
|
|
2409
|
+
}
|
|
2410
|
+
),
|
|
2411
|
+
body(() => setOpen(false))
|
|
2412
|
+
] })
|
|
2413
|
+
]
|
|
2414
|
+
}
|
|
2415
|
+
),
|
|
2416
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
2417
|
+
/* @__PURE__ */ jsxs(
|
|
2418
|
+
"header",
|
|
2419
|
+
{
|
|
2420
|
+
className: "flex h-16 shrink-0 items-center gap-4 border-b border-border bg-card/80 px-6 backdrop-blur",
|
|
2421
|
+
"data-testid": `${testIdPrefix}-topbar`,
|
|
2422
|
+
children: [
|
|
2423
|
+
/* @__PURE__ */ jsx(
|
|
2424
|
+
"button",
|
|
2425
|
+
{
|
|
2426
|
+
type: "button",
|
|
2427
|
+
onClick: () => setOpen(true),
|
|
2428
|
+
className: "flex size-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground lg:hidden",
|
|
2429
|
+
"data-testid": `${testIdPrefix}-nav-toggle`,
|
|
2430
|
+
"aria-label": "Open menu",
|
|
2431
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
|
|
2432
|
+
}
|
|
2433
|
+
),
|
|
2434
|
+
topbar
|
|
2435
|
+
]
|
|
2436
|
+
}
|
|
2437
|
+
),
|
|
2438
|
+
/* @__PURE__ */ jsx(
|
|
2439
|
+
"main",
|
|
2440
|
+
{
|
|
2441
|
+
className: cn("flex-1 overflow-y-auto", mainClassName),
|
|
2442
|
+
"data-testid": `${testIdPrefix}-main`,
|
|
2443
|
+
children
|
|
2444
|
+
}
|
|
2445
|
+
)
|
|
2446
|
+
] }),
|
|
2447
|
+
rightRail
|
|
2448
|
+
]
|
|
2449
|
+
}
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
var LiveDataContext = createContext(false);
|
|
2453
|
+
function useLiveDataActive() {
|
|
2454
|
+
return useContext(LiveDataContext);
|
|
2455
|
+
}
|
|
2456
|
+
function LiveDataProvider({ children }) {
|
|
2457
|
+
return /* @__PURE__ */ jsx(LiveDataContext.Provider, { value: true, children });
|
|
2458
|
+
}
|
|
2459
|
+
function WidgetPlaceholder({
|
|
2460
|
+
label,
|
|
2461
|
+
icon: Icon = Sparkles,
|
|
2462
|
+
testId
|
|
2463
|
+
}) {
|
|
2464
|
+
return /* @__PURE__ */ jsxs(
|
|
2465
|
+
"div",
|
|
2466
|
+
{
|
|
2467
|
+
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",
|
|
2468
|
+
"data-testid": testId,
|
|
2469
|
+
children: [
|
|
2470
|
+
/* @__PURE__ */ jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }),
|
|
2471
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2472
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: label }),
|
|
2473
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1", children: "\xB7 live in the app" })
|
|
2474
|
+
] })
|
|
2475
|
+
]
|
|
2476
|
+
}
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
function useActiveWorkspaceId() {
|
|
2480
|
+
const { workspaceId, fallbackWorkspaceId } = useConnection();
|
|
2481
|
+
return workspaceId ?? fallbackWorkspaceId ?? void 0;
|
|
2482
|
+
}
|
|
2483
|
+
function timeAgo(iso) {
|
|
2484
|
+
if (!iso) return "";
|
|
2485
|
+
const then = new Date(iso).getTime();
|
|
2486
|
+
if (Number.isNaN(then)) return "";
|
|
2487
|
+
const s = Math.max(0, Math.round((Date.now() - then) / 1e3));
|
|
2488
|
+
if (s < 60) return "just now";
|
|
2489
|
+
const m = Math.round(s / 60);
|
|
2490
|
+
if (m < 60) return `${m}m ago`;
|
|
2491
|
+
const h = Math.round(m / 60);
|
|
2492
|
+
if (h < 24) return `${h}h ago`;
|
|
2493
|
+
return `${Math.round(h / 24)}d ago`;
|
|
2494
|
+
}
|
|
2495
|
+
var METRIC_SOURCES = {
|
|
2496
|
+
documents: { label: "Documents", icon: FileText },
|
|
2497
|
+
conversations: { label: "Agent threads", icon: Bot }
|
|
2498
|
+
};
|
|
2499
|
+
var asMetricSource = (s) => s in METRIC_SOURCES ? s : "documents";
|
|
2500
|
+
function AgentActivityLive({
|
|
2501
|
+
title,
|
|
2502
|
+
limit,
|
|
2503
|
+
testId
|
|
2504
|
+
}) {
|
|
2505
|
+
const wsId = useActiveWorkspaceId();
|
|
2506
|
+
const { data, isLoading } = useConversations(wsId);
|
|
2507
|
+
const rows = [...data ?? []].sort((a, b) => +new Date(b.updated_at ?? 0) - +new Date(a.updated_at ?? 0)).slice(0, limit);
|
|
2508
|
+
return /* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-xl p-5", "data-testid": testId, children: [
|
|
2509
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2", children: [
|
|
2510
|
+
/* @__PURE__ */ jsx(Bot, { className: "size-4 text-muted-foreground" }),
|
|
2511
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: title })
|
|
2512
|
+
] }),
|
|
2513
|
+
isLoading ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-loading`, children: "Loading agent threads\u2026" }) : rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-empty`, children: "No agent threads yet." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-2", "data-testid": `${testId}-list`, children: rows.map((c, i) => /* @__PURE__ */ jsxs(
|
|
2514
|
+
"li",
|
|
2515
|
+
{
|
|
2516
|
+
className: "flex items-center justify-between gap-3",
|
|
2517
|
+
"data-testid": `${testId}-item-${i}`,
|
|
2518
|
+
children: [
|
|
2519
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 truncate", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx(MessagesSquare, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
2521
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm text-foreground", children: c.title?.trim() || "Untitled thread" })
|
|
2522
|
+
] }),
|
|
2523
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: timeAgo(c.updated_at) })
|
|
2524
|
+
]
|
|
2525
|
+
},
|
|
2526
|
+
c.external_id ?? i
|
|
2527
|
+
)) })
|
|
2528
|
+
] });
|
|
2529
|
+
}
|
|
2530
|
+
function LiveMetricInner({
|
|
2531
|
+
label,
|
|
2532
|
+
source,
|
|
2533
|
+
accent,
|
|
2534
|
+
testId
|
|
2535
|
+
}) {
|
|
2536
|
+
const wsId = useActiveWorkspaceId();
|
|
2537
|
+
const docs = useDocuments(wsId, { enabled: source === "documents" });
|
|
2538
|
+
const convos = useConversations(wsId, { enabled: source === "conversations" });
|
|
2539
|
+
const query = source === "documents" ? docs : convos;
|
|
2540
|
+
const count = Array.isArray(query.data) ? query.data.length : 0;
|
|
2541
|
+
return /* @__PURE__ */ jsx(
|
|
2542
|
+
MetricCard,
|
|
2543
|
+
{
|
|
2544
|
+
label: label || METRIC_SOURCES[source].label,
|
|
2545
|
+
value: query.isLoading ? "\u2014" : String(count),
|
|
2546
|
+
accent,
|
|
2547
|
+
icon: METRIC_SOURCES[source].icon,
|
|
2548
|
+
testId
|
|
2549
|
+
}
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
function AgentActivityBlock({
|
|
2553
|
+
title,
|
|
2554
|
+
limit,
|
|
2555
|
+
testId
|
|
2556
|
+
}) {
|
|
2557
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsx(AgentActivityLive, { title, limit, testId }) : /* @__PURE__ */ jsx(WidgetPlaceholder, { label: String(title || "Agent activity"), icon: Bot, testId });
|
|
2558
|
+
}
|
|
2559
|
+
function LiveMetricBlock({
|
|
2560
|
+
label,
|
|
2561
|
+
source,
|
|
2562
|
+
accent,
|
|
2563
|
+
testId
|
|
2564
|
+
}) {
|
|
2565
|
+
const src = asMetricSource(source);
|
|
2566
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsx(LiveMetricInner, { label, source: src, accent, testId }) : /* @__PURE__ */ jsx(
|
|
2567
|
+
WidgetPlaceholder,
|
|
2568
|
+
{
|
|
2569
|
+
label: String(label || METRIC_SOURCES[src].label),
|
|
2570
|
+
icon: METRIC_SOURCES[src].icon,
|
|
2571
|
+
testId
|
|
2572
|
+
}
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
function createLiveWidgets(kit) {
|
|
2576
|
+
const { blockTestId } = kit;
|
|
2577
|
+
const AgentActivityWidget = {
|
|
2578
|
+
label: "Agent activity (live)",
|
|
2579
|
+
fields: {
|
|
2580
|
+
title: { type: "text", label: "Title" },
|
|
2581
|
+
limit: { type: "number", label: "Rows", min: 1, max: 8 }
|
|
2582
|
+
},
|
|
2583
|
+
defaultProps: { title: "Recent agent activity", limit: 4 },
|
|
2584
|
+
render: ({ id, title, limit }) => /* @__PURE__ */ jsx(AgentActivityBlock, { title, limit, testId: blockTestId(id) })
|
|
2585
|
+
};
|
|
2586
|
+
const LiveMetricWidget = {
|
|
2587
|
+
label: "Live metric",
|
|
2588
|
+
fields: {
|
|
2589
|
+
label: { type: "text", label: "Label" },
|
|
2590
|
+
source: {
|
|
2591
|
+
type: "select",
|
|
2592
|
+
label: "Source",
|
|
2593
|
+
options: [
|
|
2594
|
+
{ label: "Documents", value: "documents" },
|
|
2595
|
+
{ label: "Agent threads", value: "conversations" }
|
|
2596
|
+
]
|
|
2597
|
+
},
|
|
2598
|
+
accent: {
|
|
2599
|
+
type: "radio",
|
|
2600
|
+
label: "Accent",
|
|
2601
|
+
options: [
|
|
2602
|
+
{ label: "Default", value: "default" },
|
|
2603
|
+
{ label: "Primary", value: "primary" },
|
|
2604
|
+
{ label: "Success", value: "success" }
|
|
2605
|
+
]
|
|
2606
|
+
}
|
|
2607
|
+
},
|
|
2608
|
+
defaultProps: { label: "", source: "documents", accent: "primary" },
|
|
2609
|
+
render: ({ id, label, source, accent }) => /* @__PURE__ */ jsx(LiveMetricBlock, { label, source, accent, testId: blockTestId(id) })
|
|
2610
|
+
};
|
|
2611
|
+
return {
|
|
2612
|
+
AgentActivity: AgentActivityWidget,
|
|
2613
|
+
LiveMetric: LiveMetricWidget
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2300
2616
|
|
|
2301
2617
|
// src/studio/publish.ts
|
|
2302
2618
|
function blobToDataUrl(blob) {
|
|
@@ -2375,7 +2691,8 @@ function StudioEditor({
|
|
|
2375
2691
|
live,
|
|
2376
2692
|
initialSlug,
|
|
2377
2693
|
testIdPrefix = "studio",
|
|
2378
|
-
publishAsset
|
|
2694
|
+
publishAsset,
|
|
2695
|
+
resetSeam = false
|
|
2379
2696
|
}) {
|
|
2380
2697
|
const arbi = useArbi();
|
|
2381
2698
|
const materialize = useMemo(
|
|
@@ -2406,6 +2723,14 @@ function StudioEditor({
|
|
|
2406
2723
|
cancelled = true;
|
|
2407
2724
|
};
|
|
2408
2725
|
}, [slug, live]);
|
|
2726
|
+
useEffect(() => {
|
|
2727
|
+
if (!resetSeam) return;
|
|
2728
|
+
const w = window;
|
|
2729
|
+
w.__studioResetSlug = (s) => persistence.deletePage(arbi, live, s);
|
|
2730
|
+
return () => {
|
|
2731
|
+
delete w.__studioResetSlug;
|
|
2732
|
+
};
|
|
2733
|
+
}, [resetSeam, arbi, live, persistence]);
|
|
2409
2734
|
const persist4 = useCallback(
|
|
2410
2735
|
async (toSave) => {
|
|
2411
2736
|
setSaving(true);
|
|
@@ -2562,34 +2887,36 @@ function PageRenderer({
|
|
|
2562
2887
|
live,
|
|
2563
2888
|
slug: slugProp,
|
|
2564
2889
|
emptyState,
|
|
2565
|
-
testIdPrefix = "studio"
|
|
2890
|
+
testIdPrefix = "studio",
|
|
2891
|
+
liveData = false,
|
|
2892
|
+
initialData,
|
|
2893
|
+
applyTheme = true
|
|
2566
2894
|
}) {
|
|
2567
2895
|
const params = useParams();
|
|
2568
2896
|
const slug = slugProp ?? params.slug ?? "home";
|
|
2569
2897
|
const arbi = useArbi();
|
|
2570
|
-
const [data, setData] = useState(null);
|
|
2571
|
-
const [loading, setLoading] = useState(
|
|
2898
|
+
const [data, setData] = useState(initialData ?? null);
|
|
2899
|
+
const [loading, setLoading] = useState(!initialData);
|
|
2572
2900
|
useEffect(() => {
|
|
2573
2901
|
let cancelled = false;
|
|
2574
|
-
setLoading(
|
|
2902
|
+
setLoading(!initialData);
|
|
2575
2903
|
void (async () => {
|
|
2576
|
-
const
|
|
2577
|
-
persistence.loadPublished(arbi, live, slug),
|
|
2578
|
-
persistence.loadTheme(arbi, live)
|
|
2579
|
-
]);
|
|
2904
|
+
const theme = applyTheme ? (await persistence.loadTheme(arbi, live)).data : void 0;
|
|
2580
2905
|
if (cancelled) return;
|
|
2581
|
-
const page =
|
|
2906
|
+
const page = initialData ?? (await persistence.loadPublished(arbi, live, slug)).data ?? (await persistence.loadPage(arbi, live, slug)).data;
|
|
2582
2907
|
if (cancelled) return;
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2908
|
+
if (applyTheme) {
|
|
2909
|
+
applyThemeVars(
|
|
2910
|
+
theme ? { ...defaultTheme, ...theme, colors: { ...defaultTheme.colors, ...theme.colors } } : defaultTheme
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2586
2913
|
setData(page);
|
|
2587
2914
|
setLoading(false);
|
|
2588
2915
|
})();
|
|
2589
2916
|
return () => {
|
|
2590
2917
|
cancelled = true;
|
|
2591
2918
|
};
|
|
2592
|
-
}, [arbi, live, slug, persistence, defaultTheme]);
|
|
2919
|
+
}, [arbi, live, slug, persistence, defaultTheme, initialData, applyTheme]);
|
|
2593
2920
|
if (loading) {
|
|
2594
2921
|
return /* @__PURE__ */ jsx(
|
|
2595
2922
|
"div",
|
|
@@ -2615,7 +2942,8 @@ function PageRenderer({
|
|
|
2615
2942
|
}
|
|
2616
2943
|
);
|
|
2617
2944
|
}
|
|
2618
|
-
|
|
2945
|
+
const rendered = /* @__PURE__ */ jsx(Render, { config, data });
|
|
2946
|
+
return /* @__PURE__ */ jsx("main", { "data-testid": `page-${testIdPrefix}-render`, children: liveData ? /* @__PURE__ */ jsx(LiveDataProvider, { children: rendered }) : rendered });
|
|
2619
2947
|
}
|
|
2620
2948
|
|
|
2621
2949
|
// src/studio/persistence.ts
|
|
@@ -2691,6 +3019,26 @@ function createStudioPersistence(cfg) {
|
|
|
2691
3019
|
function loadPublished(arbi, live, slug) {
|
|
2692
3020
|
return readPage(arbi, live, publishedKey(slug), publishedFile(slug));
|
|
2693
3021
|
}
|
|
3022
|
+
async function deletePage(arbi, live, slug) {
|
|
3023
|
+
try {
|
|
3024
|
+
localStorage.removeItem(pageKey(slug));
|
|
3025
|
+
localStorage.removeItem(publishedKey(slug));
|
|
3026
|
+
} catch {
|
|
3027
|
+
}
|
|
3028
|
+
if (!canUseArbi(arbi, live)) return;
|
|
3029
|
+
try {
|
|
3030
|
+
await arbi.selectWorkspace(WORKSPACE_ID);
|
|
3031
|
+
const docs = await arbi.documents.list();
|
|
3032
|
+
const names = [pageFile(slug), publishedFile(slug)];
|
|
3033
|
+
const ids = docs.filter(
|
|
3034
|
+
(d) => (d.folder ?? "").includes(FOLDER) && names.some((n) => (d.file_name ?? "").endsWith(n))
|
|
3035
|
+
).map((d) => d.external_id);
|
|
3036
|
+
if (ids.length) await arbi.documents.delete(ids);
|
|
3037
|
+
console.info(`[studio] deleted ${ids.length} doc(s) for "${slug}" from ARBI`);
|
|
3038
|
+
} catch (e) {
|
|
3039
|
+
console.warn(`[studio] ARBI delete failed for "${slug}"`, e);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2694
3042
|
async function saveTheme(arbi, live, theme) {
|
|
2695
3043
|
try {
|
|
2696
3044
|
localStorage.setItem(THEME_KEY, JSON.stringify(theme));
|
|
@@ -2727,7 +3075,7 @@ function createStudioPersistence(cfg) {
|
|
|
2727
3075
|
return null;
|
|
2728
3076
|
}
|
|
2729
3077
|
}
|
|
2730
|
-
return { savePage, loadPage, savePublished, loadPublished, saveTheme, loadTheme };
|
|
3078
|
+
return { savePage, loadPage, savePublished, loadPublished, deletePage, saveTheme, loadTheme };
|
|
2731
3079
|
}
|
|
2732
3080
|
function AiTextField({
|
|
2733
3081
|
value,
|
|
@@ -2967,7 +3315,7 @@ function ImageFieldControl({
|
|
|
2967
3315
|
{
|
|
2968
3316
|
src: thumb,
|
|
2969
3317
|
alt: d.file_name ?? "",
|
|
2970
|
-
className: "aspect-square w-full object-
|
|
3318
|
+
className: "aspect-square w-full bg-muted object-contain"
|
|
2971
3319
|
}
|
|
2972
3320
|
) : /* @__PURE__ */ jsx("span", { className: "flex aspect-square w-full items-center justify-center bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx(ImagePlus, { className: "size-4" }) })
|
|
2973
3321
|
},
|
|
@@ -3127,7 +3475,7 @@ function Section({
|
|
|
3127
3475
|
] });
|
|
3128
3476
|
}
|
|
3129
3477
|
var iconMap = {
|
|
3130
|
-
FileText,
|
|
3478
|
+
FileText: FileText,
|
|
3131
3479
|
Folder,
|
|
3132
3480
|
Users,
|
|
3133
3481
|
Briefcase,
|
|
@@ -4203,6 +4551,13 @@ function createSiteBlocks(kit) {
|
|
|
4203
4551
|
TestimonialGrid: TestimonialGridBlock
|
|
4204
4552
|
};
|
|
4205
4553
|
}
|
|
4554
|
+
var emptySlot2 = [];
|
|
4555
|
+
var METRIC_COLS = {
|
|
4556
|
+
"2": "sm:grid-cols-2",
|
|
4557
|
+
"3": "sm:grid-cols-2 lg:grid-cols-3",
|
|
4558
|
+
"4": "sm:grid-cols-2 lg:grid-cols-4"
|
|
4559
|
+
};
|
|
4560
|
+
var METRIC_GAP = { sm: "gap-3", md: "gap-4", lg: "gap-6" };
|
|
4206
4561
|
function createArbiBlocksConfig(opts = {}) {
|
|
4207
4562
|
const kit = createBlockKit(opts.aiFields, opts.imageField, opts.eyebrowClassName);
|
|
4208
4563
|
const { textField, textareaField, boolRadio, iconField, resolveIcon, blockTestId } = kit;
|
|
@@ -4240,16 +4595,19 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4240
4595
|
fields: {
|
|
4241
4596
|
title: textField("Title"),
|
|
4242
4597
|
eyebrow: textField("Eyebrow"),
|
|
4243
|
-
description: textareaField("Description", void 0, "description")
|
|
4598
|
+
description: textareaField("Description", void 0, "description"),
|
|
4599
|
+
// `actions` is a slot so the top band can host real buttons/badges authored
|
|
4600
|
+
// as blocks (drop a Button in), while the interactive body stays bespoke.
|
|
4601
|
+
actions: { type: "slot", allow: ["Button", "Badge"] }
|
|
4244
4602
|
},
|
|
4245
|
-
defaultProps: { title: "Page title" },
|
|
4246
|
-
|
|
4247
|
-
render: ({ id, title, eyebrow, description }) => /* @__PURE__ */ jsx(
|
|
4603
|
+
defaultProps: { title: "Page title", actions: emptySlot2 },
|
|
4604
|
+
render: ({ id, title, eyebrow, description, actions: Actions }) => /* @__PURE__ */ jsx(
|
|
4248
4605
|
PageHeader,
|
|
4249
4606
|
{
|
|
4250
4607
|
title,
|
|
4251
4608
|
eyebrow,
|
|
4252
4609
|
description,
|
|
4610
|
+
actions: /* @__PURE__ */ jsx(Actions, { className: "flex items-center gap-2" }),
|
|
4253
4611
|
testId: blockTestId(id)
|
|
4254
4612
|
}
|
|
4255
4613
|
)
|
|
@@ -4259,16 +4617,18 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4259
4617
|
fields: {
|
|
4260
4618
|
title: textField("Title"),
|
|
4261
4619
|
description: textareaField("Description", void 0, "description"),
|
|
4262
|
-
icon: iconField()
|
|
4620
|
+
icon: iconField(),
|
|
4621
|
+
// `action` is a slot so an empty state can offer a real call-to-action button.
|
|
4622
|
+
action: { type: "slot", allow: ["Button"] }
|
|
4263
4623
|
},
|
|
4264
|
-
defaultProps: { title: "Nothing here yet" },
|
|
4265
|
-
|
|
4266
|
-
render: ({ id, title, description, icon }) => /* @__PURE__ */ jsx(
|
|
4624
|
+
defaultProps: { title: "Nothing here yet", action: emptySlot2 },
|
|
4625
|
+
render: ({ id, title, description, icon, action: Action }) => /* @__PURE__ */ jsx(
|
|
4267
4626
|
EmptyState,
|
|
4268
4627
|
{
|
|
4269
4628
|
title,
|
|
4270
4629
|
description,
|
|
4271
4630
|
icon: resolveIcon(icon),
|
|
4631
|
+
action: /* @__PURE__ */ jsx(Action, {}),
|
|
4272
4632
|
testId: blockTestId(id)
|
|
4273
4633
|
}
|
|
4274
4634
|
)
|
|
@@ -4321,6 +4681,42 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4321
4681
|
}
|
|
4322
4682
|
)
|
|
4323
4683
|
};
|
|
4684
|
+
const MetricRowBlock = {
|
|
4685
|
+
label: "Metric row",
|
|
4686
|
+
fields: {
|
|
4687
|
+
columns: {
|
|
4688
|
+
type: "radio",
|
|
4689
|
+
label: "Columns",
|
|
4690
|
+
options: [
|
|
4691
|
+
{ label: "2", value: "2" },
|
|
4692
|
+
{ label: "3", value: "3" },
|
|
4693
|
+
{ label: "4", value: "4" }
|
|
4694
|
+
]
|
|
4695
|
+
},
|
|
4696
|
+
gap: {
|
|
4697
|
+
type: "radio",
|
|
4698
|
+
label: "Gap",
|
|
4699
|
+
options: [
|
|
4700
|
+
{ label: "S", value: "sm" },
|
|
4701
|
+
{ label: "M", value: "md" },
|
|
4702
|
+
{ label: "L", value: "lg" }
|
|
4703
|
+
]
|
|
4704
|
+
},
|
|
4705
|
+
// Static KPI tiles and (when registered) live metric widgets both belong in a band.
|
|
4706
|
+
items: { type: "slot", allow: ["MetricCard", "LiveMetric"] }
|
|
4707
|
+
},
|
|
4708
|
+
defaultProps: { columns: "3", gap: "md", items: emptySlot2 },
|
|
4709
|
+
render: ({ id, columns, gap, items: Items }) => /* @__PURE__ */ jsx("div", { "data-testid": blockTestId(id), children: /* @__PURE__ */ jsx(
|
|
4710
|
+
Items,
|
|
4711
|
+
{
|
|
4712
|
+
className: cn(
|
|
4713
|
+
"grid grid-cols-1",
|
|
4714
|
+
METRIC_COLS[columns] ?? METRIC_COLS["3"],
|
|
4715
|
+
METRIC_GAP[gap] ?? METRIC_GAP.md
|
|
4716
|
+
)
|
|
4717
|
+
}
|
|
4718
|
+
) })
|
|
4719
|
+
};
|
|
4324
4720
|
const DataTableBlockConfig = {
|
|
4325
4721
|
label: "Data table",
|
|
4326
4722
|
fields: {
|
|
@@ -4519,11 +4915,13 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4519
4915
|
};
|
|
4520
4916
|
const website = createWebsiteBlocks(kit);
|
|
4521
4917
|
const site = createSiteBlocks(kit);
|
|
4918
|
+
const widgets = opts.liveWidgets ? createLiveWidgets(kit) : {};
|
|
4522
4919
|
const components = {
|
|
4523
4920
|
SectionHeading: SectionHeadingBlock,
|
|
4524
4921
|
PageHeader: PageHeaderBlock,
|
|
4525
4922
|
EmptyState: EmptyStateBlock,
|
|
4526
4923
|
MetricCard: MetricCardBlock,
|
|
4924
|
+
MetricRow: MetricRowBlock,
|
|
4527
4925
|
DataTable: DataTableBlockConfig,
|
|
4528
4926
|
Section: SectionBlock,
|
|
4529
4927
|
Card: CardBlock,
|
|
@@ -4531,7 +4929,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4531
4929
|
Badge: BadgeBlock,
|
|
4532
4930
|
Separator: SeparatorBlock,
|
|
4533
4931
|
...website,
|
|
4534
|
-
...site
|
|
4932
|
+
...site,
|
|
4933
|
+
...widgets
|
|
4535
4934
|
};
|
|
4536
4935
|
const config = {
|
|
4537
4936
|
categories: {
|
|
@@ -4565,7 +4964,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4565
4964
|
Commerce: { title: "Commerce", components: ["Pricing"] },
|
|
4566
4965
|
Forms: { title: "Forms", components: ["ContactForm"] },
|
|
4567
4966
|
Navigation: { title: "Navigation", components: ["Navbar", "Footer"] },
|
|
4568
|
-
Data: { title: "Data", components: ["MetricCard", "DataTable"] },
|
|
4967
|
+
Data: { title: "Data", components: ["MetricRow", "MetricCard", "DataTable"] },
|
|
4968
|
+
...opts.liveWidgets ? { Widgets: { title: "Widgets", components: ["AgentActivity", "LiveMetric"] } } : {},
|
|
4569
4969
|
Primitives: { title: "Primitives", components: ["Button", "Badge", "Separator"] }
|
|
4570
4970
|
},
|
|
4571
4971
|
components,
|
|
@@ -5050,6 +5450,6 @@ function VerticalBuilder({
|
|
|
5050
5450
|
] });
|
|
5051
5451
|
}
|
|
5052
5452
|
|
|
5053
|
-
export { ASSET_REF_PREFIX, Accordion, AgentsPanel, AssetResolverProvider, AvatarBlock, Banner, BlockImage, CTABanner, Callout, Columns, ConnectionProvider, ContactForm, Container, DataTable, DataTableBlock, EmptyState, FAQ, FeatureGrid, Footer, Gallery, GridView, Hero, LegalArbiProvider, ListBlock, LogoCloud, MediaText, MetricCard, ModuleManager, Navbar, PageHeader, PageRenderer, PricingTable, RichTextBlock, Section, SectionHeading, Spacer, StatGroup, Steps, StudioEditor, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, Toolbar, VerticalBuilder, VideoEmbed, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearThemeVars, createAgentSelectionStore, createAiFields, createArbiBlocksConfig, createArbiMaterializer, createBlockKit, createImageField, createModuleRegistry, createModuleStore, createPromptLibrary, createSiteBlocks, createStudioPersistence, createThemeStore, createVerticalExport, createWebsiteBlocks, daysUntil, fmtDate, fmtDateTime, fromNow, gbp, hrs, iconMap, initials, isAssetRef, isAuthenticated, materializePageData, matterToContext, pct, tid, toEmbedUrl, toHslTriplet, useAssetResolverActive, useConnection, useFirmAiTask, useImageGen, useSemanticSearch, useWorkspaceDocs };
|
|
5453
|
+
export { ASSET_REF_PREFIX, Accordion, AgentsPanel, AppShell, AssetResolverProvider, AvatarBlock, Banner, BlockImage, CTABanner, Callout, Columns, ConnectionProvider, ContactForm, Container, DataTable, DataTableBlock, EmptyState, FAQ, FeatureGrid, Footer, Gallery, GridView, Hero, LegalArbiProvider, ListBlock, LiveDataProvider, LogoCloud, MediaText, MetricCard, ModuleManager, Navbar, PageHeader, PageRenderer, PricingTable, RichTextBlock, Section, SectionHeading, Spacer, StatGroup, Steps, StudioEditor, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, Toolbar, VerticalBuilder, VideoEmbed, WidgetPlaceholder, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearThemeVars, createAgentSelectionStore, createAiFields, createArbiBlocksConfig, createArbiMaterializer, createBlockKit, createImageField, createLiveWidgets, createModuleRegistry, createModuleStore, createPromptLibrary, createSiteBlocks, createStudioPersistence, createThemeStore, createVerticalExport, createWebsiteBlocks, daysUntil, fmtDate, fmtDateTime, fromNow, gbp, hrs, iconMap, initials, isAssetRef, isAuthenticated, materializePageData, matterToContext, pct, tid, toEmbedUrl, toHslTriplet, useAssetResolverActive, useConnection, useFirmAiTask, useImageGen, useLiveDataActive, useSemanticSearch, useWorkspaceDocs };
|
|
5054
5454
|
//# sourceMappingURL=index.js.map
|
|
5055
5455
|
//# sourceMappingURL=index.js.map
|