@tangle-network/sandbox-ui 0.2.1 → 0.3.3

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.
Files changed (68) hide show
  1. package/README.md +201 -10
  2. package/dist/auth.js +2 -2
  3. package/dist/chat-container-C8eHLw8z.d.ts +67 -0
  4. package/dist/chat.d.ts +70 -78
  5. package/dist/chat.js +8 -8
  6. package/dist/chunk-4F2GJRGU.js +756 -0
  7. package/dist/{chunk-HYEAX3DC.js → chunk-5LV6DZZF.js} +445 -114
  8. package/dist/chunk-67C53XVV.js +1106 -0
  9. package/dist/{chunk-QSQBDR3N.js → chunk-BX6AQMUS.js} +5 -2
  10. package/dist/chunk-CCKNIAS7.js +124 -0
  11. package/dist/chunk-CJ2RYVZH.js +128 -0
  12. package/dist/{chunk-KMXV7DDX.js → chunk-CNWVHQFY.js} +1 -1
  13. package/dist/{chunk-OU4TRNQZ.js → chunk-COCSO7FG.js} +3 -3
  14. package/dist/chunk-FJSVPBKY.js +85 -0
  15. package/dist/chunk-FRGMMANX.js +102 -0
  16. package/dist/{chunk-E6FS7R4X.js → chunk-HWLX5NME.js} +1 -1
  17. package/dist/chunk-JF6E2DS5.js +610 -0
  18. package/dist/chunk-MUOL44AE.js +121 -0
  19. package/dist/chunk-MXCSSOGH.js +105 -0
  20. package/dist/{chunk-J4OADEUK.js → chunk-OM6ON27W.js} +24 -9
  21. package/dist/{chunk-NI2EI43H.js → chunk-PDV7W4NY.js} +9 -124
  22. package/dist/chunk-TQN3VR4F.js +92 -0
  23. package/dist/{chunk-SOT2V7TX.js → chunk-TXI4MZAZ.js} +62 -144
  24. package/dist/chunk-WUR652Y3.js +1140 -0
  25. package/dist/chunk-YDBXQQLC.js +336 -0
  26. package/dist/{chunk-4EIWPJMJ.js → chunk-ZP6GSX4D.js} +36 -27
  27. package/dist/dashboard.d.ts +5 -2
  28. package/dist/dashboard.js +5 -4
  29. package/dist/{expanded-tool-detail-OkXGqTHe.d.ts → expanded-tool-detail-BDi_h_dZ.d.ts} +11 -4
  30. package/dist/file-tabs-CmaoDVBI.d.ts +72 -0
  31. package/dist/files.d.ts +25 -44
  32. package/dist/files.js +8 -3
  33. package/{src/styles → dist}/globals.css +16 -67
  34. package/dist/hooks.d.ts +5 -4
  35. package/dist/hooks.js +14 -9
  36. package/dist/index.d.ts +38 -9
  37. package/dist/index.js +100 -126
  38. package/dist/markdown.d.ts +1 -24
  39. package/dist/markdown.js +1 -7
  40. package/dist/openui.d.ts +115 -0
  41. package/dist/openui.js +11 -0
  42. package/dist/pages.d.ts +3 -2
  43. package/dist/pages.js +19 -16
  44. package/dist/primitives.d.ts +8 -1
  45. package/dist/primitives.js +25 -19
  46. package/dist/run.d.ts +2 -2
  47. package/dist/run.js +8 -7
  48. package/dist/{use-sidecar-auth-Bb0-w3lX.d.ts → sdk-hooks.d.ts} +61 -72
  49. package/dist/sdk-hooks.js +29 -0
  50. package/dist/styles.css +179 -0
  51. package/dist/tokens.css +165 -0
  52. package/dist/{tool-display-BvsVW_Ur.d.ts → tool-display-Ct9nFAzJ.d.ts} +1 -1
  53. package/dist/types.d.ts +1 -1
  54. package/dist/{usage-chart-DINgSVL5.d.ts → usage-chart-CY9xo3KX.d.ts} +8 -3
  55. package/dist/use-pty-session-DeZSxOCN.d.ts +69 -0
  56. package/dist/utils.d.ts +1 -1
  57. package/dist/utils.js +1 -1
  58. package/dist/workspace.d.ts +171 -33
  59. package/dist/workspace.js +25 -1
  60. package/package.json +10 -3
  61. package/dist/chunk-2UHPE5T7.js +0 -201
  62. package/dist/chunk-6MQIDUPA.js +0 -502
  63. package/dist/chunk-KYY2X6LY.js +0 -318
  64. package/dist/chunk-L6ZDH5F4.js +0 -334
  65. package/dist/chunk-M34OA6PQ.js +0 -233
  66. package/dist/chunk-M6VLC32S.js +0 -219
  67. package/dist/chunk-U62G5TS7.js +0 -472
  68. package/src/styles/tokens.css +0 -73
@@ -16,7 +16,7 @@ function extractCommand(input) {
16
16
  return extractString(input, "command") ?? extractString(input, "cmd");
17
17
  }
18
18
  function extractFilePath(input) {
19
- return extractString(input, "file_path") ?? extractString(input, "path") ?? extractString(input, "filePath");
19
+ return extractString(input, "file_path") ?? extractString(input, "path") ?? extractString(input, "filePath") ?? extractString(input, "file");
20
20
  }
21
21
  function cleanPath(path) {
22
22
  const parts = path.split("/");
@@ -108,6 +108,7 @@ function getToolDisplayMetadata(part) {
108
108
  description: filePath,
109
109
  hasDiffOutput: true,
110
110
  diffFilePath: filePath,
111
+ displayVariant: "diff",
111
112
  targetPath: filePath
112
113
  };
113
114
  case "read":
@@ -116,6 +117,7 @@ function getToolDisplayMetadata(part) {
116
117
  return {
117
118
  title: filePath ? `Read ${cleanPath(filePath)}` : "Read file",
118
119
  description: filePath,
120
+ displayVariant: "read-file",
119
121
  targetPath: filePath
120
122
  };
121
123
  case "grep":
@@ -159,7 +161,8 @@ function getToolDisplayMetadata(part) {
159
161
  }
160
162
  default:
161
163
  return {
162
- title: part.tool || "Tool"
164
+ title: part.tool || "Tool",
165
+ description: command ?? filePath ?? extractString(input, "pattern") ?? extractString(input, "query")
163
166
  };
164
167
  }
165
168
  }
@@ -0,0 +1,124 @@
1
+ import {
2
+ ToolCallGroup,
3
+ ToolCallStep
4
+ } from "./chunk-CJ2RYVZH.js";
5
+ import {
6
+ Markdown
7
+ } from "./chunk-LTFK464G.js";
8
+ import {
9
+ cn
10
+ } from "./chunk-RQHJBTEU.js";
11
+
12
+ // src/run/tool-call-feed.tsx
13
+ import { jsx } from "react/jsx-runtime";
14
+ function ToolCallFeed({ segments, className }) {
15
+ if (segments.length === 0) return null;
16
+ return /* @__PURE__ */ jsx("div", { className: cn("space-y-1", className), children: segments.map((segment, i) => {
17
+ if (segment.kind === "text") {
18
+ return segment.content.trim() ? /* @__PURE__ */ jsx(Markdown, { children: segment.content }, i) : null;
19
+ }
20
+ if (segment.kind === "tool_call") {
21
+ return /* @__PURE__ */ jsx(
22
+ ToolCallStep,
23
+ {
24
+ type: segment.call.type,
25
+ label: segment.call.label,
26
+ status: segment.call.status,
27
+ detail: segment.call.detail,
28
+ output: segment.call.output,
29
+ duration: segment.call.duration
30
+ },
31
+ segment.call.id || i
32
+ );
33
+ }
34
+ if (segment.kind === "tool_group") {
35
+ return /* @__PURE__ */ jsx(ToolCallGroup, { title: segment.title, children: segment.calls.map((call) => /* @__PURE__ */ jsx(
36
+ ToolCallStep,
37
+ {
38
+ type: call.type,
39
+ label: call.label,
40
+ status: call.status,
41
+ detail: call.detail,
42
+ output: call.output,
43
+ duration: call.duration
44
+ },
45
+ call.id
46
+ )) }, i);
47
+ }
48
+ return null;
49
+ }) });
50
+ }
51
+ function parseToolEvent(event) {
52
+ const { type, data } = event;
53
+ if (type === "tool.invocation" || type === "tool_use") {
54
+ const toolName = data.name || data.tool || "unknown";
55
+ const input = data.input;
56
+ return {
57
+ id: data.id || data.toolUseId || crypto.randomUUID(),
58
+ type: mapToolName(toolName),
59
+ label: formatToolLabel(toolName, input),
60
+ status: "running",
61
+ detail: input ? formatToolInput(toolName, input) : void 0
62
+ };
63
+ }
64
+ if (type === "tool.result" || type === "tool_result") {
65
+ return {
66
+ id: data.id || data.toolUseId || "",
67
+ type: mapToolName(data.name || data.tool || "unknown"),
68
+ label: formatToolLabel(data.name || data.tool || "unknown"),
69
+ status: data.error ? "error" : "success",
70
+ output: truncate(data.output || data.result || "", 500),
71
+ duration: data.duration
72
+ };
73
+ }
74
+ return null;
75
+ }
76
+ function mapToolName(name) {
77
+ const lower = name.toLowerCase();
78
+ if (lower.includes("bash") || lower.includes("terminal") || lower.includes("exec")) return "bash";
79
+ if (lower.includes("read") || lower.includes("cat")) return "read";
80
+ if (lower.includes("write") || lower.includes("create")) return "write";
81
+ if (lower.includes("edit") || lower.includes("replace")) return "edit";
82
+ if (lower.includes("glob") || lower.includes("find")) return "glob";
83
+ if (lower.includes("grep") || lower.includes("search")) return "grep";
84
+ if (lower.includes("list") || lower.includes("ls")) return "list";
85
+ if (lower.includes("inspect")) return "inspect";
86
+ if (lower.includes("audit")) return "audit";
87
+ return "unknown";
88
+ }
89
+ function formatToolLabel(toolName, input) {
90
+ const lower = toolName.toLowerCase();
91
+ if (lower.includes("bash") && input?.command) {
92
+ const cmd = String(input.command);
93
+ return cmd.length > 80 ? `${cmd.slice(0, 77)}...` : cmd;
94
+ }
95
+ if ((lower.includes("read") || lower.includes("cat")) && input?.path) {
96
+ return `Read ${input.path}`;
97
+ }
98
+ if (lower.includes("write") && input?.path) {
99
+ return `Write ${input.path}`;
100
+ }
101
+ if (lower.includes("edit") && input?.path) {
102
+ return `Edit ${input.path}`;
103
+ }
104
+ if (lower.includes("glob") && input?.pattern) {
105
+ return `Find ${input.pattern}`;
106
+ }
107
+ if (lower.includes("grep") && input?.pattern) {
108
+ return `Search for ${input.pattern}`;
109
+ }
110
+ return toolName;
111
+ }
112
+ function formatToolInput(toolName, input) {
113
+ if (input.command) return String(input.command);
114
+ if (input.path) return String(input.path);
115
+ return JSON.stringify(input, null, 2).slice(0, 300);
116
+ }
117
+ function truncate(text, max) {
118
+ return text.length > max ? text.slice(0, max - 3) + "..." : text;
119
+ }
120
+
121
+ export {
122
+ ToolCallFeed,
123
+ parseToolEvent
124
+ };
@@ -0,0 +1,128 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/run/tool-call-step.tsx
6
+ import { useState } from "react";
7
+ import {
8
+ Terminal,
9
+ FileText,
10
+ FileCode,
11
+ Search,
12
+ CheckCircle,
13
+ ChevronRight,
14
+ Loader2,
15
+ FolderOpen,
16
+ Download,
17
+ Pencil,
18
+ Eye
19
+ } from "lucide-react";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ var ICONS = {
22
+ bash: Terminal,
23
+ read: Eye,
24
+ write: FileText,
25
+ edit: Pencil,
26
+ glob: FolderOpen,
27
+ grep: Search,
28
+ list: FolderOpen,
29
+ download: Download,
30
+ inspect: Search,
31
+ audit: CheckCircle,
32
+ unknown: FileCode
33
+ };
34
+ var STATUS_COLORS = {
35
+ running: "text-[var(--brand-cool)]",
36
+ success: "text-[var(--code-success)]",
37
+ error: "text-[var(--code-error)]"
38
+ };
39
+ function ToolCallStep({
40
+ type,
41
+ label,
42
+ status,
43
+ detail,
44
+ output,
45
+ duration,
46
+ className
47
+ }) {
48
+ const [expanded, setExpanded] = useState(false);
49
+ const Icon = ICONS[type] || ICONS.unknown;
50
+ const hasExpandable = !!(detail || output);
51
+ return /* @__PURE__ */ jsxs(
52
+ "div",
53
+ {
54
+ className: cn(
55
+ "group overflow-hidden rounded-[var(--radius-lg)] border bg-[var(--bg-card)] transition-colors",
56
+ status === "running" && "border-[var(--border-accent)]",
57
+ status === "success" && "border-[var(--border-subtle)] hover:border-[var(--border-accent)]",
58
+ status === "error" && "border-red-500/30",
59
+ className
60
+ ),
61
+ children: [
62
+ /* @__PURE__ */ jsxs(
63
+ "button",
64
+ {
65
+ onClick: () => hasExpandable && setExpanded(!expanded),
66
+ disabled: !hasExpandable,
67
+ className: cn(
68
+ "flex w-full items-center gap-3 px-3 py-3 text-left text-sm",
69
+ hasExpandable && "cursor-pointer"
70
+ ),
71
+ children: [
72
+ /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ className: cn(
76
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
77
+ status === "running" && "border-[var(--border-accent)] bg-[var(--brand-cool)]/12 text-[var(--brand-cool)]",
78
+ status === "success" && "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
79
+ status === "error" && "border-red-500/30 bg-red-500/10 text-red-200"
80
+ ),
81
+ children: status === "running" ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsx(Icon, { className: cn("h-4 w-4 shrink-0", STATUS_COLORS[status]) })
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsx("span", { className: "truncate flex-1 font-[var(--font-sans)] text-[var(--text-secondary)]", children: label }),
85
+ /* @__PURE__ */ jsx(
86
+ "span",
87
+ {
88
+ className: cn(
89
+ "rounded-full border px-2 py-0.5 text-[11px] font-semibold uppercase tracking-[0.06em]",
90
+ status === "running" && "border-[var(--border-accent)] bg-[var(--brand-cool)]/10 text-[var(--brand-cool)]",
91
+ status === "success" && "border-emerald-500/30 bg-emerald-500/10 text-emerald-200",
92
+ status === "error" && "border-red-500/30 bg-red-500/10 text-red-200"
93
+ ),
94
+ children: status
95
+ }
96
+ ),
97
+ duration !== void 0 && status !== "running" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-[var(--text-muted)]", children: duration < 1e3 ? `${duration}ms` : `${(duration / 1e3).toFixed(1)}s` }),
98
+ hasExpandable && /* @__PURE__ */ jsx(
99
+ ChevronRight,
100
+ {
101
+ className: cn(
102
+ "h-3 w-3 text-[var(--text-muted)] transition-transform shrink-0",
103
+ expanded && "rotate-90"
104
+ )
105
+ }
106
+ )
107
+ ]
108
+ }
109
+ ),
110
+ expanded && (detail || output) && /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-[var(--border-subtle)] bg-[var(--bg-section)]/50 px-4 py-4", children: [
111
+ detail && /* @__PURE__ */ jsx("div", { className: "text-xs font-[var(--font-mono)] text-[var(--text-muted)]", children: detail }),
112
+ output && /* @__PURE__ */ jsx("pre", { className: "max-h-48 overflow-x-auto rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-input)] p-3 text-xs font-[var(--font-mono)] text-[var(--text-secondary)]", children: output })
113
+ ] })
114
+ ]
115
+ }
116
+ );
117
+ }
118
+ function ToolCallGroup({ title, children, className }) {
119
+ return /* @__PURE__ */ jsxs("div", { className: cn("my-2 space-y-2", className), children: [
120
+ title && /* @__PURE__ */ jsx("div", { className: "mb-1 px-1 text-xs font-medium uppercase tracking-wider text-[var(--text-muted)]", children: title }),
121
+ children
122
+ ] });
123
+ }
124
+
125
+ export {
126
+ ToolCallStep,
127
+ ToolCallGroup
128
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getToolCategory
3
- } from "./chunk-QSQBDR3N.js";
3
+ } from "./chunk-BX6AQMUS.js";
4
4
 
5
5
  // src/hooks/use-run-groups.ts
6
6
  import { useMemo } from "react";
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-MCGKDCOR.js";
14
14
  import {
15
15
  Button
16
- } from "./chunk-E6FS7R4X.js";
16
+ } from "./chunk-HWLX5NME.js";
17
17
  import {
18
18
  cn
19
19
  } from "./chunk-RQHJBTEU.js";
@@ -71,7 +71,7 @@ function UserMenu({
71
71
  }) {
72
72
  const initials = user.name ? user.name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : user.email.slice(0, 2).toUpperCase();
73
73
  const avatarGradient = {
74
- sandbox: "from-purple-500 to-violet-500"
74
+ sandbox: "bg-[image:var(--accent-gradient-strong)]"
75
75
  }[variant];
76
76
  const handleLogout = () => {
77
77
  if (onLogout) {
@@ -92,7 +92,7 @@ function UserMenu({
92
92
  AvatarFallback,
93
93
  {
94
94
  className: cn(
95
- "bg-gradient-to-r text-white text-xs",
95
+ "text-white text-xs",
96
96
  avatarGradient
97
97
  ),
98
98
  children: initials
@@ -0,0 +1,85 @@
1
+ // src/hooks/use-auth.ts
2
+ import * as React from "react";
3
+ function useAuth({
4
+ apiBaseUrl,
5
+ revalidateOnFocus = false,
6
+ shouldRetryOnError = false
7
+ }) {
8
+ const [user, setUser] = React.useState(null);
9
+ const [isLoading, setIsLoading] = React.useState(true);
10
+ const [error, setError] = React.useState(null);
11
+ const fetchSession = React.useCallback(async () => {
12
+ setIsLoading(true);
13
+ setError(null);
14
+ try {
15
+ const res = await fetch(`${apiBaseUrl}/auth/session`, {
16
+ credentials: "include"
17
+ });
18
+ if (!res.ok) {
19
+ throw new Error("Not authenticated");
20
+ }
21
+ const data = await res.json();
22
+ if (data.success && data.data) {
23
+ setUser(data.data);
24
+ } else {
25
+ setUser(null);
26
+ }
27
+ } catch (err) {
28
+ setError(err instanceof Error ? err : new Error("Unknown error"));
29
+ setUser(null);
30
+ if (shouldRetryOnError) {
31
+ setTimeout(fetchSession, 5e3);
32
+ }
33
+ } finally {
34
+ setIsLoading(false);
35
+ }
36
+ }, [apiBaseUrl, shouldRetryOnError]);
37
+ React.useEffect(() => {
38
+ fetchSession();
39
+ }, [fetchSession]);
40
+ React.useEffect(() => {
41
+ if (!revalidateOnFocus) return;
42
+ const handleFocus = () => {
43
+ fetchSession();
44
+ };
45
+ window.addEventListener("focus", handleFocus);
46
+ return () => window.removeEventListener("focus", handleFocus);
47
+ }, [revalidateOnFocus, fetchSession]);
48
+ return {
49
+ user,
50
+ isLoading,
51
+ isError: !!error,
52
+ error,
53
+ mutate: fetchSession
54
+ };
55
+ }
56
+ function createAuthFetcher(_apiBaseUrl) {
57
+ return async function authFetcher(url, options) {
58
+ const res = await fetch(url, {
59
+ ...options,
60
+ credentials: "include",
61
+ headers: {
62
+ ...options?.headers
63
+ }
64
+ });
65
+ if (!res.ok) {
66
+ throw new Error(`Request failed with status ${res.status}`);
67
+ }
68
+ return res.json();
69
+ };
70
+ }
71
+ function useApiKey() {
72
+ const [apiKey, setApiKey] = React.useState(null);
73
+ React.useEffect(() => {
74
+ if (typeof window !== "undefined") {
75
+ setApiKey(localStorage.getItem("apiKey"));
76
+ }
77
+ }, []);
78
+ return apiKey;
79
+ }
80
+
81
+ export {
82
+ useAuth,
83
+ createAuthFetcher,
84
+ useApiKey
85
+ };
@@ -0,0 +1,102 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/primitives/progress.tsx
6
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ var Progress = React.forwardRef(
10
+ ({ className, value, variant = "default", showValue = false, ...props }, ref) => {
11
+ const indicatorVariants = {
12
+ default: "bg-primary",
13
+ sandbox: "bg-[image:var(--accent-gradient-strong)]"
14
+ };
15
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
16
+ /* @__PURE__ */ jsx(
17
+ ProgressPrimitive.Root,
18
+ {
19
+ ref,
20
+ className: cn(
21
+ "relative h-2 w-full overflow-hidden rounded-full bg-muted",
22
+ className
23
+ ),
24
+ ...props,
25
+ children: /* @__PURE__ */ jsx(
26
+ ProgressPrimitive.Indicator,
27
+ {
28
+ className: cn(
29
+ "h-full w-full flex-1 transition-all duration-300 ease-out",
30
+ indicatorVariants[variant]
31
+ ),
32
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
33
+ }
34
+ )
35
+ }
36
+ ),
37
+ showValue && /* @__PURE__ */ jsxs("span", { className: "absolute -top-6 right-0 text-muted-foreground text-xs", children: [
38
+ value,
39
+ "%"
40
+ ] })
41
+ ] });
42
+ }
43
+ );
44
+ Progress.displayName = ProgressPrimitive.Root.displayName;
45
+
46
+ // src/primitives/skeleton.tsx
47
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
48
+ function Skeleton({
49
+ className,
50
+ ...props
51
+ }) {
52
+ return /* @__PURE__ */ jsx2(
53
+ "div",
54
+ {
55
+ className: cn("animate-pulse rounded-lg bg-muted", className),
56
+ ...props
57
+ }
58
+ );
59
+ }
60
+ function SkeletonCard({ className }) {
61
+ return /* @__PURE__ */ jsxs2(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "space-y-4 rounded-xl border border-border bg-card p-6",
66
+ className
67
+ ),
68
+ children: [
69
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-3/4" }),
70
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/2" }),
71
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2 pt-4", children: [
72
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-full" }),
73
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-5/6" }),
74
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-4/6" })
75
+ ] })
76
+ ]
77
+ }
78
+ );
79
+ }
80
+ function SkeletonTable({ rows = 5 }) {
81
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
82
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-4 border-border border-b pb-2", children: [
83
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
84
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
85
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
86
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" })
87
+ ] }),
88
+ Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs2("div", { className: "flex gap-4", children: [
89
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
90
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
91
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
92
+ /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" })
93
+ ] }, i))
94
+ ] });
95
+ }
96
+
97
+ export {
98
+ Progress,
99
+ Skeleton,
100
+ SkeletonCard,
101
+ SkeletonTable
102
+ };
@@ -18,7 +18,7 @@ var buttonVariants = cva(
18
18
  secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 active:scale-[0.98]",
19
19
  ghost: "hover:bg-accent hover:text-accent-foreground",
20
20
  link: "text-primary underline-offset-4 hover:underline",
21
- sandbox: "bg-gradient-to-r from-purple-600 to-violet-500 text-white shadow-lg shadow-purple-500/25 hover:from-purple-700 hover:to-violet-600 hover:shadow-purple-500/40 active:scale-[0.98]"
21
+ sandbox: "bg-[image:var(--accent-gradient-strong)] text-white shadow-[var(--shadow-accent)] hover:brightness-110 active:scale-[0.98]"
22
22
  },
23
23
  size: {
24
24
  default: "h-10 px-4 py-2",