@tangle-network/sandbox-ui 0.3.3 → 0.3.4

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.
@@ -248,7 +248,7 @@ function WorkspaceLayout({
248
248
  "data-sandbox-theme": theme,
249
249
  "data-density": density,
250
250
  className: cn(
251
- "flex h-screen flex-col overflow-hidden bg-[radial-gradient(circle_at_top,rgba(98,114,243,0.14),transparent_34%),linear-gradient(180deg,var(--bg-root),var(--bg-dark)_82%)] text-[var(--text-primary)] font-[var(--font-sans)]",
251
+ "flex h-screen flex-col overflow-hidden bg-[var(--bg-root)] text-[var(--text-primary)] font-[var(--font-sans)]",
252
252
  className
253
253
  ),
254
254
  children: [
@@ -1,114 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ export { A as AppSidebar, a as AppSidebarProps, B as Backend, b as BackendSelector, c as BackendSelectorProps, C as ClusterStatusBar, d as ClusterStatusBarProps, e as ClusterStatusItem, D as DashboardLayout, f as DashboardLayoutProps, v as DashboardProfile, g as DashboardUser, N as NavItem, h as NewSandboxCard, i as NewSandboxCardProps, w as ProductVariant, P as ProfileComparison, j as ProfileComparisonProps, k as ProfileSelector, l as ProfileSelectorProps, R as ResourceMeter, m as ResourceMeterProps, S as SandboxCard, n as SandboxCardData, o as SandboxCardProps, p as SandboxStatus, q as SandboxTable, r as SandboxTableProps, s as SidebarNavItem, t as SidebarSandbox, x as Variant, V as VariantList, u as VariantListProps, y as VariantOutcome, z as VariantStatus } from './index-BOjBJwzD.js';
2
2
  export { a as BillingBalance, c as BillingDashboard, d as BillingDashboardProps, B as BillingSubscription, b as BillingUsage, e as PricingPage, f as PricingPageProps, P as PricingTier, g as UsageChart, h as UsageChartProps, U as UsageDataPoint } from './usage-chart-CY9xo3KX.js';
3
- import * as React from 'react';
4
-
5
- type ProductVariant = "sandbox";
6
- interface NavItem {
7
- id: string;
8
- label: string;
9
- href: string;
10
- icon: React.ComponentType<{
11
- className?: string;
12
- }>;
13
- }
14
- interface DashboardUser {
15
- email: string;
16
- name?: string;
17
- tier?: string;
18
- avatarUrl?: string;
19
- }
20
- interface DashboardLayoutProps {
21
- children: React.ReactNode;
22
- variant?: ProductVariant;
23
- navItems: NavItem[];
24
- activeNavId?: string;
25
- user?: DashboardUser | null;
26
- isLoading?: boolean;
27
- onLogout?: () => void;
28
- onSettingsClick?: () => void;
29
- settingsHref?: string;
30
- className?: string;
31
- sidebarClassName?: string;
32
- contentClassName?: string;
33
- /** Custom link component (e.g., Next.js Link). Use any type to support various router implementations. */
34
- LinkComponent?: React.ComponentType<any>;
35
- }
36
- declare function DashboardLayout({ children, variant, navItems, activeNavId, user, isLoading, onLogout, onSettingsClick, settingsHref, className, sidebarClassName, contentClassName, LinkComponent, }: DashboardLayoutProps): react_jsx_runtime.JSX.Element;
37
-
38
- interface Backend {
39
- type: string;
40
- label: string;
41
- description?: string;
42
- }
43
- interface BackendSelectorProps {
44
- backends: Backend[];
45
- selected: string[];
46
- onChange: (selected: string[]) => void;
47
- label?: string;
48
- hint?: string;
49
- multiSelect?: boolean;
50
- className?: string;
51
- }
52
- declare function BackendSelector({ backends, selected, onChange, label, hint, multiSelect, className, }: BackendSelectorProps): react_jsx_runtime.JSX.Element;
53
-
54
- interface Profile {
55
- id: string;
56
- name: string;
57
- description?: string;
58
- is_builtin?: boolean;
59
- extends?: string;
60
- model?: string;
61
- metrics?: {
62
- total_runs: number;
63
- success_rate: number;
64
- avg_duration_ms: number;
65
- };
66
- }
67
- interface ProfileSelectorProps {
68
- profiles: Profile[];
69
- selectedId?: string | null;
70
- onSelect: (profile: Profile | null) => void;
71
- onCreateClick?: () => void;
72
- onManageClick?: () => void;
73
- label?: string;
74
- placeholder?: string;
75
- showMetrics?: boolean;
76
- className?: string;
77
- }
78
- declare function ProfileSelector({ profiles, selectedId, onSelect, onCreateClick, onManageClick, label, placeholder, showMetrics, className, }: ProfileSelectorProps): react_jsx_runtime.JSX.Element;
79
- /**
80
- * Profile performance comparison card.
81
- * Shows metrics from multiple profiles side by side.
82
- */
83
- interface ProfileComparisonProps {
84
- profiles: Profile[];
85
- className?: string;
86
- }
87
- declare function ProfileComparison({ profiles, className, }: ProfileComparisonProps): react_jsx_runtime.JSX.Element | null;
88
-
89
- type VariantStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
90
- type VariantOutcome = "pending_review" | "accepted" | "rejected" | "merged_with_conflicts" | "expired";
91
- interface Variant {
92
- id: string;
93
- label: string;
94
- sublabel?: string;
95
- status: VariantStatus;
96
- outcome?: VariantOutcome;
97
- durationMs?: number;
98
- error?: string;
99
- summary?: string;
100
- /** Link to view variant details (e.g., chat UI) */
101
- detailsUrl?: string;
102
- }
103
- interface VariantListProps {
104
- variants: Variant[];
105
- selectedId?: string | null;
106
- onSelect?: (id: string) => void;
107
- onAccept?: (id: string) => void;
108
- onReject?: (id: string) => void;
109
- isActioning?: string | null;
110
- className?: string;
111
- }
112
- declare function VariantList({ variants, selectedId, onSelect, onAccept, onReject, isActioning, className, }: VariantListProps): react_jsx_runtime.JSX.Element;
113
-
114
- export { type Backend, BackendSelector, type BackendSelectorProps, DashboardLayout, type DashboardLayoutProps, type Profile as DashboardProfile, type DashboardUser, type NavItem, type ProductVariant, ProfileComparison, type ProfileComparisonProps, ProfileSelector, type ProfileSelectorProps, type Variant, VariantList, type VariantListProps, type VariantOutcome, type VariantStatus };
3
+ import 'react/jsx-runtime';
4
+ import 'react';
package/dist/dashboard.js CHANGED
@@ -1,10 +1,16 @@
1
1
  import {
2
+ AppSidebar,
2
3
  BackendSelector,
4
+ ClusterStatusBar,
3
5
  DashboardLayout,
6
+ NewSandboxCard,
4
7
  ProfileComparison,
5
8
  ProfileSelector,
9
+ ResourceMeter,
10
+ SandboxCard,
11
+ SandboxTable,
6
12
  VariantList
7
- } from "./chunk-OM6ON27W.js";
13
+ } from "./chunk-HY5IBRCE.js";
8
14
  import {
9
15
  BillingDashboard,
10
16
  PricingPage,
@@ -17,12 +23,18 @@ import "./chunk-MXCSSOGH.js";
17
23
  import "./chunk-HWLX5NME.js";
18
24
  import "./chunk-RQHJBTEU.js";
19
25
  export {
26
+ AppSidebar,
20
27
  BackendSelector,
21
28
  BillingDashboard,
29
+ ClusterStatusBar,
22
30
  DashboardLayout,
31
+ NewSandboxCard,
23
32
  PricingPage,
24
33
  ProfileComparison,
25
34
  ProfileSelector,
35
+ ResourceMeter,
36
+ SandboxCard,
37
+ SandboxTable,
26
38
  UsageChart,
27
39
  VariantList
28
40
  };
@@ -0,0 +1,219 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import './usage-chart-CY9xo3KX.js';
4
+
5
+ interface SidebarNavItem {
6
+ id: string;
7
+ label: string;
8
+ href: string;
9
+ icon: string;
10
+ badge?: string;
11
+ }
12
+ interface SidebarSandbox {
13
+ id: string;
14
+ name: string;
15
+ label?: string;
16
+ }
17
+ interface AppSidebarProps {
18
+ navItems: SidebarNavItem[];
19
+ activeNavId?: string;
20
+ sandboxes?: SidebarSandbox[];
21
+ activeSandboxId?: string;
22
+ onSandboxChange?: (id: string) => void;
23
+ onNewAgent?: () => void;
24
+ className?: string;
25
+ LinkComponent?: React.ComponentType<any>;
26
+ }
27
+ declare function AppSidebar({ navItems, activeNavId, sandboxes, activeSandboxId, onSandboxChange, onNewAgent, className, LinkComponent, }: AppSidebarProps): react_jsx_runtime.JSX.Element;
28
+
29
+ interface ClusterStatusItem {
30
+ icon: string;
31
+ label: string;
32
+ value: string;
33
+ valueClass?: string;
34
+ }
35
+ interface ClusterStatusBarProps {
36
+ items: ClusterStatusItem[];
37
+ latency?: string;
38
+ className?: string;
39
+ }
40
+ declare function ClusterStatusBar({ items, latency, className }: ClusterStatusBarProps): react_jsx_runtime.JSX.Element;
41
+
42
+ type ProductVariant = "sandbox";
43
+ interface NavItem {
44
+ id: string;
45
+ label: string;
46
+ href: string;
47
+ icon: React.ComponentType<{
48
+ className?: string;
49
+ }>;
50
+ /** Material icon name for Stitch sidebar (optional, falls back to icon component) */
51
+ materialIcon?: string;
52
+ }
53
+ interface DashboardUser {
54
+ email: string;
55
+ name?: string;
56
+ tier?: string;
57
+ avatarUrl?: string;
58
+ }
59
+ interface TopNavLink {
60
+ label: string;
61
+ href: string;
62
+ }
63
+ interface DashboardLayoutProps {
64
+ children: React.ReactNode;
65
+ variant?: ProductVariant;
66
+ navItems: NavItem[];
67
+ activeNavId?: string;
68
+ user?: DashboardUser | null;
69
+ isLoading?: boolean;
70
+ onLogout?: () => void;
71
+ onSettingsClick?: () => void;
72
+ settingsHref?: string;
73
+ onNewSandbox?: () => void;
74
+ className?: string;
75
+ sidebarClassName?: string;
76
+ contentClassName?: string;
77
+ topNavLinks?: TopNavLink[];
78
+ activeTopNavHref?: string;
79
+ sandboxName?: string;
80
+ sandboxLabel?: string;
81
+ /** Custom link component (e.g., Next.js Link). Use any type to support various router implementations. */
82
+ LinkComponent?: React.ComponentType<any>;
83
+ /** Footer content rendered at bottom of viewport */
84
+ footer?: React.ReactNode;
85
+ }
86
+ declare function DashboardLayout({ children, variant, navItems, activeNavId, user, isLoading, onLogout, onSettingsClick, settingsHref, onNewSandbox, className, sidebarClassName, contentClassName, topNavLinks, activeTopNavHref, sandboxName, sandboxLabel, LinkComponent, footer, }: DashboardLayoutProps): react_jsx_runtime.JSX.Element;
87
+
88
+ interface ResourceMeterProps {
89
+ label: string;
90
+ value: number;
91
+ max?: number;
92
+ unit?: string;
93
+ icon?: string;
94
+ className?: string;
95
+ }
96
+ declare function ResourceMeter({ label, value, max, unit, icon, className }: ResourceMeterProps): react_jsx_runtime.JSX.Element;
97
+
98
+ type SandboxStatus = "running" | "hibernating" | "provisioning" | "stopped" | "failed" | "archived";
99
+ interface SandboxCardData {
100
+ id: string;
101
+ name: string;
102
+ nodeId?: string;
103
+ status: SandboxStatus;
104
+ image?: string;
105
+ imageIcon?: React.ReactNode;
106
+ cpuPercent?: number;
107
+ ramUsed?: number;
108
+ ramTotal?: number;
109
+ provisioningMessage?: string;
110
+ provisioningPercent?: number;
111
+ archivedAt?: string;
112
+ }
113
+ interface SandboxCardProps {
114
+ sandbox: SandboxCardData;
115
+ onOpenIDE?: (id: string) => void;
116
+ onOpenTerminal?: (id: string) => void;
117
+ onWake?: (id: string) => void;
118
+ onRestore?: (id: string) => void;
119
+ className?: string;
120
+ }
121
+ declare function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, className }: SandboxCardProps): react_jsx_runtime.JSX.Element;
122
+ interface NewSandboxCardProps {
123
+ onClick?: () => void;
124
+ className?: string;
125
+ }
126
+ declare function NewSandboxCard({ onClick, className }: NewSandboxCardProps): react_jsx_runtime.JSX.Element;
127
+
128
+ interface SandboxTableProps {
129
+ sandboxes: SandboxCardData[];
130
+ page?: number;
131
+ pageSize?: number;
132
+ total?: number;
133
+ onPageChange?: (page: number) => void;
134
+ onOpenIDE?: (id: string) => void;
135
+ onOpenTerminal?: (id: string) => void;
136
+ onSSH?: (id: string) => void;
137
+ onWake?: (id: string) => void;
138
+ onMore?: (id: string) => void;
139
+ className?: string;
140
+ }
141
+ declare function SandboxTable({ sandboxes, page, pageSize, total, onPageChange, onOpenIDE, onOpenTerminal, onSSH, onWake, onMore, className, }: SandboxTableProps): react_jsx_runtime.JSX.Element;
142
+
143
+ interface Backend {
144
+ type: string;
145
+ label: string;
146
+ description?: string;
147
+ }
148
+ interface BackendSelectorProps {
149
+ backends: Backend[];
150
+ selected: string[];
151
+ onChange: (selected: string[]) => void;
152
+ label?: string;
153
+ hint?: string;
154
+ multiSelect?: boolean;
155
+ className?: string;
156
+ }
157
+ declare function BackendSelector({ backends, selected, onChange, label, hint, multiSelect, className, }: BackendSelectorProps): react_jsx_runtime.JSX.Element;
158
+
159
+ interface Profile {
160
+ id: string;
161
+ name: string;
162
+ description?: string;
163
+ is_builtin?: boolean;
164
+ extends?: string;
165
+ model?: string;
166
+ metrics?: {
167
+ total_runs: number;
168
+ success_rate: number;
169
+ avg_duration_ms: number;
170
+ };
171
+ }
172
+ interface ProfileSelectorProps {
173
+ profiles: Profile[];
174
+ selectedId?: string | null;
175
+ onSelect: (profile: Profile | null) => void;
176
+ onCreateClick?: () => void;
177
+ onManageClick?: () => void;
178
+ label?: string;
179
+ placeholder?: string;
180
+ showMetrics?: boolean;
181
+ className?: string;
182
+ }
183
+ declare function ProfileSelector({ profiles, selectedId, onSelect, onCreateClick, onManageClick, label, placeholder, showMetrics, className, }: ProfileSelectorProps): react_jsx_runtime.JSX.Element;
184
+ /**
185
+ * Profile performance comparison card.
186
+ * Shows metrics from multiple profiles side by side.
187
+ */
188
+ interface ProfileComparisonProps {
189
+ profiles: Profile[];
190
+ className?: string;
191
+ }
192
+ declare function ProfileComparison({ profiles, className, }: ProfileComparisonProps): react_jsx_runtime.JSX.Element | null;
193
+
194
+ type VariantStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
195
+ type VariantOutcome = "pending_review" | "accepted" | "rejected" | "merged_with_conflicts" | "expired";
196
+ interface Variant {
197
+ id: string;
198
+ label: string;
199
+ sublabel?: string;
200
+ status: VariantStatus;
201
+ outcome?: VariantOutcome;
202
+ durationMs?: number;
203
+ error?: string;
204
+ summary?: string;
205
+ /** Link to view variant details (e.g., chat UI) */
206
+ detailsUrl?: string;
207
+ }
208
+ interface VariantListProps {
209
+ variants: Variant[];
210
+ selectedId?: string | null;
211
+ onSelect?: (id: string) => void;
212
+ onAccept?: (id: string) => void;
213
+ onReject?: (id: string) => void;
214
+ isActioning?: string | null;
215
+ className?: string;
216
+ }
217
+ declare function VariantList({ variants, selectedId, onSelect, onAccept, onReject, isActioning, className, }: VariantListProps): react_jsx_runtime.JSX.Element;
218
+
219
+ export { AppSidebar as A, type Backend as B, ClusterStatusBar as C, DashboardLayout as D, type NavItem as N, ProfileComparison as P, ResourceMeter as R, SandboxCard as S, type TopNavLink as T, VariantList as V, type AppSidebarProps as a, BackendSelector as b, type BackendSelectorProps as c, type ClusterStatusBarProps as d, type ClusterStatusItem as e, type DashboardLayoutProps as f, type DashboardUser as g, NewSandboxCard as h, type NewSandboxCardProps as i, type ProfileComparisonProps as j, ProfileSelector as k, type ProfileSelectorProps as l, type ResourceMeterProps as m, type SandboxCardData as n, type SandboxCardProps as o, type SandboxStatus as p, SandboxTable as q, type SandboxTableProps as r, type SidebarNavItem as s, type SidebarSandbox as t, type VariantListProps as u, type Profile as v, type ProductVariant as w, type Variant as x, type VariantOutcome as y, type VariantStatus as z };
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export { E as ExpandedToolDetail, I as InlineThinkingItem, c as InlineToolItem,
13
13
  import { b as ToolPart } from './parts-CyGkM6Fp.js';
14
14
  export { R as ReasoningPart, S as SessionMessage, a as SessionPart, T as TextPart, c as ToolState, d as ToolStatus, e as ToolTime } from './parts-CyGkM6Fp.js';
15
15
  export { FileArtifactPane, FileArtifactPaneProps, FilePreview, FilePreviewProps } from './files.js';
16
- export { Backend, BackendSelector, BackendSelectorProps, DashboardLayout, DashboardLayoutProps, DashboardUser, NavItem, ProfileComparison, ProfileComparisonProps, ProfileSelector, ProfileSelectorProps, VariantList, VariantListProps } from './dashboard.js';
16
+ export { A as AppSidebar, a as AppSidebarProps, B as Backend, b as BackendSelector, c as BackendSelectorProps, C as ClusterStatusBar, d as ClusterStatusBarProps, e as ClusterStatusItem, D as DashboardLayout, f as DashboardLayoutProps, g as DashboardUser, N as NavItem, h as NewSandboxCard, i as NewSandboxCardProps, P as ProfileComparison, j as ProfileComparisonProps, k as ProfileSelector, l as ProfileSelectorProps, R as ResourceMeter, m as ResourceMeterProps, S as SandboxCard, n as SandboxCardData, o as SandboxCardProps, p as SandboxStatus, q as SandboxTable, r as SandboxTableProps, s as SidebarNavItem, t as SidebarSandbox, T as TopNavLink, V as VariantList, u as VariantListProps } from './index-BOjBJwzD.js';
17
17
  export { c as BillingDashboard, d as BillingDashboardProps, e as PricingCards, f as PricingPageProps, g as UsageChart, h as UsageChartProps, U as UsageDataPoint } from './usage-chart-CY9xo3KX.js';
18
18
  export { AuthHeader, GitHubLoginButton, UserMenu } from './auth.js';
19
19
  export { CodeBlock, CopyButton, Markdown, MarkdownProps } from './markdown.js';
package/dist/index.js CHANGED
@@ -80,7 +80,7 @@ import {
80
80
  StatusBar,
81
81
  TerminalPanel,
82
82
  WorkspaceLayout
83
- } from "./chunk-67C53XVV.js";
83
+ } from "./chunk-QGI5E7JD.js";
84
84
  import {
85
85
  EmptyState,
86
86
  Input,
@@ -156,14 +156,18 @@ import {
156
156
  Markdown
157
157
  } from "./chunk-LTFK464G.js";
158
158
  import {
159
+ AppSidebar,
159
160
  BackendSelector,
161
+ ClusterStatusBar,
160
162
  DashboardLayout,
163
+ NewSandboxCard,
161
164
  ProfileComparison,
162
165
  ProfileSelector,
163
- ThemeToggle,
164
- VariantList,
165
- useTheme
166
- } from "./chunk-OM6ON27W.js";
166
+ ResourceMeter,
167
+ SandboxCard,
168
+ SandboxTable,
169
+ VariantList
170
+ } from "./chunk-HY5IBRCE.js";
167
171
  import {
168
172
  BillingDashboard,
169
173
  PricingPage,
@@ -213,9 +217,95 @@ import {
213
217
  import {
214
218
  cn
215
219
  } from "./chunk-RQHJBTEU.js";
220
+
221
+ // src/primitives/theme-toggle.tsx
222
+ import { useCallback, useEffect, useState } from "react";
223
+ import { jsx, jsxs } from "react/jsx-runtime";
224
+ function getSystemTheme() {
225
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
226
+ }
227
+ function applyTheme(theme) {
228
+ const resolved = theme === "system" ? getSystemTheme() : theme;
229
+ document.documentElement.classList.toggle("dark", resolved === "dark");
230
+ }
231
+ function useTheme() {
232
+ const [theme, setThemeState] = useState(() => {
233
+ if (typeof window === "undefined") return "system";
234
+ return localStorage.getItem("theme") ?? "system";
235
+ });
236
+ const setTheme = useCallback((next) => {
237
+ setThemeState(next);
238
+ if (next === "system") {
239
+ localStorage.removeItem("theme");
240
+ } else {
241
+ localStorage.setItem("theme", next);
242
+ }
243
+ applyTheme(next);
244
+ }, []);
245
+ useEffect(() => {
246
+ applyTheme(theme);
247
+ if (theme !== "system") return;
248
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
249
+ const handler = () => applyTheme("system");
250
+ mq.addEventListener("change", handler);
251
+ return () => mq.removeEventListener("change", handler);
252
+ }, [theme]);
253
+ return { theme, setTheme };
254
+ }
255
+ var iconClass = "h-4 w-4";
256
+ function SunIcon() {
257
+ return /* @__PURE__ */ jsxs(
258
+ "svg",
259
+ {
260
+ xmlns: "http://www.w3.org/2000/svg",
261
+ viewBox: "0 0 24 24",
262
+ fill: "none",
263
+ stroke: "currentColor",
264
+ strokeWidth: 2,
265
+ strokeLinecap: "round",
266
+ strokeLinejoin: "round",
267
+ className: iconClass,
268
+ children: [
269
+ /* @__PURE__ */ jsx("circle", { cx: 12, cy: 12, r: 5 }),
270
+ /* @__PURE__ */ jsx("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
271
+ ]
272
+ }
273
+ );
274
+ }
275
+ function MoonIcon() {
276
+ return /* @__PURE__ */ jsx(
277
+ "svg",
278
+ {
279
+ xmlns: "http://www.w3.org/2000/svg",
280
+ viewBox: "0 0 24 24",
281
+ fill: "none",
282
+ stroke: "currentColor",
283
+ strokeWidth: 2,
284
+ strokeLinecap: "round",
285
+ strokeLinejoin: "round",
286
+ className: iconClass,
287
+ children: /* @__PURE__ */ jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
288
+ }
289
+ );
290
+ }
291
+ function ThemeToggle() {
292
+ const { theme, setTheme } = useTheme();
293
+ const resolved = theme === "system" ? getSystemTheme() : theme;
294
+ return /* @__PURE__ */ jsx(
295
+ "button",
296
+ {
297
+ type: "button",
298
+ onClick: () => setTheme(resolved === "dark" ? "light" : "dark"),
299
+ className: "inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors",
300
+ "aria-label": `Switch to ${resolved === "dark" ? "light" : "dark"} mode`,
301
+ children: resolved === "dark" ? /* @__PURE__ */ jsx(SunIcon, {}) : /* @__PURE__ */ jsx(MoonIcon, {})
302
+ }
303
+ );
304
+ }
216
305
  export {
217
306
  AgentTimeline,
218
307
  AgentWorkbench,
308
+ AppSidebar,
219
309
  ArtifactPane,
220
310
  AuditResults,
221
311
  AuthHeader,
@@ -235,6 +325,7 @@ export {
235
325
  ChatContainer,
236
326
  ChatInput,
237
327
  ChatMessage,
328
+ ClusterStatusBar,
238
329
  CodeBlock2 as CodeBlock,
239
330
  CodeBlock as CodeBlockDisplay,
240
331
  CommandPreview,
@@ -284,14 +375,18 @@ export {
284
375
  Logo,
285
376
  Markdown,
286
377
  MessageList,
378
+ NewSandboxCard,
287
379
  OpenUIArtifactRenderer,
288
380
  PricingPage as PricingCards,
289
381
  ProfileComparison,
290
382
  ProfileSelector,
291
383
  Progress,
292
384
  QuestionPreview,
385
+ ResourceMeter,
293
386
  RunGroup,
294
387
  RuntimePane,
388
+ SandboxCard,
389
+ SandboxTable,
295
390
  SandboxWorkbench,
296
391
  Select,
297
392
  SelectContent,
package/dist/tokens.css CHANGED
@@ -1,7 +1,41 @@
1
1
  /* Tangle Sandbox UI design tokens */
2
2
 
3
+ /* MD3 surface hierarchy — Stitch design system */
3
4
  :root,
4
5
  [data-sandbox-ui] {
6
+ --md3-surface: #12131a;
7
+ --md3-surface-dim: #12131a;
8
+ --md3-surface-bright: #383841;
9
+ --md3-surface-container-lowest: #0d0e15;
10
+ --md3-surface-container-low: #1a1b23;
11
+ --md3-surface-container: #1e1f27;
12
+ --md3-surface-container-high: #292931;
13
+ --md3-surface-container-highest: #34343c;
14
+ --md3-surface-variant: #34343c;
15
+ --md3-on-surface: #e3e1ec;
16
+ --md3-on-surface-variant: #ccc3d7;
17
+ --md3-primary: #d1bcff;
18
+ --md3-primary-container: #a178ff;
19
+ --md3-on-primary: #3c0090;
20
+ --md3-on-primary-container: #34007f;
21
+ --md3-primary-fixed: #e9ddff;
22
+ --md3-primary-fixed-dim: #d1bcff;
23
+ --md3-secondary: #b6c4ff;
24
+ --md3-secondary-container: #133eae;
25
+ --md3-on-secondary: #00277f;
26
+ --md3-on-secondary-container: #a3b5ff;
27
+ --md3-secondary-fixed: #dce1ff;
28
+ --md3-secondary-fixed-dim: #b6c4ff;
29
+ --md3-tertiary: #c7c5d0;
30
+ --md3-tertiary-container: #90909a;
31
+ --md3-outline: #958da1;
32
+ --md3-outline-variant: #4a4455;
33
+ --md3-error: #ffb4ab;
34
+ --md3-error-container: #93000a;
35
+ --md3-on-error: #690005;
36
+ --md3-inverse-surface: #e3e1ec;
37
+ --md3-inverse-primary: #6f35df;
38
+ --md3-surface-tint: #d1bcff;
5
39
  /* Semantic HSL bridge for shadcn/radix primitives */
6
40
  --hsl-background: 245 18% 7%;
7
41
  --hsl-foreground: 220 20% 96%;
@@ -60,7 +94,7 @@
60
94
  --accent-text: var(--brand-cool);
61
95
 
62
96
  /* Surfaces */
63
- --bg-root: hsl(var(--hsl-background));
97
+ --bg-root: radial-gradient(circle at top, rgba(98, 114, 243, 0.14), transparent 34%), linear-gradient(180deg, hsl(var(--hsl-background)), hsl(246 19% 9%) 82%);
64
98
  --bg-dark: hsl(246 19% 9%);
65
99
  --bg-card: hsl(var(--hsl-card));
66
100
  --bg-elevated: hsl(245 20% 12%);
@@ -155,6 +189,82 @@
155
189
  --accent-gradient-strong: linear-gradient(135deg, hsl(187 75% 48%), hsl(164 74% 56%));
156
190
  }
157
191
 
192
+ [data-sandbox-theme="vault"] {
193
+ /* Vault AI — navy/emerald fintech palette matching tangle.tools/taxes */
194
+ --hsl-background: 210 17% 97%;
195
+ --hsl-foreground: 210 20% 10%;
196
+ --hsl-card: 0 0% 100%;
197
+ --hsl-card-foreground: 210 20% 10%;
198
+ --hsl-popover: 0 0% 100%;
199
+ --hsl-popover-foreground: 210 20% 10%;
200
+ --hsl-primary: 212 100% 10%;
201
+ --hsl-primary-foreground: 0 0% 100%;
202
+ --hsl-secondary: 152 100% 22%;
203
+ --hsl-secondary-foreground: 0 0% 100%;
204
+ --hsl-muted: 210 14% 95%;
205
+ --hsl-muted-foreground: 215 10% 40%;
206
+ --hsl-accent: 210 20% 94%;
207
+ --hsl-accent-foreground: 210 20% 10%;
208
+ --hsl-destructive: 0 72% 41%;
209
+ --hsl-destructive-foreground: 0 0% 100%;
210
+ --hsl-border: 214 18% 88%;
211
+ --hsl-input: 214 18% 90%;
212
+ --hsl-ring: 152 100% 22%;
213
+ --hsl-success: 152 82% 34%;
214
+ --hsl-warning: 41 96% 50%;
215
+ --hsl-info: 212 80% 50%;
216
+
217
+ --bg-root: #f8f9fa;
218
+ --bg-dark: #f3f4f5;
219
+ --bg-card: #ffffff;
220
+ --bg-elevated: #edeeef;
221
+ --bg-section: #f3f4f5;
222
+ --bg-input: #f3f4f5;
223
+ --bg-hover: #e7e8e9;
224
+ --bg-selection: rgba(0, 110, 42, 0.08);
225
+
226
+ --text-primary: #001831;
227
+ --text-secondary: #43474e;
228
+ --text-muted: #73777f;
229
+
230
+ --brand-primary: #001831;
231
+ --brand-strong: #002d54;
232
+ --brand-cool: #006e2a;
233
+ --brand-glow: #3ce36a;
234
+ --brand-purple: #001831;
235
+ --brand-vibrant: #006e2a;
236
+
237
+ --border-subtle: rgba(0, 24, 49, 0.06);
238
+ --border-default: rgba(0, 24, 49, 0.1);
239
+ --border-hover: rgba(0, 24, 49, 0.15);
240
+ --border-accent: rgba(0, 110, 42, 0.2);
241
+ --border-accent-hover: rgba(0, 110, 42, 0.4);
242
+
243
+ --btn-primary-bg: #001831;
244
+ --btn-primary-hover: #002d54;
245
+ --btn-cta-bg: #006e2a;
246
+ --btn-cta-text: #ffffff;
247
+
248
+ --code-keyword: #002d54;
249
+ --code-string: #006e2a;
250
+ --code-function: #001831;
251
+ --code-number: #b45309;
252
+ --code-success: #006e2a;
253
+ --code-comment: #73777f;
254
+ --code-error: #ba1a1a;
255
+
256
+ --shadow-card: 0 20px 48px rgba(0, 24, 49, 0.06);
257
+ --shadow-dropdown: 0 24px 64px rgba(0, 24, 49, 0.12);
258
+ --shadow-glow: 0 0 40px rgba(0, 110, 42, 0.08);
259
+
260
+ --tangle-gradient: linear-gradient(135deg, #001831, #002d54);
261
+ --tangle-gradient-text: linear-gradient(135deg, #001831, #006e2a);
262
+ --accent-gradient-strong: linear-gradient(135deg, #001831, #002d54);
263
+
264
+ --font-sans: "Inter", "Manrope", ui-sans-serif, system-ui, sans-serif;
265
+ --font-mono: "JetBrains Mono", ui-monospace, monospace;
266
+ }
267
+
158
268
  [data-density="compact"] {
159
269
  --radius-sm: 8px;
160
270
  --radius-md: 12px;
@@ -48,7 +48,7 @@ interface WorkspaceLayoutProps {
48
48
  /** Disable resize handles */
49
49
  resizable?: boolean;
50
50
  /** Visual theme for sandbox surfaces */
51
- theme?: "operator" | "builder" | "consumer";
51
+ theme?: "operator" | "builder" | "consumer" | "vault";
52
52
  /** Density mode for control sizing */
53
53
  density?: "comfortable" | "compact";
54
54
  /** Accessible label for the left panel */