@tangle-network/ui 1.0.0
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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/active-sessions-store-CeOmXgv5.d.ts +85 -0
- package/dist/artifact-pane-DvJyPWV4.d.ts +24 -0
- package/dist/auth.d.ts +74 -0
- package/dist/auth.js +15 -0
- package/dist/button-CMQuQEW_.d.ts +17 -0
- package/dist/chat.d.ts +232 -0
- package/dist/chat.js +30 -0
- package/dist/chunk-2NFQRQOD.js +1009 -0
- package/dist/chunk-2VH6PUXD.js +186 -0
- package/dist/chunk-34A66VBG.js +214 -0
- package/dist/chunk-3OI2QKFD.js +0 -0
- package/dist/chunk-4CLN43XT.js +45 -0
- package/dist/chunk-54SQQMMM.js +156 -0
- package/dist/chunk-5Z5ZYMOJ.js +0 -0
- package/dist/chunk-66BNMOVT.js +167 -0
- package/dist/chunk-6BGQA4BQ.js +0 -0
- package/dist/chunk-7UO2ZMRQ.js +133 -0
- package/dist/chunk-BX6AQMUS.js +183 -0
- package/dist/chunk-CD53GZOM.js +59 -0
- package/dist/chunk-CSAIKY36.js +54 -0
- package/dist/chunk-EEE55AVS.js +1201 -0
- package/dist/chunk-GYPQXTJU.js +230 -0
- package/dist/chunk-HFL6R6IF.js +37 -0
- package/dist/chunk-HJKCSXCH.js +737 -0
- package/dist/chunk-LISXUB4D.js +1222 -0
- package/dist/chunk-LQS34IGP.js +0 -0
- package/dist/chunk-MKTSMWVD.js +109 -0
- package/dist/chunk-NKDZ7GZE.js +192 -0
- package/dist/chunk-OEX7NZE3.js +321 -0
- package/dist/chunk-Q56BYXQF.js +61 -0
- package/dist/chunk-Q7EIIWTC.js +0 -0
- package/dist/chunk-REJESC5U.js +117 -0
- package/dist/chunk-RQGKSCEZ.js +0 -0
- package/dist/chunk-RQHJBTEU.js +10 -0
- package/dist/chunk-TMFOPHHN.js +299 -0
- package/dist/chunk-XGKULLYE.js +40 -0
- package/dist/chunk-XIHMJ7ZQ.js +614 -0
- package/dist/chunk-YJ2G3XO5.js +1048 -0
- package/dist/chunk-YNN4O57I.js +754 -0
- package/dist/code-block-DjXf8eOG.d.ts +19 -0
- package/dist/document-editor-pane-A5LT5H4N.js +12 -0
- package/dist/document-editor-pane-DyDEX_Zm.d.ts +124 -0
- package/dist/editor.d.ts +120 -0
- package/dist/editor.js +34 -0
- package/dist/files.d.ts +175 -0
- package/dist/files.js +20 -0
- package/dist/hooks.d.ts +56 -0
- package/dist/hooks.js +41 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +446 -0
- package/dist/markdown.d.ts +15 -0
- package/dist/markdown.js +14 -0
- package/dist/message-BHWbxBtT.d.ts +15 -0
- package/dist/openui.d.ts +115 -0
- package/dist/openui.js +12 -0
- package/dist/parts-dj7AcUg0.d.ts +36 -0
- package/dist/primitives.d.ts +332 -0
- package/dist/primitives.js +191 -0
- package/dist/run-PfLmDAox.d.ts +41 -0
- package/dist/run.d.ts +69 -0
- package/dist/run.js +36 -0
- package/dist/sdk-hooks.d.ts +285 -0
- package/dist/sdk-hooks.js +31 -0
- package/dist/stores.d.ts +17 -0
- package/dist/stores.js +76 -0
- package/dist/tool-call-feed-Bs3MyQMT.d.ts +68 -0
- package/dist/tool-display-z4JcDmMQ.d.ts +32 -0
- package/dist/tool-previews.d.ts +48 -0
- package/dist/tool-previews.js +21 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +45 -0
- package/dist/utils.js +32 -0
- package/package.json +193 -0
- package/src/auth/auth.tsx +228 -0
- package/src/auth/index.ts +13 -0
- package/src/auth/login-layout.tsx +46 -0
- package/src/chat/agent-timeline.stories.tsx +429 -0
- package/src/chat/agent-timeline.tsx +360 -0
- package/src/chat/chat-container.tsx +486 -0
- package/src/chat/chat-input.stories.tsx +142 -0
- package/src/chat/chat-input.tsx +389 -0
- package/src/chat/chat-message.stories.tsx +237 -0
- package/src/chat/chat-message.tsx +129 -0
- package/src/chat/index.ts +18 -0
- package/src/chat/message-list.stories.tsx +336 -0
- package/src/chat/message-list.tsx +79 -0
- package/src/chat/thinking-indicator.stories.tsx +56 -0
- package/src/chat/thinking-indicator.tsx +30 -0
- package/src/chat/user-message.stories.tsx +92 -0
- package/src/chat/user-message.tsx +43 -0
- package/src/editor/document-editor-pane.tsx +351 -0
- package/src/editor/editor-provider.tsx +428 -0
- package/src/editor/editor-toolbar.tsx +130 -0
- package/src/editor/index.ts +31 -0
- package/src/editor/markdown-conversion.ts +21 -0
- package/src/editor/markdown-document-editor.tsx +137 -0
- package/src/editor/tiptap-editor.tsx +331 -0
- package/src/editor/use-editor.ts +221 -0
- package/src/files/file-artifact-pane.tsx +183 -0
- package/src/files/file-preview.tsx +342 -0
- package/src/files/file-tabs.tsx +71 -0
- package/src/files/file-tree.tsx +258 -0
- package/src/files/index.ts +17 -0
- package/src/files/rich-file-tree.stories.tsx +104 -0
- package/src/files/rich-file-tree.test.tsx +42 -0
- package/src/files/rich-file-tree.tsx +232 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/use-auth.ts +153 -0
- package/src/hooks/use-auto-scroll.ts +59 -0
- package/src/hooks/use-dropdown-menu.ts +40 -0
- package/src/hooks/use-live-time.test.tsx +40 -0
- package/src/hooks/use-live-time.ts +27 -0
- package/src/hooks/use-realtime-session.ts +319 -0
- package/src/hooks/use-run-collapse-state.ts +25 -0
- package/src/hooks/use-run-groups.ts +111 -0
- package/src/hooks/use-sdk-session.ts +575 -0
- package/src/hooks/use-sse-stream.ts +475 -0
- package/src/hooks/use-tool-call-stream.ts +96 -0
- package/src/index.ts +14 -0
- package/src/lib/utils.ts +6 -0
- package/src/markdown/code-block.tsx +198 -0
- package/src/markdown/index.ts +2 -0
- package/src/markdown/markdown.stories.tsx +190 -0
- package/src/markdown/markdown.tsx +62 -0
- package/src/openui/index.ts +20 -0
- package/src/openui/openui-artifact-renderer.tsx +542 -0
- package/src/primitives/artifact-pane.tsx +91 -0
- package/src/primitives/avatar.stories.tsx +95 -0
- package/src/primitives/avatar.tsx +47 -0
- package/src/primitives/badge.stories.tsx +57 -0
- package/src/primitives/badge.tsx +97 -0
- package/src/primitives/button.stories.tsx +48 -0
- package/src/primitives/button.tsx +115 -0
- package/src/primitives/card.stories.tsx +53 -0
- package/src/primitives/card.tsx +98 -0
- package/src/primitives/code-block.stories.tsx +115 -0
- package/src/primitives/code-block.tsx +22 -0
- package/src/primitives/design-tokens.stories.tsx +162 -0
- package/src/primitives/dialog.stories.tsx +176 -0
- package/src/primitives/dialog.tsx +137 -0
- package/src/primitives/drop-zone.stories.tsx +123 -0
- package/src/primitives/drop-zone.tsx +131 -0
- package/src/primitives/dropdown-menu.stories.tsx +122 -0
- package/src/primitives/dropdown-menu.tsx +214 -0
- package/src/primitives/empty-state.stories.tsx +81 -0
- package/src/primitives/empty-state.tsx +40 -0
- package/src/primitives/index.ts +118 -0
- package/src/primitives/input.stories.tsx +113 -0
- package/src/primitives/input.tsx +136 -0
- package/src/primitives/label.stories.tsx +84 -0
- package/src/primitives/label.tsx +24 -0
- package/src/primitives/progress.stories.tsx +93 -0
- package/src/primitives/progress.tsx +50 -0
- package/src/primitives/segmented-control.test.tsx +328 -0
- package/src/primitives/segmented-control.tsx +154 -0
- package/src/primitives/select.stories.tsx +164 -0
- package/src/primitives/select.tsx +158 -0
- package/src/primitives/sidebar-drop-zone.stories.tsx +100 -0
- package/src/primitives/sidebar-drop-zone.tsx +149 -0
- package/src/primitives/skeleton.stories.tsx +79 -0
- package/src/primitives/skeleton.tsx +55 -0
- package/src/primitives/stat-card.stories.tsx +137 -0
- package/src/primitives/stat-card.tsx +97 -0
- package/src/primitives/switch.stories.tsx +85 -0
- package/src/primitives/switch.tsx +28 -0
- package/src/primitives/table.stories.tsx +170 -0
- package/src/primitives/table.tsx +116 -0
- package/src/primitives/tabs.stories.tsx +180 -0
- package/src/primitives/tabs.tsx +71 -0
- package/src/primitives/terminal-display.stories.tsx +191 -0
- package/src/primitives/terminal-display.tsx +189 -0
- package/src/primitives/theme-toggle.stories.tsx +32 -0
- package/src/primitives/theme-toggle.tsx +96 -0
- package/src/primitives/toast.stories.tsx +155 -0
- package/src/primitives/toast.tsx +190 -0
- package/src/primitives/upload-progress.stories.tsx +120 -0
- package/src/primitives/upload-progress.tsx +110 -0
- package/src/run/expanded-tool-detail.stories.tsx +182 -0
- package/src/run/expanded-tool-detail.tsx +186 -0
- package/src/run/index.ts +13 -0
- package/src/run/inline-thinking-item.stories.tsx +136 -0
- package/src/run/inline-thinking-item.tsx +120 -0
- package/src/run/inline-tool-item.stories.tsx +222 -0
- package/src/run/inline-tool-item.tsx +190 -0
- package/src/run/run-group.stories.tsx +322 -0
- package/src/run/run-group.tsx +569 -0
- package/src/run/run-item-primitives.tsx +17 -0
- package/src/run/tool-call-feed.stories.tsx +294 -0
- package/src/run/tool-call-feed.tsx +192 -0
- package/src/run/tool-call-step.stories.tsx +198 -0
- package/src/run/tool-call-step.tsx +240 -0
- package/src/sdk-hooks.ts +38 -0
- package/src/stores/active-sessions-store.ts +455 -0
- package/src/stores/chat-store.ts +43 -0
- package/src/stores/index.ts +2 -0
- package/src/tool-previews/command-preview.tsx +116 -0
- package/src/tool-previews/diff-preview.tsx +85 -0
- package/src/tool-previews/glob-results-preview.tsx +98 -0
- package/src/tool-previews/grep-results-preview.tsx +157 -0
- package/src/tool-previews/index.ts +22 -0
- package/src/tool-previews/preview-primitives.tsx +84 -0
- package/src/tool-previews/question-preview.tsx +101 -0
- package/src/tool-previews/web-search-preview.tsx +117 -0
- package/src/tool-previews/write-file-preview.tsx +80 -0
- package/src/types/branding.ts +11 -0
- package/src/types/index.ts +5 -0
- package/src/types/message.ts +13 -0
- package/src/types/parts.ts +51 -0
- package/src/types/run.ts +56 -0
- package/src/types/tool-display.ts +41 -0
- package/src/utils/copy-text.ts +30 -0
- package/src/utils/format.test.ts +43 -0
- package/src/utils/format.ts +56 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/time-ago.ts +9 -0
- package/src/utils/tool-display.ts +238 -0
|
@@ -0,0 +1,1222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card
|
|
3
|
+
} from "./chunk-GYPQXTJU.js";
|
|
4
|
+
import {
|
|
5
|
+
cn
|
|
6
|
+
} from "./chunk-RQHJBTEU.js";
|
|
7
|
+
|
|
8
|
+
// src/primitives/dialog.tsx
|
|
9
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
10
|
+
import { X } from "lucide-react";
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var Dialog = DialogPrimitive.Root;
|
|
14
|
+
var DialogTrigger = DialogPrimitive.Trigger;
|
|
15
|
+
var DialogPortal = DialogPrimitive.Portal;
|
|
16
|
+
var DialogClose = DialogPrimitive.Close;
|
|
17
|
+
var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
18
|
+
DialogPrimitive.Overlay,
|
|
19
|
+
{
|
|
20
|
+
ref,
|
|
21
|
+
className: cn(
|
|
22
|
+
"fixed inset-0 z-50 bg-black/40",
|
|
23
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
24
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
25
|
+
className
|
|
26
|
+
),
|
|
27
|
+
...props
|
|
28
|
+
}
|
|
29
|
+
));
|
|
30
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
31
|
+
var DialogContent = React.forwardRef(({ className, children, variant = "default", ...props }, ref) => {
|
|
32
|
+
const variants = {
|
|
33
|
+
default: "border-border",
|
|
34
|
+
sandbox: "border-[var(--border-accent)] shadow-[var(--shadow-accent)]"
|
|
35
|
+
};
|
|
36
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
37
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
38
|
+
/* @__PURE__ */ jsxs(
|
|
39
|
+
DialogPrimitive.Content,
|
|
40
|
+
{
|
|
41
|
+
ref,
|
|
42
|
+
className: cn(
|
|
43
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
|
|
44
|
+
"gap-4 rounded-lg border bg-card p-6 shadow-lg duration-200",
|
|
45
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
46
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
47
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
48
|
+
"data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]",
|
|
49
|
+
"data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
|
50
|
+
variants[variant],
|
|
51
|
+
className
|
|
52
|
+
),
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
children,
|
|
56
|
+
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
57
|
+
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
59
|
+
] })
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
] });
|
|
64
|
+
});
|
|
65
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
66
|
+
var DialogHeader = ({
|
|
67
|
+
className,
|
|
68
|
+
...props
|
|
69
|
+
}) => /* @__PURE__ */ jsx(
|
|
70
|
+
"div",
|
|
71
|
+
{
|
|
72
|
+
className: cn(
|
|
73
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
74
|
+
className
|
|
75
|
+
),
|
|
76
|
+
...props
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
DialogHeader.displayName = "DialogHeader";
|
|
80
|
+
var DialogFooter = ({
|
|
81
|
+
className,
|
|
82
|
+
...props
|
|
83
|
+
}) => /* @__PURE__ */ jsx(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
className: cn(
|
|
87
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
88
|
+
className
|
|
89
|
+
),
|
|
90
|
+
...props
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
DialogFooter.displayName = "DialogFooter";
|
|
94
|
+
var DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
95
|
+
DialogPrimitive.Title,
|
|
96
|
+
{
|
|
97
|
+
ref,
|
|
98
|
+
className: cn(
|
|
99
|
+
"font-semibold text-lg leading-none tracking-tight",
|
|
100
|
+
className
|
|
101
|
+
),
|
|
102
|
+
...props
|
|
103
|
+
}
|
|
104
|
+
));
|
|
105
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
106
|
+
var DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
107
|
+
DialogPrimitive.Description,
|
|
108
|
+
{
|
|
109
|
+
ref,
|
|
110
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
111
|
+
...props
|
|
112
|
+
}
|
|
113
|
+
));
|
|
114
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
115
|
+
|
|
116
|
+
// src/primitives/input.tsx
|
|
117
|
+
import * as React2 from "react";
|
|
118
|
+
import { cva } from "class-variance-authority";
|
|
119
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
120
|
+
var inputVariants = cva(
|
|
121
|
+
"flex w-full rounded-lg border bg-card px-4 py-2 text-sm transition-all duration-200 placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50 file:border-0 file:bg-transparent file:font-medium file:text-sm",
|
|
122
|
+
{
|
|
123
|
+
variants: {
|
|
124
|
+
variant: {
|
|
125
|
+
default: "border-input focus:ring-ring",
|
|
126
|
+
sandbox: "border-border focus:border-[var(--border-accent-hover)] focus:ring-[var(--border-accent)]",
|
|
127
|
+
error: "border-[var(--surface-danger-border)] focus:ring-[var(--surface-danger-border)]"
|
|
128
|
+
},
|
|
129
|
+
size: {
|
|
130
|
+
default: "h-11",
|
|
131
|
+
sm: "h-9 px-3",
|
|
132
|
+
lg: "h-12 px-5"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
defaultVariants: {
|
|
136
|
+
variant: "default",
|
|
137
|
+
size: "default"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
var Input = React2.forwardRef(
|
|
142
|
+
({ className, type, variant, size, label, error, hint, id, ...props }, ref) => {
|
|
143
|
+
const inputId = id ?? label?.toLowerCase().replace(/\s+/g, "-");
|
|
144
|
+
const input = /* @__PURE__ */ jsx2(
|
|
145
|
+
"input",
|
|
146
|
+
{
|
|
147
|
+
type,
|
|
148
|
+
id: inputId,
|
|
149
|
+
className: cn(inputVariants({ variant: error ? "error" : variant, size, className })),
|
|
150
|
+
ref,
|
|
151
|
+
...props
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
if (!label && !error && !hint) return input;
|
|
155
|
+
return /* @__PURE__ */ jsxs2("div", { className: "w-full space-y-1.5", children: [
|
|
156
|
+
label && /* @__PURE__ */ jsx2(
|
|
157
|
+
"label",
|
|
158
|
+
{
|
|
159
|
+
htmlFor: inputId,
|
|
160
|
+
className: "block font-medium text-foreground text-sm",
|
|
161
|
+
children: label
|
|
162
|
+
}
|
|
163
|
+
),
|
|
164
|
+
input,
|
|
165
|
+
error && /* @__PURE__ */ jsx2("p", { className: "text-[var(--surface-danger-text)] text-sm font-medium", children: error }),
|
|
166
|
+
hint && !error && /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground/70 text-sm", children: hint })
|
|
167
|
+
] });
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
Input.displayName = "Input";
|
|
171
|
+
var Textarea = React2.forwardRef(
|
|
172
|
+
({ className, variant = "default", label, error, hint, id, ...props }, ref) => {
|
|
173
|
+
const textareaId = id ?? label?.toLowerCase().replace(/\s+/g, "-");
|
|
174
|
+
const variants = {
|
|
175
|
+
default: "border-input focus:ring-ring",
|
|
176
|
+
sandbox: "border-border focus:border-[var(--border-accent-hover)] focus:ring-[var(--border-accent)]"
|
|
177
|
+
};
|
|
178
|
+
const textarea = /* @__PURE__ */ jsx2(
|
|
179
|
+
"textarea",
|
|
180
|
+
{
|
|
181
|
+
id: textareaId,
|
|
182
|
+
className: cn(
|
|
183
|
+
"flex min-h-[120px] w-full resize-y rounded-lg border bg-card px-4 py-3 text-sm transition-all duration-200",
|
|
184
|
+
"placeholder:text-muted-foreground",
|
|
185
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-0",
|
|
186
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
187
|
+
error ? "border-[var(--surface-danger-border)] focus:ring-[var(--surface-danger-border)]" : variants[variant],
|
|
188
|
+
className
|
|
189
|
+
),
|
|
190
|
+
ref,
|
|
191
|
+
...props
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
if (!label && !error && !hint) return textarea;
|
|
195
|
+
return /* @__PURE__ */ jsxs2("div", { className: "w-full space-y-1.5", children: [
|
|
196
|
+
label && /* @__PURE__ */ jsx2(
|
|
197
|
+
"label",
|
|
198
|
+
{
|
|
199
|
+
htmlFor: textareaId,
|
|
200
|
+
className: "block font-medium text-muted-foreground text-sm",
|
|
201
|
+
children: label
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
textarea,
|
|
205
|
+
error && /* @__PURE__ */ jsx2("p", { className: "text-[var(--surface-danger-text)] text-sm", children: error }),
|
|
206
|
+
hint && !error && /* @__PURE__ */ jsx2("p", { className: "text-muted-foreground/70 text-sm", children: hint })
|
|
207
|
+
] });
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
Textarea.displayName = "Textarea";
|
|
211
|
+
|
|
212
|
+
// src/primitives/select.tsx
|
|
213
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
214
|
+
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
215
|
+
import * as React3 from "react";
|
|
216
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
217
|
+
var Select = SelectPrimitive.Root;
|
|
218
|
+
var SelectGroup = SelectPrimitive.Group;
|
|
219
|
+
var SelectValue = SelectPrimitive.Value;
|
|
220
|
+
var SelectTrigger = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
|
|
221
|
+
SelectPrimitive.Trigger,
|
|
222
|
+
{
|
|
223
|
+
ref,
|
|
224
|
+
className: cn(
|
|
225
|
+
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-border bg-card px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
226
|
+
className
|
|
227
|
+
),
|
|
228
|
+
...props,
|
|
229
|
+
children: [
|
|
230
|
+
children,
|
|
231
|
+
/* @__PURE__ */ jsx3(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx3(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
));
|
|
235
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
236
|
+
var SelectScrollUpButton = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
|
|
237
|
+
SelectPrimitive.ScrollUpButton,
|
|
238
|
+
{
|
|
239
|
+
ref,
|
|
240
|
+
className: cn(
|
|
241
|
+
"flex cursor-default items-center justify-center py-1",
|
|
242
|
+
className
|
|
243
|
+
),
|
|
244
|
+
...props,
|
|
245
|
+
children: /* @__PURE__ */ jsx3(ChevronUp, { className: "h-4 w-4" })
|
|
246
|
+
}
|
|
247
|
+
));
|
|
248
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
249
|
+
var SelectScrollDownButton = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
|
|
250
|
+
SelectPrimitive.ScrollDownButton,
|
|
251
|
+
{
|
|
252
|
+
ref,
|
|
253
|
+
className: cn(
|
|
254
|
+
"flex cursor-default items-center justify-center py-1",
|
|
255
|
+
className
|
|
256
|
+
),
|
|
257
|
+
...props,
|
|
258
|
+
children: /* @__PURE__ */ jsx3(ChevronDown, { className: "h-4 w-4" })
|
|
259
|
+
}
|
|
260
|
+
));
|
|
261
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
262
|
+
var SelectContent = React3.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx3(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs3(
|
|
263
|
+
SelectPrimitive.Content,
|
|
264
|
+
{
|
|
265
|
+
ref,
|
|
266
|
+
className: cn(
|
|
267
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-card text-foreground shadow-[var(--shadow-card)] data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
268
|
+
position === "popper" && "data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1",
|
|
269
|
+
className
|
|
270
|
+
),
|
|
271
|
+
position,
|
|
272
|
+
...props,
|
|
273
|
+
children: [
|
|
274
|
+
/* @__PURE__ */ jsx3(SelectScrollUpButton, {}),
|
|
275
|
+
/* @__PURE__ */ jsx3(
|
|
276
|
+
SelectPrimitive.Viewport,
|
|
277
|
+
{
|
|
278
|
+
className: cn(
|
|
279
|
+
"p-1",
|
|
280
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
281
|
+
),
|
|
282
|
+
children
|
|
283
|
+
}
|
|
284
|
+
),
|
|
285
|
+
/* @__PURE__ */ jsx3(SelectScrollDownButton, {})
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
) }));
|
|
289
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
290
|
+
var SelectLabel = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
|
|
291
|
+
SelectPrimitive.Label,
|
|
292
|
+
{
|
|
293
|
+
ref,
|
|
294
|
+
className: cn("px-2 py-1.5 font-semibold text-sm", className),
|
|
295
|
+
...props
|
|
296
|
+
}
|
|
297
|
+
));
|
|
298
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
299
|
+
var SelectItem = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs3(
|
|
300
|
+
SelectPrimitive.Item,
|
|
301
|
+
{
|
|
302
|
+
ref,
|
|
303
|
+
className: cn(
|
|
304
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none focus:bg-muted/50 focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
305
|
+
className
|
|
306
|
+
),
|
|
307
|
+
...props,
|
|
308
|
+
children: [
|
|
309
|
+
/* @__PURE__ */ jsx3("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx3(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx3(Check, { className: "h-4 w-4" }) }) }),
|
|
310
|
+
/* @__PURE__ */ jsx3(SelectPrimitive.ItemText, { children })
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
));
|
|
314
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
315
|
+
var SelectSeparator = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
|
|
316
|
+
SelectPrimitive.Separator,
|
|
317
|
+
{
|
|
318
|
+
ref,
|
|
319
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
320
|
+
...props
|
|
321
|
+
}
|
|
322
|
+
));
|
|
323
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
324
|
+
|
|
325
|
+
// src/primitives/segmented-control.tsx
|
|
326
|
+
import * as React4 from "react";
|
|
327
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
328
|
+
function SegmentedControl({
|
|
329
|
+
value,
|
|
330
|
+
onValueChange,
|
|
331
|
+
options,
|
|
332
|
+
variant = "row",
|
|
333
|
+
className,
|
|
334
|
+
...rest
|
|
335
|
+
}) {
|
|
336
|
+
if (typeof process !== "undefined" && process?.env?.NODE_ENV !== "production" && !rest["aria-label"] && !rest["aria-labelledby"]) {
|
|
337
|
+
console.warn(
|
|
338
|
+
'[SegmentedControl] role="radiogroup" requires either aria-label or aria-labelledby for accessibility.'
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
const optionRefs = React4.useRef(/* @__PURE__ */ new Map());
|
|
342
|
+
const hasMatch = options.some((o) => o.value === value);
|
|
343
|
+
const handleKeyDown = (e) => {
|
|
344
|
+
if (options.length === 0) return;
|
|
345
|
+
let idx = options.findIndex((o) => o.value === value);
|
|
346
|
+
if (idx === -1) idx = 0;
|
|
347
|
+
let next;
|
|
348
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (idx + 1) % options.length;
|
|
349
|
+
else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (idx - 1 + options.length) % options.length;
|
|
350
|
+
else if (e.key === "Home") next = 0;
|
|
351
|
+
else if (e.key === "End") next = options.length - 1;
|
|
352
|
+
if (next !== void 0) {
|
|
353
|
+
e.preventDefault();
|
|
354
|
+
if (options[next].value !== value) {
|
|
355
|
+
onValueChange(options[next].value);
|
|
356
|
+
}
|
|
357
|
+
optionRefs.current.get(options[next].value)?.focus();
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
return /* @__PURE__ */ jsx4(
|
|
361
|
+
"div",
|
|
362
|
+
{
|
|
363
|
+
role: "radiogroup",
|
|
364
|
+
id: rest.id,
|
|
365
|
+
"aria-label": rest["aria-label"],
|
|
366
|
+
"aria-labelledby": rest["aria-labelledby"],
|
|
367
|
+
onKeyDown: handleKeyDown,
|
|
368
|
+
className: cn(
|
|
369
|
+
"flex gap-1",
|
|
370
|
+
variant === "row" && "flex-wrap items-center rounded-lg border border-border bg-card p-1",
|
|
371
|
+
variant === "tabs" && "flex-nowrap items-end border-b border-border pb-0 overflow-x-auto",
|
|
372
|
+
className
|
|
373
|
+
),
|
|
374
|
+
children: options.map((option, i) => {
|
|
375
|
+
const active = option.value === value;
|
|
376
|
+
const focusable = active || !hasMatch && i === 0;
|
|
377
|
+
return /* @__PURE__ */ jsxs4(
|
|
378
|
+
"button",
|
|
379
|
+
{
|
|
380
|
+
ref: (el) => {
|
|
381
|
+
if (el) optionRefs.current.set(option.value, el);
|
|
382
|
+
else optionRefs.current.delete(option.value);
|
|
383
|
+
},
|
|
384
|
+
type: "button",
|
|
385
|
+
role: "radio",
|
|
386
|
+
"aria-checked": active,
|
|
387
|
+
tabIndex: focusable ? 0 : -1,
|
|
388
|
+
onClick: () => {
|
|
389
|
+
if (!active) onValueChange(option.value);
|
|
390
|
+
},
|
|
391
|
+
className: cn(
|
|
392
|
+
"relative inline-flex items-center gap-2 whitespace-nowrap text-sm transition-colors",
|
|
393
|
+
variant === "row" && "rounded-md px-3 py-1.5",
|
|
394
|
+
variant === "tabs" && "rounded-none border-b-2 -mb-px px-4 py-2",
|
|
395
|
+
// Active styling is the ONLY styled state — unselected
|
|
396
|
+
// segments stay transparent on purpose so they don't
|
|
397
|
+
// compete visually with the selection.
|
|
398
|
+
active ? variant === "row" ? "border border-transparent bg-[var(--accent-surface)] text-[var(--accent-text)] font-semibold" : "border-[var(--accent-text)] text-[var(--accent-text)] font-semibold" : variant === "row" ? "border border-transparent text-muted-foreground hover:text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
|
|
399
|
+
),
|
|
400
|
+
children: [
|
|
401
|
+
/* @__PURE__ */ jsx4("span", { children: option.label }),
|
|
402
|
+
option.adornment && /* @__PURE__ */ jsx4(
|
|
403
|
+
"span",
|
|
404
|
+
{
|
|
405
|
+
className: cn(
|
|
406
|
+
"text-xs",
|
|
407
|
+
active ? "text-[var(--accent-text)]/80" : "text-muted-foreground"
|
|
408
|
+
),
|
|
409
|
+
children: option.adornment
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
]
|
|
413
|
+
},
|
|
414
|
+
option.value
|
|
415
|
+
);
|
|
416
|
+
})
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/primitives/progress.tsx
|
|
422
|
+
import * as ProgressPrimitive from "@radix-ui/react-progress";
|
|
423
|
+
import * as React5 from "react";
|
|
424
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
425
|
+
var Progress = React5.forwardRef(
|
|
426
|
+
({ className, value, variant = "default", showValue = false, ...props }, ref) => {
|
|
427
|
+
const indicatorVariants = {
|
|
428
|
+
default: "bg-primary",
|
|
429
|
+
sandbox: "bg-[image:var(--accent-gradient-strong)]"
|
|
430
|
+
};
|
|
431
|
+
return /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
432
|
+
/* @__PURE__ */ jsx5(
|
|
433
|
+
ProgressPrimitive.Root,
|
|
434
|
+
{
|
|
435
|
+
ref,
|
|
436
|
+
className: cn(
|
|
437
|
+
"relative h-2 w-full overflow-hidden rounded-full bg-muted",
|
|
438
|
+
className
|
|
439
|
+
),
|
|
440
|
+
...props,
|
|
441
|
+
children: /* @__PURE__ */ jsx5(
|
|
442
|
+
ProgressPrimitive.Indicator,
|
|
443
|
+
{
|
|
444
|
+
className: cn(
|
|
445
|
+
"h-full w-full flex-1 transition-all duration-300 ease-out",
|
|
446
|
+
indicatorVariants[variant]
|
|
447
|
+
),
|
|
448
|
+
style: { transform: `translateX(-${100 - (value || 0)}%)` }
|
|
449
|
+
}
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
showValue && /* @__PURE__ */ jsxs5("span", { className: "absolute -top-6 right-0 text-muted-foreground text-xs", children: [
|
|
454
|
+
value,
|
|
455
|
+
"%"
|
|
456
|
+
] })
|
|
457
|
+
] });
|
|
458
|
+
}
|
|
459
|
+
);
|
|
460
|
+
Progress.displayName = ProgressPrimitive.Root.displayName;
|
|
461
|
+
|
|
462
|
+
// src/primitives/switch.tsx
|
|
463
|
+
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
464
|
+
import * as React6 from "react";
|
|
465
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
466
|
+
var Switch = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
|
|
467
|
+
SwitchPrimitives.Root,
|
|
468
|
+
{
|
|
469
|
+
className: cn(
|
|
470
|
+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
471
|
+
className
|
|
472
|
+
),
|
|
473
|
+
...props,
|
|
474
|
+
ref,
|
|
475
|
+
children: /* @__PURE__ */ jsx6(
|
|
476
|
+
SwitchPrimitives.Thumb,
|
|
477
|
+
{
|
|
478
|
+
className: cn(
|
|
479
|
+
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
|
480
|
+
)
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
}
|
|
484
|
+
));
|
|
485
|
+
Switch.displayName = SwitchPrimitives.Root.displayName;
|
|
486
|
+
|
|
487
|
+
// src/primitives/skeleton.tsx
|
|
488
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
489
|
+
function Skeleton({
|
|
490
|
+
className,
|
|
491
|
+
...props
|
|
492
|
+
}) {
|
|
493
|
+
return /* @__PURE__ */ jsx7(
|
|
494
|
+
"div",
|
|
495
|
+
{
|
|
496
|
+
className: cn("animate-pulse rounded-lg bg-muted/50", className),
|
|
497
|
+
...props
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
function SkeletonCard({ className }) {
|
|
502
|
+
return /* @__PURE__ */ jsxs6(
|
|
503
|
+
"div",
|
|
504
|
+
{
|
|
505
|
+
className: cn(
|
|
506
|
+
"space-y-4 rounded-xl border border-border bg-card p-6",
|
|
507
|
+
className
|
|
508
|
+
),
|
|
509
|
+
children: [
|
|
510
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-3/4" }),
|
|
511
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/2" }),
|
|
512
|
+
/* @__PURE__ */ jsxs6("div", { className: "space-y-2 pt-4", children: [
|
|
513
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-3 w-full" }),
|
|
514
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-3 w-5/6" }),
|
|
515
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-3 w-4/6" })
|
|
516
|
+
] })
|
|
517
|
+
]
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
function SkeletonTable({ rows = 5 }) {
|
|
522
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-3", children: [
|
|
523
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex gap-4 border-border border-b pb-2", children: [
|
|
524
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
525
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
526
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
527
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" })
|
|
528
|
+
] }),
|
|
529
|
+
Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxs6("div", { className: "flex gap-4", children: [
|
|
530
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
531
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
532
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" }),
|
|
533
|
+
/* @__PURE__ */ jsx7(Skeleton, { className: "h-4 w-1/4" })
|
|
534
|
+
] }, i))
|
|
535
|
+
] });
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/primitives/toast.tsx
|
|
539
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
540
|
+
import {
|
|
541
|
+
AlertCircle,
|
|
542
|
+
AlertTriangle,
|
|
543
|
+
CheckCircle2,
|
|
544
|
+
Info,
|
|
545
|
+
X as X2
|
|
546
|
+
} from "lucide-react";
|
|
547
|
+
import * as React7 from "react";
|
|
548
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
549
|
+
var toastVariants = cva2(
|
|
550
|
+
"pointer-events-auto relative flex w-full items-center justify-between gap-3 overflow-hidden rounded-lg border p-4 shadow-lg transition-all",
|
|
551
|
+
{
|
|
552
|
+
variants: {
|
|
553
|
+
variant: {
|
|
554
|
+
default: "border-border bg-background text-foreground",
|
|
555
|
+
success: "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]",
|
|
556
|
+
error: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]",
|
|
557
|
+
warning: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]",
|
|
558
|
+
info: "border-[var(--surface-info-border)] bg-[var(--surface-info-bg)] text-[var(--surface-info-text)]"
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
defaultVariants: {
|
|
562
|
+
variant: "default"
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
var icons = {
|
|
567
|
+
success: CheckCircle2,
|
|
568
|
+
error: AlertCircle,
|
|
569
|
+
warning: AlertTriangle,
|
|
570
|
+
info: Info,
|
|
571
|
+
default: Info
|
|
572
|
+
};
|
|
573
|
+
function ToastComponent({
|
|
574
|
+
id,
|
|
575
|
+
title,
|
|
576
|
+
description,
|
|
577
|
+
variant = "default",
|
|
578
|
+
onDismiss
|
|
579
|
+
}) {
|
|
580
|
+
const Icon2 = icons[variant];
|
|
581
|
+
return /* @__PURE__ */ jsxs7(
|
|
582
|
+
"div",
|
|
583
|
+
{
|
|
584
|
+
className: cn(toastVariants({ variant })),
|
|
585
|
+
role: "alert",
|
|
586
|
+
"aria-live": "polite",
|
|
587
|
+
children: [
|
|
588
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-3", children: [
|
|
589
|
+
/* @__PURE__ */ jsx8(Icon2, { className: "h-5 w-5 shrink-0", "aria-hidden": "true" }),
|
|
590
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex-1", children: [
|
|
591
|
+
/* @__PURE__ */ jsx8("p", { className: "font-medium text-sm", children: title }),
|
|
592
|
+
description && /* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm opacity-80", children: description })
|
|
593
|
+
] })
|
|
594
|
+
] }),
|
|
595
|
+
/* @__PURE__ */ jsx8(
|
|
596
|
+
"button",
|
|
597
|
+
{
|
|
598
|
+
type: "button",
|
|
599
|
+
onClick: () => onDismiss(id),
|
|
600
|
+
className: "shrink-0 rounded-md p-1 opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
601
|
+
"aria-label": "Dismiss notification",
|
|
602
|
+
children: /* @__PURE__ */ jsx8(X2, { className: "h-4 w-4" })
|
|
603
|
+
}
|
|
604
|
+
)
|
|
605
|
+
]
|
|
606
|
+
}
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
function ToastContainer({ toasts, onDismiss }) {
|
|
610
|
+
return /* @__PURE__ */ jsx8(
|
|
611
|
+
"div",
|
|
612
|
+
{
|
|
613
|
+
className: "fixed right-4 bottom-4 z-50 flex max-w-md flex-col gap-2",
|
|
614
|
+
"aria-label": "Notifications",
|
|
615
|
+
children: toasts.map((toast) => /* @__PURE__ */ jsx8(ToastComponent, { ...toast, onDismiss }, toast.id))
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
var ToastContext = React7.createContext(null);
|
|
620
|
+
function ToastProvider({ children }) {
|
|
621
|
+
const [toasts, setToasts] = React7.useState([]);
|
|
622
|
+
const dismiss = React7.useCallback((id) => {
|
|
623
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
624
|
+
}, []);
|
|
625
|
+
const toast = React7.useCallback(
|
|
626
|
+
(input) => {
|
|
627
|
+
const id = Math.random().toString(36).slice(2);
|
|
628
|
+
const newToast = { id, ...input };
|
|
629
|
+
setToasts((prev) => [...prev, newToast]);
|
|
630
|
+
const duration = input.duration ?? 5e3;
|
|
631
|
+
if (duration > 0) {
|
|
632
|
+
setTimeout(() => dismiss(id), duration);
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
[dismiss]
|
|
636
|
+
);
|
|
637
|
+
const success = React7.useCallback(
|
|
638
|
+
(title, description) => {
|
|
639
|
+
toast({ title, description, variant: "success" });
|
|
640
|
+
},
|
|
641
|
+
[toast]
|
|
642
|
+
);
|
|
643
|
+
const error = React7.useCallback(
|
|
644
|
+
(title, description) => {
|
|
645
|
+
toast({ title, description, variant: "error" });
|
|
646
|
+
},
|
|
647
|
+
[toast]
|
|
648
|
+
);
|
|
649
|
+
const warning = React7.useCallback(
|
|
650
|
+
(title, description) => {
|
|
651
|
+
toast({ title, description, variant: "warning" });
|
|
652
|
+
},
|
|
653
|
+
[toast]
|
|
654
|
+
);
|
|
655
|
+
const info = React7.useCallback(
|
|
656
|
+
(title, description) => {
|
|
657
|
+
toast({ title, description, variant: "info" });
|
|
658
|
+
},
|
|
659
|
+
[toast]
|
|
660
|
+
);
|
|
661
|
+
const value = React7.useMemo(
|
|
662
|
+
() => ({ toasts, toast, success, error, warning, info, dismiss }),
|
|
663
|
+
[toasts, toast, success, error, warning, info, dismiss]
|
|
664
|
+
);
|
|
665
|
+
return /* @__PURE__ */ jsxs7(ToastContext.Provider, { value, children: [
|
|
666
|
+
children,
|
|
667
|
+
/* @__PURE__ */ jsx8(ToastContainer, { toasts, onDismiss: dismiss })
|
|
668
|
+
] });
|
|
669
|
+
}
|
|
670
|
+
function useToast() {
|
|
671
|
+
const context = React7.useContext(ToastContext);
|
|
672
|
+
if (!context) {
|
|
673
|
+
throw new Error("useToast must be used within a ToastProvider");
|
|
674
|
+
}
|
|
675
|
+
return context;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// src/primitives/label.tsx
|
|
679
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
680
|
+
import { cva as cva3 } from "class-variance-authority";
|
|
681
|
+
import * as React8 from "react";
|
|
682
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
683
|
+
var labelVariants = cva3(
|
|
684
|
+
"font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
685
|
+
);
|
|
686
|
+
var Label2 = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx9(
|
|
687
|
+
LabelPrimitive.Root,
|
|
688
|
+
{
|
|
689
|
+
ref,
|
|
690
|
+
className: cn(labelVariants(), className),
|
|
691
|
+
...props
|
|
692
|
+
}
|
|
693
|
+
));
|
|
694
|
+
Label2.displayName = LabelPrimitive.Root.displayName;
|
|
695
|
+
|
|
696
|
+
// src/primitives/empty-state.tsx
|
|
697
|
+
import * as React9 from "react";
|
|
698
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
699
|
+
var EmptyState = React9.forwardRef(
|
|
700
|
+
({ className, icon, title, description, action, ...props }, ref) => {
|
|
701
|
+
return /* @__PURE__ */ jsxs8(
|
|
702
|
+
"div",
|
|
703
|
+
{
|
|
704
|
+
ref,
|
|
705
|
+
className: cn(
|
|
706
|
+
"flex flex-col items-center justify-center px-4 py-16 text-center",
|
|
707
|
+
className
|
|
708
|
+
),
|
|
709
|
+
...props,
|
|
710
|
+
children: [
|
|
711
|
+
icon && /* @__PURE__ */ jsx10("div", { className: "mb-4 rounded-full bg-muted p-4 text-muted-foreground", children: icon }),
|
|
712
|
+
/* @__PURE__ */ jsx10("h3", { className: "font-semibold text-lg", children: title }),
|
|
713
|
+
description && /* @__PURE__ */ jsx10("p", { className: "mt-2 max-w-sm text-muted-foreground text-sm", children: description }),
|
|
714
|
+
action && /* @__PURE__ */ jsx10("div", { className: "mt-6", children: action })
|
|
715
|
+
]
|
|
716
|
+
}
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
EmptyState.displayName = "EmptyState";
|
|
721
|
+
|
|
722
|
+
// src/primitives/stat-card.tsx
|
|
723
|
+
import * as React10 from "react";
|
|
724
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
725
|
+
var StatCard = React10.forwardRef(
|
|
726
|
+
({
|
|
727
|
+
className,
|
|
728
|
+
variant = "default",
|
|
729
|
+
title,
|
|
730
|
+
value,
|
|
731
|
+
subtitle,
|
|
732
|
+
icon,
|
|
733
|
+
trend,
|
|
734
|
+
...props
|
|
735
|
+
}, ref) => {
|
|
736
|
+
const iconColors = {
|
|
737
|
+
default: "text-muted-foreground",
|
|
738
|
+
sandbox: "text-[var(--accent-text)]"
|
|
739
|
+
};
|
|
740
|
+
const trendColors = {
|
|
741
|
+
positive: "text-[var(--surface-success-text)]",
|
|
742
|
+
negative: "text-[var(--surface-danger-text)]",
|
|
743
|
+
neutral: "text-muted-foreground"
|
|
744
|
+
};
|
|
745
|
+
const trendStatus = trend ? trend.value > 0 ? "positive" : trend.value < 0 ? "negative" : "neutral" : null;
|
|
746
|
+
return /* @__PURE__ */ jsx11(
|
|
747
|
+
Card,
|
|
748
|
+
{
|
|
749
|
+
ref,
|
|
750
|
+
variant,
|
|
751
|
+
className: cn("p-6", className),
|
|
752
|
+
...props,
|
|
753
|
+
children: /* @__PURE__ */ jsxs9("div", { className: "flex items-start justify-between", children: [
|
|
754
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
|
|
755
|
+
/* @__PURE__ */ jsx11("p", { className: "text-muted-foreground text-sm", children: title }),
|
|
756
|
+
/* @__PURE__ */ jsx11("p", { className: "font-bold text-3xl tracking-tight", children: value }),
|
|
757
|
+
subtitle && /* @__PURE__ */ jsx11("p", { className: "text-muted-foreground opacity-70 text-xs", children: subtitle }),
|
|
758
|
+
trend && trendStatus && /* @__PURE__ */ jsxs9(
|
|
759
|
+
"div",
|
|
760
|
+
{
|
|
761
|
+
className: cn(
|
|
762
|
+
"flex items-center gap-1 text-sm",
|
|
763
|
+
trendColors[trendStatus]
|
|
764
|
+
),
|
|
765
|
+
children: [
|
|
766
|
+
trend.value > 0 ? "\u2191" : trend.value < 0 ? "\u2193" : "\u2192",
|
|
767
|
+
/* @__PURE__ */ jsxs9("span", { children: [
|
|
768
|
+
Math.abs(trend.value),
|
|
769
|
+
"%"
|
|
770
|
+
] }),
|
|
771
|
+
trend.label && /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: trend.label })
|
|
772
|
+
]
|
|
773
|
+
}
|
|
774
|
+
)
|
|
775
|
+
] }),
|
|
776
|
+
icon && /* @__PURE__ */ jsx11(
|
|
777
|
+
"div",
|
|
778
|
+
{
|
|
779
|
+
className: cn(
|
|
780
|
+
"rounded-lg bg-muted/50 p-2",
|
|
781
|
+
variant === "sandbox" && "bg-[var(--accent-surface-soft)]",
|
|
782
|
+
iconColors[variant]
|
|
783
|
+
),
|
|
784
|
+
children: icon
|
|
785
|
+
}
|
|
786
|
+
)
|
|
787
|
+
] })
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
);
|
|
792
|
+
StatCard.displayName = "StatCard";
|
|
793
|
+
|
|
794
|
+
// src/primitives/index.ts
|
|
795
|
+
import { Logo, TangleKnot } from "@tangle-network/brand";
|
|
796
|
+
|
|
797
|
+
// src/primitives/terminal-display.tsx
|
|
798
|
+
import * as React11 from "react";
|
|
799
|
+
import { useEffect, useRef as useRef2 } from "react";
|
|
800
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
801
|
+
var TerminalDisplay = React11.forwardRef(
|
|
802
|
+
({
|
|
803
|
+
className,
|
|
804
|
+
variant = "default",
|
|
805
|
+
title = "Terminal",
|
|
806
|
+
showHeader = true,
|
|
807
|
+
autoScroll = true,
|
|
808
|
+
maxHeight = "400px",
|
|
809
|
+
children,
|
|
810
|
+
...props
|
|
811
|
+
}, ref) => {
|
|
812
|
+
const containerRef = useRef2(null);
|
|
813
|
+
useEffect(() => {
|
|
814
|
+
if (autoScroll && containerRef.current) {
|
|
815
|
+
containerRef.current.scrollTop = containerRef.current.scrollHeight;
|
|
816
|
+
}
|
|
817
|
+
}, [autoScroll]);
|
|
818
|
+
const variants = {
|
|
819
|
+
default: "border-border",
|
|
820
|
+
sandbox: "border-border shadow-[var(--shadow-accent)]"
|
|
821
|
+
};
|
|
822
|
+
return /* @__PURE__ */ jsxs10(
|
|
823
|
+
"div",
|
|
824
|
+
{
|
|
825
|
+
ref,
|
|
826
|
+
className: cn(
|
|
827
|
+
"overflow-hidden rounded-xl border bg-background font-mono text-sm",
|
|
828
|
+
variants[variant],
|
|
829
|
+
className
|
|
830
|
+
),
|
|
831
|
+
...props,
|
|
832
|
+
children: [
|
|
833
|
+
showHeader && /* @__PURE__ */ jsx12("div", { className: "flex items-center border-b border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx12("span", { className: "text-muted-foreground text-xs", children: title }) }),
|
|
834
|
+
/* @__PURE__ */ jsx12(
|
|
835
|
+
"div",
|
|
836
|
+
{
|
|
837
|
+
ref: containerRef,
|
|
838
|
+
className: "overflow-auto p-4",
|
|
839
|
+
style: { maxHeight },
|
|
840
|
+
children
|
|
841
|
+
}
|
|
842
|
+
)
|
|
843
|
+
]
|
|
844
|
+
}
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
);
|
|
848
|
+
TerminalDisplay.displayName = "TerminalDisplay";
|
|
849
|
+
var TerminalLine = React11.forwardRef(
|
|
850
|
+
({ className, type = "output", prompt = "$", timestamp, children, ...props }, ref) => {
|
|
851
|
+
const typeStyles = {
|
|
852
|
+
input: "text-foreground",
|
|
853
|
+
output: "text-foreground",
|
|
854
|
+
error: "text-[var(--surface-danger-text)]",
|
|
855
|
+
success: "text-[var(--surface-success-text)]",
|
|
856
|
+
info: "text-[var(--surface-info-text)]",
|
|
857
|
+
thinking: "text-[var(--surface-warning-text)] animate-pulse",
|
|
858
|
+
command: "text-foreground",
|
|
859
|
+
warning: "text-[var(--surface-warning-text)]"
|
|
860
|
+
};
|
|
861
|
+
return /* @__PURE__ */ jsxs10(
|
|
862
|
+
"div",
|
|
863
|
+
{
|
|
864
|
+
ref,
|
|
865
|
+
className: cn(
|
|
866
|
+
"flex items-start gap-2 py-0.5 leading-relaxed",
|
|
867
|
+
typeStyles[type],
|
|
868
|
+
className
|
|
869
|
+
),
|
|
870
|
+
...props,
|
|
871
|
+
children: [
|
|
872
|
+
(type === "input" || type === "command") && /* @__PURE__ */ jsx12("span", { className: "shrink-0 select-none text-[var(--surface-success-text)]", children: prompt }),
|
|
873
|
+
type === "thinking" && /* @__PURE__ */ jsx12("span", { className: "shrink-0 select-none", children: "..." }),
|
|
874
|
+
timestamp && /* @__PURE__ */ jsxs10("span", { className: "shrink-0 select-none text-muted-foreground opacity-50", children: [
|
|
875
|
+
"[",
|
|
876
|
+
timestamp,
|
|
877
|
+
"]"
|
|
878
|
+
] }),
|
|
879
|
+
/* @__PURE__ */ jsx12("span", { className: "whitespace-pre-wrap break-all", children })
|
|
880
|
+
]
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
);
|
|
885
|
+
TerminalLine.displayName = "TerminalLine";
|
|
886
|
+
var TerminalCursor = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
|
|
887
|
+
"span",
|
|
888
|
+
{
|
|
889
|
+
ref,
|
|
890
|
+
className: cn(
|
|
891
|
+
"ml-0.5 inline-block h-4 w-2 animate-pulse bg-foreground",
|
|
892
|
+
className
|
|
893
|
+
),
|
|
894
|
+
...props
|
|
895
|
+
}
|
|
896
|
+
));
|
|
897
|
+
TerminalCursor.displayName = "TerminalCursor";
|
|
898
|
+
var TerminalInput = React11.forwardRef(
|
|
899
|
+
({ className, onSubmit, variant = "default", ...props }, ref) => {
|
|
900
|
+
const [value, setValue] = React11.useState("");
|
|
901
|
+
const handleKeyDown = (e) => {
|
|
902
|
+
if (e.key === "Enter" && value.trim() && onSubmit) {
|
|
903
|
+
onSubmit(value.trim());
|
|
904
|
+
setValue("");
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
const variants = {
|
|
908
|
+
default: "border-border focus-within:border-border",
|
|
909
|
+
sandbox: "border-border focus-within:border-[var(--border-accent-hover)]"
|
|
910
|
+
};
|
|
911
|
+
return /* @__PURE__ */ jsxs10(
|
|
912
|
+
"div",
|
|
913
|
+
{
|
|
914
|
+
className: cn(
|
|
915
|
+
"flex items-center rounded-lg border bg-background px-4 py-2.5 font-mono text-sm transition-colors",
|
|
916
|
+
variants[variant],
|
|
917
|
+
className
|
|
918
|
+
),
|
|
919
|
+
children: [
|
|
920
|
+
/* @__PURE__ */ jsx12("span", { className: "mr-2 select-none text-[var(--surface-success-text)]", children: "$" }),
|
|
921
|
+
/* @__PURE__ */ jsx12(
|
|
922
|
+
"input",
|
|
923
|
+
{
|
|
924
|
+
ref,
|
|
925
|
+
type: "text",
|
|
926
|
+
value,
|
|
927
|
+
onChange: (e) => setValue(e.target.value),
|
|
928
|
+
onKeyDown: handleKeyDown,
|
|
929
|
+
className: "flex-1 bg-transparent text-foreground outline-none placeholder:text-muted-foreground",
|
|
930
|
+
...props
|
|
931
|
+
}
|
|
932
|
+
),
|
|
933
|
+
/* @__PURE__ */ jsx12(TerminalCursor, {})
|
|
934
|
+
]
|
|
935
|
+
}
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
);
|
|
939
|
+
TerminalInput.displayName = "TerminalInput";
|
|
940
|
+
|
|
941
|
+
// src/primitives/drop-zone.tsx
|
|
942
|
+
import { useCallback as useCallback2, useRef as useRef3, useState as useState3 } from "react";
|
|
943
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
944
|
+
function DropZone({
|
|
945
|
+
onDrop,
|
|
946
|
+
accept,
|
|
947
|
+
disabled,
|
|
948
|
+
overlay,
|
|
949
|
+
title = "Drop files to upload",
|
|
950
|
+
description = "Your files will be securely stored in the workspace.",
|
|
951
|
+
icon = "cloud_upload",
|
|
952
|
+
children,
|
|
953
|
+
className
|
|
954
|
+
}) {
|
|
955
|
+
const [dragOver, setDragOver] = useState3(false);
|
|
956
|
+
const counter = useRef3(0);
|
|
957
|
+
const isAccepted = useCallback2(
|
|
958
|
+
(file) => {
|
|
959
|
+
if (!accept) return true;
|
|
960
|
+
const extensions = accept.split(",").map((ext) => ext.trim().toLowerCase());
|
|
961
|
+
const fileName = file.name.toLowerCase();
|
|
962
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
963
|
+
},
|
|
964
|
+
[accept]
|
|
965
|
+
);
|
|
966
|
+
const handleDragEnter = useCallback2(
|
|
967
|
+
(e) => {
|
|
968
|
+
e.preventDefault();
|
|
969
|
+
if (disabled) return;
|
|
970
|
+
counter.current++;
|
|
971
|
+
if (e.dataTransfer?.types.includes("Files")) setDragOver(true);
|
|
972
|
+
},
|
|
973
|
+
[disabled]
|
|
974
|
+
);
|
|
975
|
+
const handleDragLeave = useCallback2((e) => {
|
|
976
|
+
e.preventDefault();
|
|
977
|
+
counter.current--;
|
|
978
|
+
if (counter.current === 0) setDragOver(false);
|
|
979
|
+
}, []);
|
|
980
|
+
const handleDragOver = useCallback2(
|
|
981
|
+
(e) => {
|
|
982
|
+
e.preventDefault();
|
|
983
|
+
if (!disabled) e.dataTransfer.dropEffect = "copy";
|
|
984
|
+
},
|
|
985
|
+
[disabled]
|
|
986
|
+
);
|
|
987
|
+
const handleDrop = useCallback2(
|
|
988
|
+
(e) => {
|
|
989
|
+
e.preventDefault();
|
|
990
|
+
counter.current = 0;
|
|
991
|
+
setDragOver(false);
|
|
992
|
+
if (disabled) return;
|
|
993
|
+
const allFiles = Array.from(e.dataTransfer?.files || []);
|
|
994
|
+
const accepted = accept ? allFiles.filter(isAccepted) : allFiles;
|
|
995
|
+
if (accepted.length > 0) onDrop(accepted);
|
|
996
|
+
},
|
|
997
|
+
[disabled, accept, isAccepted, onDrop]
|
|
998
|
+
);
|
|
999
|
+
return /* @__PURE__ */ jsxs11(
|
|
1000
|
+
"div",
|
|
1001
|
+
{
|
|
1002
|
+
onDragEnter: handleDragEnter,
|
|
1003
|
+
onDragLeave: handleDragLeave,
|
|
1004
|
+
onDragOver: handleDragOver,
|
|
1005
|
+
onDrop: handleDrop,
|
|
1006
|
+
className: cn("relative", className),
|
|
1007
|
+
children: [
|
|
1008
|
+
dragOver && (overlay || /* @__PURE__ */ jsx13("div", { className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none bg-background", children: /* @__PURE__ */ jsxs11("div", { className: "rounded-2xl border-2 border-dashed border-border bg-card p-16 text-center shadow-[var(--shadow-dropdown)] max-w-lg mx-auto", children: [
|
|
1009
|
+
/* @__PURE__ */ jsx13("div", { className: "mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-2xl border border-border bg-[var(--accent-surface-soft)]", children: typeof icon === "string" ? /* @__PURE__ */ jsxs11("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "h-10 w-10 text-[var(--accent-text)]", children: [
|
|
1010
|
+
/* @__PURE__ */ jsx13("title", { children: "Upload" }),
|
|
1011
|
+
/* @__PURE__ */ jsx13("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1012
|
+
/* @__PURE__ */ jsx13("polyline", { points: "17 8 12 3 7 8" }),
|
|
1013
|
+
/* @__PURE__ */ jsx13("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
|
|
1014
|
+
] }) : icon }),
|
|
1015
|
+
/* @__PURE__ */ jsx13("h2", { className: "text-2xl font-bold text-foreground", children: title }),
|
|
1016
|
+
/* @__PURE__ */ jsx13("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
1017
|
+
] }) })),
|
|
1018
|
+
children
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// src/primitives/upload-progress.tsx
|
|
1025
|
+
import { AlertCircle as AlertCircle2, CheckCircle2 as CheckCircle22, FileText, Loader2, RefreshCw, X as X3 } from "lucide-react";
|
|
1026
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1027
|
+
function formatSize(bytes) {
|
|
1028
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
1029
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
|
|
1030
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
1031
|
+
}
|
|
1032
|
+
function UploadProgress({ files, onRemove, onRetry, className }) {
|
|
1033
|
+
if (files.length === 0) return null;
|
|
1034
|
+
return /* @__PURE__ */ jsx14("div", { className: cn("space-y-2", className), children: files.map((file) => /* @__PURE__ */ jsxs12(
|
|
1035
|
+
"div",
|
|
1036
|
+
{
|
|
1037
|
+
className: cn(
|
|
1038
|
+
"flex items-center gap-3 rounded-lg border px-3 py-2 text-sm",
|
|
1039
|
+
file.status === "error" ? "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)]" : file.status === "complete" ? "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]" : "border-border bg-card"
|
|
1040
|
+
),
|
|
1041
|
+
children: [
|
|
1042
|
+
file.status === "complete" && /* @__PURE__ */ jsx14(CheckCircle22, { className: "h-4 w-4 shrink-0 text-[var(--surface-success-text)]" }),
|
|
1043
|
+
file.status === "error" && /* @__PURE__ */ jsx14(AlertCircle2, { className: "h-4 w-4 shrink-0 text-[var(--surface-danger-text)]" }),
|
|
1044
|
+
file.status === "uploading" && /* @__PURE__ */ jsx14(Loader2, { className: "h-4 w-4 shrink-0 animate-spin text-primary" }),
|
|
1045
|
+
file.status === "pending" && /* @__PURE__ */ jsx14(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
1046
|
+
/* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
|
|
1047
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1048
|
+
/* @__PURE__ */ jsx14("span", { className: "truncate font-medium text-foreground", children: file.name }),
|
|
1049
|
+
/* @__PURE__ */ jsx14("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatSize(file.size) })
|
|
1050
|
+
] }),
|
|
1051
|
+
file.status === "uploading" && file.progress !== void 0 && /* @__PURE__ */ jsx14("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted/50", children: /* @__PURE__ */ jsx14(
|
|
1052
|
+
"div",
|
|
1053
|
+
{
|
|
1054
|
+
className: "h-full rounded-full bg-primary transition-all",
|
|
1055
|
+
style: { width: `${file.progress}%` }
|
|
1056
|
+
}
|
|
1057
|
+
) }),
|
|
1058
|
+
file.status === "error" && file.error && /* @__PURE__ */ jsx14("p", { className: "mt-0.5 text-xs text-[var(--surface-danger-text)]", children: file.error })
|
|
1059
|
+
] }),
|
|
1060
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1061
|
+
file.status === "error" && onRetry && /* @__PURE__ */ jsx14(
|
|
1062
|
+
"button",
|
|
1063
|
+
{
|
|
1064
|
+
type: "button",
|
|
1065
|
+
onClick: () => onRetry(file.id),
|
|
1066
|
+
className: "rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1067
|
+
children: /* @__PURE__ */ jsx14(RefreshCw, { className: "h-3.5 w-3.5" })
|
|
1068
|
+
}
|
|
1069
|
+
),
|
|
1070
|
+
onRemove && /* @__PURE__ */ jsx14(
|
|
1071
|
+
"button",
|
|
1072
|
+
{
|
|
1073
|
+
type: "button",
|
|
1074
|
+
onClick: () => onRemove(file.id),
|
|
1075
|
+
className: "rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
|
|
1076
|
+
children: /* @__PURE__ */ jsx14(X3, { className: "h-3.5 w-3.5" })
|
|
1077
|
+
}
|
|
1078
|
+
)
|
|
1079
|
+
] })
|
|
1080
|
+
]
|
|
1081
|
+
},
|
|
1082
|
+
file.id
|
|
1083
|
+
)) });
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/primitives/sidebar-drop-zone.tsx
|
|
1087
|
+
import { useCallback as useCallback3, useRef as useRef4, useState as useState4 } from "react";
|
|
1088
|
+
import { Upload } from "lucide-react";
|
|
1089
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1090
|
+
function SidebarDropZone({
|
|
1091
|
+
onDrop,
|
|
1092
|
+
accept,
|
|
1093
|
+
disabled,
|
|
1094
|
+
title = "Drop files here",
|
|
1095
|
+
description,
|
|
1096
|
+
icon,
|
|
1097
|
+
persistent = false,
|
|
1098
|
+
className
|
|
1099
|
+
}) {
|
|
1100
|
+
const [dragOver, setDragOver] = useState4(false);
|
|
1101
|
+
const counter = useRef4(0);
|
|
1102
|
+
const isAccepted = useCallback3(
|
|
1103
|
+
(file) => {
|
|
1104
|
+
if (!accept) return true;
|
|
1105
|
+
const extensions = accept.split(",").map((ext) => ext.trim().toLowerCase());
|
|
1106
|
+
const fileName = file.name.toLowerCase();
|
|
1107
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
1108
|
+
},
|
|
1109
|
+
[accept]
|
|
1110
|
+
);
|
|
1111
|
+
const handleDragEnter = useCallback3(
|
|
1112
|
+
(e) => {
|
|
1113
|
+
e.preventDefault();
|
|
1114
|
+
e.stopPropagation();
|
|
1115
|
+
if (disabled) return;
|
|
1116
|
+
counter.current++;
|
|
1117
|
+
if (e.dataTransfer?.types.includes("Files")) setDragOver(true);
|
|
1118
|
+
},
|
|
1119
|
+
[disabled]
|
|
1120
|
+
);
|
|
1121
|
+
const handleDragLeave = useCallback3((e) => {
|
|
1122
|
+
e.preventDefault();
|
|
1123
|
+
e.stopPropagation();
|
|
1124
|
+
counter.current--;
|
|
1125
|
+
if (counter.current === 0) setDragOver(false);
|
|
1126
|
+
}, []);
|
|
1127
|
+
const handleDragOver = useCallback3(
|
|
1128
|
+
(e) => {
|
|
1129
|
+
e.preventDefault();
|
|
1130
|
+
e.stopPropagation();
|
|
1131
|
+
if (!disabled) e.dataTransfer.dropEffect = "copy";
|
|
1132
|
+
},
|
|
1133
|
+
[disabled]
|
|
1134
|
+
);
|
|
1135
|
+
const handleDrop = useCallback3(
|
|
1136
|
+
(e) => {
|
|
1137
|
+
e.preventDefault();
|
|
1138
|
+
e.stopPropagation();
|
|
1139
|
+
counter.current = 0;
|
|
1140
|
+
setDragOver(false);
|
|
1141
|
+
if (disabled) return;
|
|
1142
|
+
const allFiles = Array.from(e.dataTransfer?.files || []);
|
|
1143
|
+
const accepted = accept ? allFiles.filter(isAccepted) : allFiles;
|
|
1144
|
+
if (accepted.length > 0) onDrop(accepted);
|
|
1145
|
+
},
|
|
1146
|
+
[disabled, accept, isAccepted, onDrop]
|
|
1147
|
+
);
|
|
1148
|
+
const isVisible = persistent || dragOver;
|
|
1149
|
+
return /* @__PURE__ */ jsx15(
|
|
1150
|
+
"div",
|
|
1151
|
+
{
|
|
1152
|
+
onDragEnter: handleDragEnter,
|
|
1153
|
+
onDragLeave: handleDragLeave,
|
|
1154
|
+
onDragOver: handleDragOver,
|
|
1155
|
+
onDrop: handleDrop,
|
|
1156
|
+
className: cn(
|
|
1157
|
+
"rounded-lg border-2 border-dashed transition-all duration-150",
|
|
1158
|
+
isVisible ? "p-4" : "p-0 border-transparent",
|
|
1159
|
+
dragOver ? "border-[var(--brand-cool,hsl(var(--ring)))] bg-[var(--accent-surface-soft)]" : persistent ? "border-[var(--border-subtle,hsl(var(--border)))] bg-transparent hover:border-[var(--border-default,hsl(var(--border)))] hover:bg-[var(--bg-hover,hsl(var(--accent)))]" : "",
|
|
1160
|
+
disabled && "opacity-50 pointer-events-none",
|
|
1161
|
+
className
|
|
1162
|
+
),
|
|
1163
|
+
children: isVisible && /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center gap-2 text-center", children: [
|
|
1164
|
+
/* @__PURE__ */ jsx15("div", { className: cn(
|
|
1165
|
+
"flex h-8 w-8 items-center justify-center rounded-lg transition-colors",
|
|
1166
|
+
dragOver ? "bg-[var(--brand-cool,hsl(var(--primary)))]/15 text-[var(--brand-cool,hsl(var(--primary)))]" : "text-[var(--text-muted,hsl(var(--muted-foreground)))]"
|
|
1167
|
+
), children: icon ?? /* @__PURE__ */ jsx15(Upload, { className: "h-4 w-4" }) }),
|
|
1168
|
+
/* @__PURE__ */ jsx15("p", { className: cn(
|
|
1169
|
+
"text-xs font-medium",
|
|
1170
|
+
dragOver ? "text-[var(--text-primary,hsl(var(--foreground)))]" : "text-[var(--text-muted,hsl(var(--muted-foreground)))]"
|
|
1171
|
+
), children: title }),
|
|
1172
|
+
description && /* @__PURE__ */ jsx15("p", { className: "text-[10px] text-[var(--text-muted,hsl(var(--muted-foreground)))]", children: description })
|
|
1173
|
+
] })
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
export {
|
|
1179
|
+
Dialog,
|
|
1180
|
+
DialogTrigger,
|
|
1181
|
+
DialogPortal,
|
|
1182
|
+
DialogClose,
|
|
1183
|
+
DialogOverlay,
|
|
1184
|
+
DialogContent,
|
|
1185
|
+
DialogHeader,
|
|
1186
|
+
DialogFooter,
|
|
1187
|
+
DialogTitle,
|
|
1188
|
+
DialogDescription,
|
|
1189
|
+
Input,
|
|
1190
|
+
Textarea,
|
|
1191
|
+
Select,
|
|
1192
|
+
SelectGroup,
|
|
1193
|
+
SelectValue,
|
|
1194
|
+
SelectTrigger,
|
|
1195
|
+
SelectScrollUpButton,
|
|
1196
|
+
SelectScrollDownButton,
|
|
1197
|
+
SelectContent,
|
|
1198
|
+
SelectLabel,
|
|
1199
|
+
SelectItem,
|
|
1200
|
+
SelectSeparator,
|
|
1201
|
+
SegmentedControl,
|
|
1202
|
+
Progress,
|
|
1203
|
+
Switch,
|
|
1204
|
+
Skeleton,
|
|
1205
|
+
SkeletonCard,
|
|
1206
|
+
SkeletonTable,
|
|
1207
|
+
ToastContainer,
|
|
1208
|
+
ToastProvider,
|
|
1209
|
+
useToast,
|
|
1210
|
+
Label2 as Label,
|
|
1211
|
+
EmptyState,
|
|
1212
|
+
StatCard,
|
|
1213
|
+
TerminalDisplay,
|
|
1214
|
+
TerminalLine,
|
|
1215
|
+
TerminalCursor,
|
|
1216
|
+
TerminalInput,
|
|
1217
|
+
DropZone,
|
|
1218
|
+
UploadProgress,
|
|
1219
|
+
SidebarDropZone,
|
|
1220
|
+
Logo,
|
|
1221
|
+
TangleKnot
|
|
1222
|
+
};
|