@tangle-network/sandbox-ui 0.14.0 → 0.15.1

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 (104) hide show
  1. package/dist/auth.d.ts +1 -74
  2. package/dist/auth.js +1 -4
  3. package/dist/chat.d.ts +1 -136
  4. package/dist/chat.js +2 -15
  5. package/dist/chunk-2BUPSB7O.js +0 -0
  6. package/dist/chunk-3J6FG3FJ.js +18 -0
  7. package/dist/chunk-76IQLPW2.js +206 -0
  8. package/dist/chunk-7ZA5SEK3.js +239 -0
  9. package/dist/chunk-AHBZCBDO.js +2960 -0
  10. package/dist/chunk-AZ3AWMTM.js +8 -0
  11. package/dist/chunk-CMY7W45U.js +380 -0
  12. package/dist/{chunk-QMU2PWOU.js → chunk-DNZ4DTNA.js} +71 -17
  13. package/dist/chunk-EI44GEQ5.js +6 -0
  14. package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
  15. package/dist/chunk-JBGKGLD7.js +16 -0
  16. package/dist/chunk-NJNME4J4.js +14 -0
  17. package/dist/chunk-QPAJR74X.js +20 -0
  18. package/dist/chunk-TK46XFLM.js +28 -0
  19. package/dist/chunk-WID73FPH.js +89 -0
  20. package/dist/chunk-YVXK4XRO.js +30 -0
  21. package/dist/dashboard.d.ts +538 -4
  22. package/dist/dashboard.js +15 -886
  23. package/dist/editor.d.ts +1 -120
  24. package/dist/editor.js +1 -5
  25. package/dist/files.d.ts +1 -129
  26. package/dist/files.js +2 -7
  27. package/dist/globals.css +2 -1265
  28. package/dist/hooks.d.ts +114 -11
  29. package/dist/hooks.js +17 -88
  30. package/dist/index.d.ts +24 -99
  31. package/dist/index.js +247 -252
  32. package/dist/markdown.d.ts +1 -29
  33. package/dist/markdown.js +2 -2
  34. package/dist/openui.d.ts +8 -115
  35. package/dist/openui.js +1 -6
  36. package/dist/pages.d.ts +1 -2
  37. package/dist/pages.js +68 -66
  38. package/dist/primitives.d.ts +14 -49
  39. package/dist/primitives.js +69 -77
  40. package/dist/run.d.ts +1 -14
  41. package/dist/run.js +2 -22
  42. package/dist/sdk-hooks.d.ts +3 -283
  43. package/dist/sdk-hooks.js +10 -14
  44. package/dist/stores.d.ts +2 -14
  45. package/dist/stores.js +11 -39
  46. package/dist/styles.css +2 -1265
  47. package/dist/{usage-chart-CPTcNlGs.d.ts → template-card-UhV3pmRC.d.ts} +16 -1
  48. package/dist/types.d.ts +11 -8
  49. package/dist/types.js +1 -0
  50. package/dist/utils.d.ts +1 -44
  51. package/dist/utils.js +6 -12
  52. package/dist/workspace.d.ts +5 -10
  53. package/dist/workspace.js +3 -19
  54. package/package.json +19 -54
  55. package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
  56. package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
  57. package/dist/branding-DCi5VEik.d.ts +0 -13
  58. package/dist/button-CMQuQEW_.d.ts +0 -17
  59. package/dist/chat-container-f4yEs6KN.d.ts +0 -106
  60. package/dist/chunk-34A66VBG.js +0 -214
  61. package/dist/chunk-34I7UFSX.js +0 -92
  62. package/dist/chunk-36QY2W5G.js +0 -802
  63. package/dist/chunk-4CLN43XT.js +0 -45
  64. package/dist/chunk-54SQQMMM.js +0 -156
  65. package/dist/chunk-66EZOYZR.js +0 -102
  66. package/dist/chunk-BX6AQMUS.js +0 -183
  67. package/dist/chunk-DI3NZ5ZX.js +0 -192
  68. package/dist/chunk-DPGIXDAI.js +0 -220
  69. package/dist/chunk-DXMIEK4K.js +0 -1426
  70. package/dist/chunk-GSZA3TSY.js +0 -79
  71. package/dist/chunk-HB5Y37YU.js +0 -54
  72. package/dist/chunk-LQNEZDRM.js +0 -109
  73. package/dist/chunk-MA7YKRUP.js +0 -131
  74. package/dist/chunk-MKTSMWVD.js +0 -109
  75. package/dist/chunk-MQXABZTB.js +0 -1348
  76. package/dist/chunk-MT5FJ3ZT.js +0 -186
  77. package/dist/chunk-NKUPJC34.js +0 -2070
  78. package/dist/chunk-OEX7NZE3.js +0 -321
  79. package/dist/chunk-OKLQVY3Y.js +0 -139
  80. package/dist/chunk-Q56BYXQF.js +0 -61
  81. package/dist/chunk-QD4QE5P5.js +0 -40
  82. package/dist/chunk-QDH5GEGY.js +0 -630
  83. package/dist/chunk-QID2OOMG.js +0 -133
  84. package/dist/chunk-RQHJBTEU.js +0 -10
  85. package/dist/chunk-T7HMZEVO.js +0 -216
  86. package/dist/chunk-U6QTHMY6.js +0 -1290
  87. package/dist/chunk-US6JKJKH.js +0 -124
  88. package/dist/chunk-VX3XOUEB.js +0 -63
  89. package/dist/chunk-XLG757B6.js +0 -933
  90. package/dist/chunk-ZMNSRDMH.js +0 -127
  91. package/dist/chunk-ZNCEM5CD.js +0 -316
  92. package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
  93. package/dist/document-editor-pane-TLPVRBBU.js +0 -11
  94. package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
  95. package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
  96. package/dist/parts-CyGkM6Fp.d.ts +0 -50
  97. package/dist/run-CtFZ6s-D.d.ts +0 -41
  98. package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
  99. package/dist/sidecar-CFU2W9j1.d.ts +0 -8
  100. package/dist/template-card-BAtvcAkU.d.ts +0 -18
  101. package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
  102. package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
  103. package/dist/use-sandbox-metrics-DWc0k9Xm.d.ts +0 -153
  104. package/dist/variant-list-BrHYcBCk.d.ts +0 -540
@@ -1,45 +0,0 @@
1
- // src/utils/format.ts
2
- function formatDuration(ms) {
3
- if (ms < 1e3) return "<1s";
4
- const seconds = Math.floor(ms / 1e3);
5
- if (seconds < 60) return `${seconds}s`;
6
- const minutes = Math.floor(seconds / 60);
7
- const remaining = seconds % 60;
8
- return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
9
- }
10
- function truncateText(text, max) {
11
- const cleaned = text.replace(/\s+/g, " ").trim();
12
- if (cleaned.length <= max) return cleaned;
13
- return cleaned.slice(0, max).trim() + "...";
14
- }
15
- function formatUptime(ms) {
16
- if (!Number.isFinite(ms) || ms < 0) return "\u2014";
17
- const totalSeconds = Math.floor(ms / 1e3);
18
- if (totalSeconds < 60) return `${totalSeconds}s`;
19
- const minutes = Math.floor(totalSeconds / 60);
20
- const seconds = totalSeconds % 60;
21
- if (minutes < 60) return `${minutes}m ${seconds}s`;
22
- const hours = Math.floor(minutes / 60);
23
- const remMinutes = minutes % 60;
24
- if (hours < 24) return `${hours}h ${remMinutes}m`;
25
- const days = Math.floor(hours / 24);
26
- const remHours = hours % 24;
27
- return `${days}d ${remHours}h`;
28
- }
29
- function formatBytes(bytes) {
30
- if (!Number.isFinite(bytes) || bytes < 0) return "\u2014";
31
- if (bytes < 1024) return `${Math.round(bytes)} B`;
32
- const kb = bytes / 1024;
33
- if (kb < 1024) return `${kb < 10 ? kb.toFixed(1) : Math.round(kb)} KB`;
34
- const mb = kb / 1024;
35
- if (mb < 1024) return `${mb < 10 ? mb.toFixed(1) : Math.round(mb)} MB`;
36
- const gb = mb / 1024;
37
- return `${gb < 10 ? gb.toFixed(2) : gb.toFixed(1)} GB`;
38
- }
39
-
40
- export {
41
- formatDuration,
42
- truncateText,
43
- formatUptime,
44
- formatBytes
45
- };
@@ -1,156 +0,0 @@
1
- import {
2
- getToolCategory
3
- } from "./chunk-BX6AQMUS.js";
4
-
5
- // src/hooks/use-run-groups.ts
6
- import { useMemo } from "react";
7
- function computeRunStats(messages, partMap) {
8
- const stats = {
9
- toolCount: 0,
10
- messageCount: messages.length,
11
- thinkingDurationMs: 0,
12
- textPartCount: 0,
13
- toolCategories: /* @__PURE__ */ new Set()
14
- };
15
- for (const msg of messages) {
16
- const parts = partMap[msg.id] ?? [];
17
- for (const part of parts) {
18
- switch (part.type) {
19
- case "tool":
20
- stats.toolCount++;
21
- stats.toolCategories.add(getToolCategory(part.tool));
22
- break;
23
- case "text":
24
- if (!part.synthetic) stats.textPartCount++;
25
- break;
26
- case "reasoning": {
27
- const start = part.time?.start;
28
- const end = part.time?.end;
29
- if (start && end) stats.thinkingDurationMs += end - start;
30
- break;
31
- }
32
- }
33
- }
34
- }
35
- return stats;
36
- }
37
- function getLastTextContent(messages, partMap) {
38
- for (let i = messages.length - 1; i >= 0; i--) {
39
- const parts = partMap[messages[i].id] ?? [];
40
- for (let j = parts.length - 1; j >= 0; j--) {
41
- const part = parts[j];
42
- if (part.type === "text" && !part.synthetic && part.text.trim()) {
43
- return part.text.trim();
44
- }
45
- }
46
- }
47
- return null;
48
- }
49
- function useRunGroups({
50
- messages,
51
- partMap,
52
- isStreaming
53
- }) {
54
- return useMemo(() => {
55
- const groups = [];
56
- let currentRunMessages = [];
57
- function flushRun(streaming) {
58
- if (currentRunMessages.length === 0) return;
59
- const msgs = [...currentRunMessages];
60
- const stats = computeRunStats(msgs, partMap);
61
- const summaryText = getLastTextContent(msgs, partMap);
62
- const isComplete = !streaming;
63
- groups.push({
64
- type: "run",
65
- run: {
66
- id: msgs[0].id,
67
- messages: msgs,
68
- isComplete,
69
- isStreaming: streaming,
70
- stats,
71
- summaryText,
72
- finalTextPart: null
73
- }
74
- });
75
- currentRunMessages = [];
76
- }
77
- for (let i = 0; i < messages.length; i++) {
78
- const msg = messages[i];
79
- if (msg.role === "user") {
80
- flushRun(false);
81
- groups.push({ type: "user", message: msg });
82
- } else {
83
- currentRunMessages.push(msg);
84
- }
85
- }
86
- if (currentRunMessages.length > 0) {
87
- flushRun(isStreaming);
88
- }
89
- return groups;
90
- }, [messages, partMap, isStreaming]);
91
- }
92
-
93
- // src/hooks/use-run-collapse-state.ts
94
- import { useCallback, useState } from "react";
95
- function useRunCollapseState(runs) {
96
- const [collapsedMap, setCollapsedMap] = useState({});
97
- const isCollapsed = useCallback(
98
- (runId) => {
99
- return collapsedMap[runId] ?? false;
100
- },
101
- [collapsedMap]
102
- );
103
- const toggleCollapse = useCallback((runId) => {
104
- setCollapsedMap((prev) => ({ ...prev, [runId]: !prev[runId] }));
105
- }, []);
106
- return { isCollapsed, toggleCollapse };
107
- }
108
-
109
- // src/hooks/use-auto-scroll.ts
110
- import {
111
- useCallback as useCallback2,
112
- useEffect,
113
- useRef,
114
- useState as useState2
115
- } from "react";
116
- var BOTTOM_THRESHOLD = 40;
117
- function useAutoScroll(containerRef, deps = []) {
118
- const [isAtBottom, setIsAtBottom] = useState2(true);
119
- const userScrolledUp = useRef(false);
120
- const checkBottom = useCallback2(() => {
121
- const el = containerRef.current;
122
- if (!el) return true;
123
- return el.scrollHeight - el.scrollTop - el.clientHeight < BOTTOM_THRESHOLD;
124
- }, [containerRef]);
125
- useEffect(() => {
126
- const el = containerRef.current;
127
- if (!el) return;
128
- const onScroll = () => {
129
- const atBottom = checkBottom();
130
- setIsAtBottom(atBottom);
131
- userScrolledUp.current = !atBottom;
132
- };
133
- el.addEventListener("scroll", onScroll, { passive: true });
134
- return () => el.removeEventListener("scroll", onScroll);
135
- }, [containerRef, checkBottom]);
136
- useEffect(() => {
137
- if (userScrolledUp.current) return;
138
- const el = containerRef.current;
139
- if (!el) return;
140
- el.scrollTop = el.scrollHeight;
141
- }, deps);
142
- const scrollToBottom = useCallback2(() => {
143
- const el = containerRef.current;
144
- if (!el) return;
145
- userScrolledUp.current = false;
146
- el.scrollTo({ top: el.scrollHeight, behavior: "smooth" });
147
- setIsAtBottom(true);
148
- }, [containerRef]);
149
- return { isAtBottom, scrollToBottom };
150
- }
151
-
152
- export {
153
- useRunGroups,
154
- useRunCollapseState,
155
- useAutoScroll
156
- };
@@ -1,102 +0,0 @@
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/50", 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
- };
@@ -1,183 +0,0 @@
1
- // src/utils/tool-display.ts
2
- var TOOL_NAME_PREFIX = "tool:";
3
- function normalizeToolName(tool) {
4
- const n = tool?.toLowerCase() ?? "";
5
- return n.startsWith(TOOL_NAME_PREFIX) ? n.slice(TOOL_NAME_PREFIX.length) : n;
6
- }
7
- function extractString(obj, key) {
8
- if (typeof obj === "object" && obj !== null && key in obj) {
9
- const val = obj[key];
10
- if (typeof val === "string") return val;
11
- }
12
- return void 0;
13
- }
14
- function extractCommand(input) {
15
- if (typeof input === "string") return input;
16
- return extractString(input, "command") ?? extractString(input, "cmd");
17
- }
18
- function extractFilePath(input) {
19
- return extractString(input, "file_path") ?? extractString(input, "path") ?? extractString(input, "filePath") ?? extractString(input, "file");
20
- }
21
- function cleanPath(path) {
22
- const parts = path.split("/");
23
- return parts.length > 3 ? ".../" + parts.slice(-2).join("/") : path;
24
- }
25
- var TOOL_CATEGORY_ICONS = {
26
- command: "terminal",
27
- write: "file-plus",
28
- read: "file-text",
29
- search: "search",
30
- edit: "file-edit",
31
- task: "cpu",
32
- web: "globe",
33
- todo: "check-square",
34
- other: "box"
35
- };
36
- function getToolCategory(toolName) {
37
- const name = normalizeToolName(toolName);
38
- switch (name) {
39
- case "bash":
40
- case "shell":
41
- case "command":
42
- case "execute":
43
- return "command";
44
- case "write":
45
- case "write_file":
46
- case "create_file":
47
- return "write";
48
- case "read":
49
- case "read_file":
50
- case "cat":
51
- return "read";
52
- case "grep":
53
- case "search":
54
- case "rg":
55
- return "search";
56
- case "edit":
57
- case "patch":
58
- case "sed":
59
- return "edit";
60
- case "glob":
61
- case "find":
62
- case "ls":
63
- return "search";
64
- case "web_search":
65
- case "web_fetch":
66
- case "fetch":
67
- return "web";
68
- case "task":
69
- case "agent":
70
- case "spawn":
71
- return "task";
72
- case "todo":
73
- case "todo_write":
74
- return "todo";
75
- default:
76
- return "other";
77
- }
78
- }
79
- function getToolDisplayMetadata(part) {
80
- const name = normalizeToolName(part.tool);
81
- const input = part.state.status !== "pending" ? part.state.input : void 0;
82
- const filePath = extractFilePath(input);
83
- const command = extractCommand(input);
84
- switch (name) {
85
- case "bash":
86
- case "shell":
87
- case "command":
88
- case "execute":
89
- return {
90
- title: "Run command",
91
- description: command ? truncateCommand(command) : void 0,
92
- displayVariant: "command",
93
- commandSnippet: command
94
- };
95
- case "write":
96
- case "write_file":
97
- case "create_file":
98
- return {
99
- title: filePath ? `Write ${cleanPath(filePath)}` : "Write file",
100
- description: filePath,
101
- displayVariant: "write-file",
102
- targetPath: filePath
103
- };
104
- case "edit":
105
- case "patch":
106
- return {
107
- title: filePath ? `Edit ${cleanPath(filePath)}` : "Edit file",
108
- description: filePath,
109
- hasDiffOutput: true,
110
- diffFilePath: filePath,
111
- displayVariant: "diff",
112
- targetPath: filePath
113
- };
114
- case "read":
115
- case "read_file":
116
- case "cat":
117
- return {
118
- title: filePath ? `Read ${cleanPath(filePath)}` : "Read file",
119
- description: filePath,
120
- displayVariant: "read-file",
121
- targetPath: filePath
122
- };
123
- case "grep":
124
- case "search":
125
- case "rg": {
126
- const pattern = extractString(input, "pattern");
127
- return {
128
- title: pattern ? `Search: ${pattern}` : "Search",
129
- description: pattern,
130
- displayVariant: "grep"
131
- };
132
- }
133
- case "glob":
134
- case "find":
135
- case "ls": {
136
- const pattern = extractString(input, "pattern");
137
- return {
138
- title: pattern ? `Find: ${pattern}` : "Find files",
139
- description: pattern,
140
- displayVariant: "glob"
141
- };
142
- }
143
- case "web_search":
144
- case "web_fetch":
145
- case "fetch": {
146
- const query = extractString(input, "query") ?? extractString(input, "url");
147
- return {
148
- title: query ? `Web: ${truncateCommand(query)}` : "Web search",
149
- description: query,
150
- displayVariant: "web-search"
151
- };
152
- }
153
- case "task":
154
- case "agent":
155
- case "spawn": {
156
- const desc = extractString(input, "description") ?? extractString(input, "prompt");
157
- return {
158
- title: desc ? `Task: ${truncateCommand(desc)}` : "Agent task",
159
- description: desc
160
- };
161
- }
162
- default:
163
- return {
164
- title: part.tool || "Tool",
165
- description: command ?? filePath ?? extractString(input, "pattern") ?? extractString(input, "query")
166
- };
167
- }
168
- }
169
- function truncateCommand(cmd) {
170
- const first = cmd.split("\n")[0];
171
- return first.length > 60 ? first.slice(0, 57) + "..." : first;
172
- }
173
- function getToolErrorText(part, fallback) {
174
- if (part.state.status !== "error") return void 0;
175
- return part.state.error || fallback;
176
- }
177
-
178
- export {
179
- TOOL_CATEGORY_ICONS,
180
- getToolCategory,
181
- getToolDisplayMetadata,
182
- getToolErrorText
183
- };
@@ -1,192 +0,0 @@
1
- import {
2
- Avatar,
3
- AvatarFallback,
4
- AvatarImage,
5
- DropdownMenu,
6
- DropdownMenuContent,
7
- DropdownMenuItem,
8
- DropdownMenuLabel,
9
- DropdownMenuSeparator,
10
- DropdownMenuTrigger
11
- } from "./chunk-34A66VBG.js";
12
- import {
13
- Button
14
- } from "./chunk-MKTSMWVD.js";
15
- import {
16
- cn
17
- } from "./chunk-RQHJBTEU.js";
18
-
19
- // src/auth/auth.tsx
20
- import { jsx, jsxs } from "react/jsx-runtime";
21
- function GitHubIcon({ className }) {
22
- return /* @__PURE__ */ jsx(
23
- "svg",
24
- {
25
- className,
26
- viewBox: "0 0 24 24",
27
- fill: "currentColor",
28
- "aria-hidden": "true",
29
- children: /* @__PURE__ */ jsx(
30
- "path",
31
- {
32
- fillRule: "evenodd",
33
- clipRule: "evenodd",
34
- d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
35
- }
36
- )
37
- }
38
- );
39
- }
40
- function GitHubLoginButton({
41
- authUrl = "/auth/github",
42
- variant = "default",
43
- className,
44
- children,
45
- ...props
46
- }) {
47
- return /* @__PURE__ */ jsxs(
48
- Button,
49
- {
50
- variant,
51
- className: cn("gap-2", className),
52
- onClick: () => {
53
- window.location.href = authUrl;
54
- },
55
- ...props,
56
- children: [
57
- /* @__PURE__ */ jsx(GitHubIcon, { className: "h-5 w-5" }),
58
- children ?? "Sign in with GitHub"
59
- ]
60
- }
61
- );
62
- }
63
- function UserMenu({
64
- user,
65
- logoutUrl = "/auth/logout",
66
- links = [],
67
- variant = "sandbox",
68
- onLogout
69
- }) {
70
- const initials = user.name ? user.name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : user.email.slice(0, 2).toUpperCase();
71
- const avatarGradient = {
72
- sandbox: "bg-[image:var(--accent-gradient-strong)]"
73
- }[variant];
74
- const handleLogout = () => {
75
- if (onLogout) {
76
- onLogout();
77
- }
78
- window.location.href = logoutUrl;
79
- };
80
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
81
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
82
- "button",
83
- {
84
- type: "button",
85
- className: "flex items-center gap-2 rounded-lg p-1.5 transition-colors hover:bg-accent focus:outline-none focus:ring-2 focus:ring-ring",
86
- children: [
87
- /* @__PURE__ */ jsxs(Avatar, { className: "h-8 w-8", children: [
88
- /* @__PURE__ */ jsx(AvatarImage, { src: void 0, alt: user.name ?? user.email }),
89
- /* @__PURE__ */ jsx(
90
- AvatarFallback,
91
- {
92
- className: cn(
93
- "text-white text-xs",
94
- avatarGradient
95
- ),
96
- children: initials
97
- }
98
- )
99
- ] }),
100
- /* @__PURE__ */ jsxs("div", { className: "hidden text-left md:block", children: [
101
- /* @__PURE__ */ jsx("p", { className: "font-medium text-sm", children: user.name ?? user.email }),
102
- user.tier && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-xs capitalize", children: [
103
- user.tier,
104
- " Plan"
105
- ] })
106
- ] })
107
- ]
108
- }
109
- ) }),
110
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
111
- /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-1", children: [
112
- /* @__PURE__ */ jsx("p", { className: "font-medium text-sm", children: user.name ?? "Account" }),
113
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: user.email })
114
- ] }) }),
115
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
116
- links.map((link) => /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs("a", { href: link.href, className: "flex items-center gap-2", children: [
117
- link.icon,
118
- link.label
119
- ] }) }, link.href)),
120
- links.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
121
- /* @__PURE__ */ jsx(
122
- DropdownMenuItem,
123
- {
124
- onClick: handleLogout,
125
- className: "text-[var(--surface-danger-text)] focus:text-[var(--surface-danger-text)]",
126
- children: "Sign out"
127
- }
128
- )
129
- ] })
130
- ] });
131
- }
132
- function AuthHeader({
133
- user,
134
- loading = false,
135
- variant = "sandbox",
136
- apiBaseUrl = "",
137
- menuLinks,
138
- className
139
- }) {
140
- if (loading) {
141
- return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
142
- /* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-pulse rounded-full bg-muted" }),
143
- /* @__PURE__ */ jsx("div", { className: "hidden md:block", children: /* @__PURE__ */ jsx("div", { className: "h-4 w-20 animate-pulse rounded bg-muted" }) })
144
- ] });
145
- }
146
- if (!user) {
147
- return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2", className), children: /* @__PURE__ */ jsx(
148
- GitHubLoginButton,
149
- {
150
- authUrl: `${apiBaseUrl}/auth/github`,
151
- variant,
152
- size: "sm"
153
- }
154
- ) });
155
- }
156
- return /* @__PURE__ */ jsx(
157
- UserMenu,
158
- {
159
- user,
160
- variant,
161
- logoutUrl: `${apiBaseUrl}/auth/logout`,
162
- links: menuLinks
163
- }
164
- );
165
- }
166
-
167
- // src/auth/login-layout.tsx
168
- import { Terminal } from "lucide-react";
169
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
170
- function LoginLayout({
171
- title = "Welcome Back",
172
- subtitle = "Sign in to your workspace.",
173
- brandIcon,
174
- children,
175
- className
176
- }) {
177
- return /* @__PURE__ */ jsx2("div", { className: cn("relative flex min-h-screen items-center justify-center bg-background overflow-hidden antialiased font-sans flex-col", className), children: /* @__PURE__ */ jsxs2("div", { className: "z-10 w-full max-w-md px-6 animate-in flex flex-col items-center", children: [
178
- /* @__PURE__ */ jsxs2("div", { className: "mb-10 text-center flex flex-col items-center", children: [
179
- /* @__PURE__ */ jsx2("div", { className: "inline-flex h-14 w-14 mb-4 items-center justify-center rounded-lg bg-muted border border-border", children: brandIcon || /* @__PURE__ */ jsx2(Terminal, { className: "h-7 w-7 text-foreground" }) }),
180
- /* @__PURE__ */ jsx2("h1", { className: "text-2xl font-bold tracking-tight text-foreground font-display", children: title }),
181
- /* @__PURE__ */ jsx2("p", { className: "mt-2 text-sm text-muted-foreground", children: subtitle })
182
- ] }),
183
- /* @__PURE__ */ jsx2("div", { className: "w-full bg-card p-8 border border-border rounded-lg", children })
184
- ] }) });
185
- }
186
-
187
- export {
188
- GitHubLoginButton,
189
- UserMenu,
190
- AuthHeader,
191
- LoginLayout
192
- };