@cortexasystem/ui 0.1.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/dist/index.cjs +2137 -0
- package/dist/index.d.cts +525 -0
- package/dist/index.d.ts +525 -0
- package/dist/index.js +1977 -0
- package/dist/isotipo-cortexa-dark-F2MDSEEV.png +0 -0
- package/dist/isotipo-cortexa-light-LV3O6ASR.png +0 -0
- package/package.json +61 -0
- package/src/styles.css +2 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1977 @@
|
|
|
1
|
+
// src/providers/theme-provider.tsx
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState
|
|
8
|
+
} from "react";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
var ThemeProviderContext = createContext(void 0);
|
|
11
|
+
function resolveTheme(theme) {
|
|
12
|
+
if (theme === "system") {
|
|
13
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
14
|
+
}
|
|
15
|
+
return theme;
|
|
16
|
+
}
|
|
17
|
+
function ThemeProvider({
|
|
18
|
+
children,
|
|
19
|
+
defaultTheme = "system",
|
|
20
|
+
forcedTheme,
|
|
21
|
+
storageKey = "cortexa-theme"
|
|
22
|
+
}) {
|
|
23
|
+
const [theme, setThemeState] = useState(() => {
|
|
24
|
+
if (typeof window === "undefined") {
|
|
25
|
+
return forcedTheme ?? defaultTheme;
|
|
26
|
+
}
|
|
27
|
+
return window.localStorage.getItem(storageKey) ?? forcedTheme ?? defaultTheme;
|
|
28
|
+
});
|
|
29
|
+
const activeTheme = forcedTheme ?? theme;
|
|
30
|
+
const resolvedTheme = typeof window === "undefined" ? "light" : resolveTheme(activeTheme);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const root = document.documentElement;
|
|
33
|
+
root.classList.remove("light", "dark");
|
|
34
|
+
root.classList.add(resolvedTheme);
|
|
35
|
+
}, [resolvedTheme]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (forcedTheme || typeof window === "undefined") {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
window.localStorage.setItem(storageKey, theme);
|
|
41
|
+
}, [forcedTheme, storageKey, theme]);
|
|
42
|
+
const value = useMemo(
|
|
43
|
+
() => ({
|
|
44
|
+
theme: activeTheme,
|
|
45
|
+
resolvedTheme,
|
|
46
|
+
setTheme: (nextTheme) => {
|
|
47
|
+
if (!forcedTheme) {
|
|
48
|
+
setThemeState(nextTheme);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}),
|
|
52
|
+
[activeTheme, forcedTheme, resolvedTheme]
|
|
53
|
+
);
|
|
54
|
+
return /* @__PURE__ */ jsx(ThemeProviderContext.Provider, { value, children });
|
|
55
|
+
}
|
|
56
|
+
function useTheme() {
|
|
57
|
+
const context = useContext(ThemeProviderContext);
|
|
58
|
+
if (!context) {
|
|
59
|
+
throw new Error("useTheme must be used within ThemeProvider");
|
|
60
|
+
}
|
|
61
|
+
return context;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/lib/cn.ts
|
|
65
|
+
import { clsx } from "clsx";
|
|
66
|
+
import { twMerge } from "tailwind-merge";
|
|
67
|
+
function cn(...inputs) {
|
|
68
|
+
return twMerge(clsx(inputs));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/assets/isotipo-cortexa-dark.png
|
|
72
|
+
var isotipo_cortexa_dark_default = "./isotipo-cortexa-dark-F2MDSEEV.png";
|
|
73
|
+
|
|
74
|
+
// src/assets/isotipo-cortexa-light.png
|
|
75
|
+
var isotipo_cortexa_light_default = "./isotipo-cortexa-light-LV3O6ASR.png";
|
|
76
|
+
|
|
77
|
+
// src/components/branding/brand-logo.tsx
|
|
78
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
79
|
+
var sizeMap = {
|
|
80
|
+
sm: { icon: "h-6 w-6", text: "text-sm", gap: "gap-2" },
|
|
81
|
+
md: { icon: "h-7 w-7", text: "text-lg", gap: "gap-3" },
|
|
82
|
+
lg: { icon: "h-9 w-9", text: "text-xl", gap: "gap-3" }
|
|
83
|
+
};
|
|
84
|
+
function BrandLogo({ className, size = "md", href }) {
|
|
85
|
+
const { resolvedTheme } = useTheme();
|
|
86
|
+
const isDark = resolvedTheme === "dark";
|
|
87
|
+
const s = sizeMap[size];
|
|
88
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx2(
|
|
90
|
+
"div",
|
|
91
|
+
{
|
|
92
|
+
className: cn(
|
|
93
|
+
"flex shrink-0 items-center justify-center rounded-md",
|
|
94
|
+
s.icon,
|
|
95
|
+
isDark ? "bg-[var(--color-brand)] p-1" : "bg-transparent"
|
|
96
|
+
),
|
|
97
|
+
children: /* @__PURE__ */ jsx2(
|
|
98
|
+
"img",
|
|
99
|
+
{
|
|
100
|
+
src: isDark ? isotipo_cortexa_dark_default : isotipo_cortexa_light_default,
|
|
101
|
+
alt: "Cortexa",
|
|
102
|
+
className: "max-h-full max-w-full object-contain"
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline", children: [
|
|
108
|
+
/* @__PURE__ */ jsx2(
|
|
109
|
+
"span",
|
|
110
|
+
{
|
|
111
|
+
className: cn(
|
|
112
|
+
"font-bold leading-none",
|
|
113
|
+
s.text,
|
|
114
|
+
isDark ? "text-white" : "text-[var(--color-brand)]"
|
|
115
|
+
),
|
|
116
|
+
children: "Cortexa"
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
/* @__PURE__ */ jsx2(
|
|
120
|
+
"span",
|
|
121
|
+
{
|
|
122
|
+
className: cn(
|
|
123
|
+
"ml-1 font-normal leading-none",
|
|
124
|
+
s.text,
|
|
125
|
+
isDark ? "text-white" : "text-[var(--color-accent-blue)]"
|
|
126
|
+
),
|
|
127
|
+
children: "Fiscal"
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
] })
|
|
131
|
+
] });
|
|
132
|
+
const wrapperClass = cn("flex items-center", s.gap, className);
|
|
133
|
+
if (href) {
|
|
134
|
+
return /* @__PURE__ */ jsx2("a", { href, className: wrapperClass, "aria-label": "Cortexa Fiscal \u2014 Inicio", children: content });
|
|
135
|
+
}
|
|
136
|
+
return /* @__PURE__ */ jsx2("div", { className: wrapperClass, "aria-label": "Cortexa Fiscal", children: content });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/components/data-display/icons.tsx
|
|
140
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
141
|
+
var toneStyles = {
|
|
142
|
+
brand: "bg-[var(--color-brand)]/10 text-[var(--color-brand)]",
|
|
143
|
+
info: "bg-[var(--color-info-bg)] text-[var(--color-accent-blue)]",
|
|
144
|
+
success: "bg-[var(--color-success-bg)] text-[var(--color-success)]",
|
|
145
|
+
warning: "bg-[var(--color-warning-bg)] text-[var(--color-warning)]",
|
|
146
|
+
danger: "bg-destructive/10 text-destructive",
|
|
147
|
+
neutral: "bg-muted text-muted-foreground"
|
|
148
|
+
};
|
|
149
|
+
var sizeStyles = {
|
|
150
|
+
sm: { wrapper: "h-8 w-8 rounded-lg", icon: "h-4 w-4" },
|
|
151
|
+
md: { wrapper: "h-10 w-10 rounded-lg", icon: "h-5 w-5" },
|
|
152
|
+
lg: { wrapper: "h-12 w-12 rounded-xl", icon: "h-6 w-6" }
|
|
153
|
+
};
|
|
154
|
+
function FeatureIcon({ className, icon: Icon2, tone = "brand", size = "md", iconClassName }) {
|
|
155
|
+
const classes = sizeStyles[size];
|
|
156
|
+
return /* @__PURE__ */ jsx3("span", { className: cn("inline-flex items-center justify-center", classes.wrapper, toneStyles[tone], className), children: /* @__PURE__ */ jsx3(Icon2, { className: cn(classes.icon, iconClassName) }) });
|
|
157
|
+
}
|
|
158
|
+
function ModuleIconButton({
|
|
159
|
+
className,
|
|
160
|
+
type = "button",
|
|
161
|
+
icon,
|
|
162
|
+
label,
|
|
163
|
+
description,
|
|
164
|
+
tone = "brand",
|
|
165
|
+
...props
|
|
166
|
+
}) {
|
|
167
|
+
return /* @__PURE__ */ jsxs2(
|
|
168
|
+
"button",
|
|
169
|
+
{
|
|
170
|
+
type,
|
|
171
|
+
className: cn(
|
|
172
|
+
"group flex flex-col items-center gap-3 rounded-lg border border-border bg-card p-5 text-center transition-all hover:bg-accent/30 hover:border-[var(--color-accent-blue)]/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
173
|
+
className
|
|
174
|
+
),
|
|
175
|
+
...props,
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsx3(
|
|
178
|
+
FeatureIcon,
|
|
179
|
+
{
|
|
180
|
+
icon,
|
|
181
|
+
tone,
|
|
182
|
+
size: "md",
|
|
183
|
+
className: "transition-colors group-hover:bg-[var(--color-brand)]/20"
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsxs2("span", { className: "grid gap-1", children: [
|
|
187
|
+
/* @__PURE__ */ jsx3("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
188
|
+
description ? /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
189
|
+
] })
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/components/primitives/avatar.tsx
|
|
196
|
+
import * as React from "react";
|
|
197
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
198
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
199
|
+
var Avatar = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
200
|
+
AvatarPrimitive.Root,
|
|
201
|
+
{
|
|
202
|
+
ref,
|
|
203
|
+
className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
|
|
204
|
+
...props
|
|
205
|
+
}
|
|
206
|
+
));
|
|
207
|
+
Avatar.displayName = AvatarPrimitive.Root.displayName;
|
|
208
|
+
var AvatarImage = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(AvatarPrimitive.Image, { ref, className: cn("aspect-square h-full w-full", className), ...props }));
|
|
209
|
+
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
|
|
210
|
+
var AvatarFallback = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
|
|
211
|
+
AvatarPrimitive.Fallback,
|
|
212
|
+
{
|
|
213
|
+
ref,
|
|
214
|
+
className: cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className),
|
|
215
|
+
...props
|
|
216
|
+
}
|
|
217
|
+
));
|
|
218
|
+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
|
|
219
|
+
|
|
220
|
+
// src/components/data-display/profile-avatar.tsx
|
|
221
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
222
|
+
var sizeMap2 = {
|
|
223
|
+
xs: { avatar: "h-8 w-8", text: "text-xs", dot: "h-2.5 w-2.5" },
|
|
224
|
+
sm: { avatar: "h-10 w-10", text: "text-sm", dot: "h-3 w-3" },
|
|
225
|
+
md: { avatar: "h-12 w-12", text: "text-base", dot: "h-3.5 w-3.5" },
|
|
226
|
+
lg: { avatar: "h-16 w-16", text: "text-lg", dot: "h-4 w-4" }
|
|
227
|
+
};
|
|
228
|
+
var statusMap = {
|
|
229
|
+
online: "bg-[var(--color-success)]",
|
|
230
|
+
away: "bg-[var(--color-warning)]",
|
|
231
|
+
offline: "bg-muted-foreground",
|
|
232
|
+
inactive: "bg-border"
|
|
233
|
+
};
|
|
234
|
+
function getInitials(name) {
|
|
235
|
+
return name.trim().split(/\s+/).slice(0, 2).map((part) => part[0]?.toUpperCase() ?? "").join("");
|
|
236
|
+
}
|
|
237
|
+
function ProfileAvatar({
|
|
238
|
+
className,
|
|
239
|
+
avatarClassName,
|
|
240
|
+
fallbackClassName,
|
|
241
|
+
name,
|
|
242
|
+
src,
|
|
243
|
+
alt,
|
|
244
|
+
initials,
|
|
245
|
+
size = "sm",
|
|
246
|
+
status
|
|
247
|
+
}) {
|
|
248
|
+
const classes = sizeMap2[size];
|
|
249
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("relative inline-flex", className), children: [
|
|
250
|
+
/* @__PURE__ */ jsxs3(Avatar, { className: cn(classes.avatar, avatarClassName), children: [
|
|
251
|
+
src ? /* @__PURE__ */ jsx5(AvatarImage, { src, alt: alt ?? name }) : null,
|
|
252
|
+
/* @__PURE__ */ jsx5(AvatarFallback, { className: cn("bg-[var(--color-brand)] text-white font-medium", classes.text, fallbackClassName), children: initials ?? getInitials(name) })
|
|
253
|
+
] }),
|
|
254
|
+
status ? /* @__PURE__ */ jsx5(
|
|
255
|
+
"span",
|
|
256
|
+
{
|
|
257
|
+
"aria-hidden": "true",
|
|
258
|
+
className: cn("absolute bottom-0 right-0 rounded-full border-2 border-card", classes.dot, statusMap[status])
|
|
259
|
+
}
|
|
260
|
+
) : null
|
|
261
|
+
] });
|
|
262
|
+
}
|
|
263
|
+
function AvatarGroup({ className, users, size = "xs", limit = 4, extraLabel }) {
|
|
264
|
+
const visibleUsers = users.slice(0, limit);
|
|
265
|
+
const hiddenCount = Math.max(0, users.length - limit);
|
|
266
|
+
const classes = sizeMap2[size];
|
|
267
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("flex items-center gap-3", className), children: [
|
|
268
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex -space-x-2", children: [
|
|
269
|
+
visibleUsers.map((user) => /* @__PURE__ */ jsx5(
|
|
270
|
+
ProfileAvatar,
|
|
271
|
+
{
|
|
272
|
+
name: user.name,
|
|
273
|
+
src: user.src,
|
|
274
|
+
initials: user.initials,
|
|
275
|
+
size,
|
|
276
|
+
status: user.status,
|
|
277
|
+
avatarClassName: "border-2 border-card"
|
|
278
|
+
},
|
|
279
|
+
user.id ?? user.name
|
|
280
|
+
)),
|
|
281
|
+
hiddenCount > 0 ? /* @__PURE__ */ jsxs3(
|
|
282
|
+
"div",
|
|
283
|
+
{
|
|
284
|
+
className: cn(
|
|
285
|
+
"flex items-center justify-center rounded-full border-2 border-card bg-muted text-muted-foreground font-medium",
|
|
286
|
+
classes.avatar,
|
|
287
|
+
classes.text
|
|
288
|
+
),
|
|
289
|
+
children: [
|
|
290
|
+
"+",
|
|
291
|
+
hiddenCount
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
) : null
|
|
295
|
+
] }),
|
|
296
|
+
extraLabel ? /* @__PURE__ */ jsx5("div", { className: "text-sm text-muted-foreground", children: extraLabel }) : null
|
|
297
|
+
] });
|
|
298
|
+
}
|
|
299
|
+
function ProfileAvatarRow({ className, name, role, src, initials, status, size = "sm", aside }) {
|
|
300
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("flex items-center justify-between gap-3", className), children: [
|
|
301
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3", children: [
|
|
302
|
+
/* @__PURE__ */ jsx5(ProfileAvatar, { name, src, initials, status, size }),
|
|
303
|
+
/* @__PURE__ */ jsxs3("div", { className: "grid gap-0.5", children: [
|
|
304
|
+
/* @__PURE__ */ jsx5("p", { className: "text-sm font-medium text-foreground", children: name }),
|
|
305
|
+
role ? /* @__PURE__ */ jsx5("p", { className: "text-xs text-muted-foreground", children: role }) : null
|
|
306
|
+
] })
|
|
307
|
+
] }),
|
|
308
|
+
aside
|
|
309
|
+
] });
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/components/data-display/typography.tsx
|
|
313
|
+
import { cva } from "class-variance-authority";
|
|
314
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
315
|
+
var typographyVariants = cva("text-foreground", {
|
|
316
|
+
variants: {
|
|
317
|
+
variant: {
|
|
318
|
+
h1: "font-display text-4xl font-bold tracking-tight",
|
|
319
|
+
h2: "font-display text-3xl font-bold tracking-tight",
|
|
320
|
+
h3: "font-display text-2xl font-semibold tracking-tight",
|
|
321
|
+
h4: "text-xl font-semibold",
|
|
322
|
+
lead: "text-lg text-muted-foreground",
|
|
323
|
+
body: "text-base",
|
|
324
|
+
small: "text-sm text-muted-foreground",
|
|
325
|
+
muted: "text-sm text-muted-foreground",
|
|
326
|
+
code: "font-mono text-sm"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
defaultVariants: {
|
|
330
|
+
variant: "body"
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
function Typography({
|
|
334
|
+
as,
|
|
335
|
+
className,
|
|
336
|
+
variant,
|
|
337
|
+
children,
|
|
338
|
+
...props
|
|
339
|
+
}) {
|
|
340
|
+
const Component = as ?? "p";
|
|
341
|
+
return /* @__PURE__ */ jsx6(Component, { className: cn(typographyVariants({ variant }), className), ...props, children });
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/components/primitives/card.tsx
|
|
345
|
+
import * as React2 from "react";
|
|
346
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
347
|
+
var cardBaseClassName = "rounded-lg border bg-card text-card-foreground shadow-sm";
|
|
348
|
+
var Card = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn(cardBaseClassName, className), ...props }));
|
|
349
|
+
Card.displayName = "Card";
|
|
350
|
+
var ClickableCard = React2.forwardRef(
|
|
351
|
+
({ className, type = "button", ...props }, ref) => /* @__PURE__ */ jsx7(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
ref,
|
|
355
|
+
type,
|
|
356
|
+
className: cn(
|
|
357
|
+
cardBaseClassName,
|
|
358
|
+
"w-full cursor-pointer text-left transition-all hover:bg-accent/30 hover:border-[var(--color-accent-blue)]/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
359
|
+
className
|
|
360
|
+
),
|
|
361
|
+
...props
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
);
|
|
365
|
+
ClickableCard.displayName = "ClickableCard";
|
|
366
|
+
var CenteredIconCard = React2.forwardRef(
|
|
367
|
+
({ className, type = "button", icon: Icon2, title, iconClassName, ...props }, ref) => /* @__PURE__ */ jsxs4(
|
|
368
|
+
"button",
|
|
369
|
+
{
|
|
370
|
+
ref,
|
|
371
|
+
type,
|
|
372
|
+
className: cn(
|
|
373
|
+
cardBaseClassName,
|
|
374
|
+
"flex w-full cursor-pointer flex-col items-center justify-center gap-4 p-6 text-center transition-all hover:bg-accent/30 hover:border-[var(--color-accent-blue)]/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
375
|
+
className
|
|
376
|
+
),
|
|
377
|
+
...props,
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ jsx7("span", { className: "flex h-12 w-12 items-center justify-center rounded-xl bg-[var(--color-brand)]/10 text-[var(--color-brand)]", children: /* @__PURE__ */ jsx7(Icon2, { className: cn("h-6 w-6", iconClassName) }) }),
|
|
380
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-semibold text-foreground", children: title })
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
);
|
|
385
|
+
CenteredIconCard.displayName = "CenteredIconCard";
|
|
386
|
+
var CardHeader = React2.forwardRef(
|
|
387
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
|
|
388
|
+
);
|
|
389
|
+
CardHeader.displayName = "CardHeader";
|
|
390
|
+
var CardTitle = React2.forwardRef(
|
|
391
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
|
|
392
|
+
);
|
|
393
|
+
CardTitle.displayName = "CardTitle";
|
|
394
|
+
var CardDescription = React2.forwardRef(
|
|
395
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn("text-sm text-muted-foreground", className), ...props })
|
|
396
|
+
);
|
|
397
|
+
CardDescription.displayName = "CardDescription";
|
|
398
|
+
var CardContent = React2.forwardRef(
|
|
399
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn("p-6 pt-0", className), ...props })
|
|
400
|
+
);
|
|
401
|
+
CardContent.displayName = "CardContent";
|
|
402
|
+
var CardFooter = React2.forwardRef(
|
|
403
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx7("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
|
|
404
|
+
);
|
|
405
|
+
CardFooter.displayName = "CardFooter";
|
|
406
|
+
|
|
407
|
+
// src/components/feedback/skeleton.tsx
|
|
408
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
409
|
+
function Skeleton({ className, ...props }) {
|
|
410
|
+
return /* @__PURE__ */ jsx8("div", { className: cn("animate-pulse rounded-md bg-muted", className), ...props });
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/components/feedback/spinner.tsx
|
|
414
|
+
import { Loader2 } from "lucide-react";
|
|
415
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
416
|
+
var sizeMap3 = {
|
|
417
|
+
sm: "h-4 w-4",
|
|
418
|
+
md: "h-5 w-5",
|
|
419
|
+
lg: "h-7 w-7"
|
|
420
|
+
};
|
|
421
|
+
function Spinner({ className, size = "md" }) {
|
|
422
|
+
return /* @__PURE__ */ jsx9(Loader2, { className: cn("animate-spin text-current", sizeMap3[size], className) });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/components/tables/table.tsx
|
|
426
|
+
import * as React3 from "react";
|
|
427
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
428
|
+
var Table = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx10("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx10("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props }) }));
|
|
429
|
+
Table.displayName = "Table";
|
|
430
|
+
var TableHeader = React3.forwardRef(
|
|
431
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
|
|
432
|
+
);
|
|
433
|
+
TableHeader.displayName = "TableHeader";
|
|
434
|
+
var TableBody = React3.forwardRef(
|
|
435
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
|
|
436
|
+
);
|
|
437
|
+
TableBody.displayName = "TableBody";
|
|
438
|
+
var TableFooter = React3.forwardRef(
|
|
439
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
440
|
+
"tfoot",
|
|
441
|
+
{
|
|
442
|
+
ref,
|
|
443
|
+
className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className),
|
|
444
|
+
...props
|
|
445
|
+
}
|
|
446
|
+
)
|
|
447
|
+
);
|
|
448
|
+
TableFooter.displayName = "TableFooter";
|
|
449
|
+
var TableRow = React3.forwardRef(
|
|
450
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
451
|
+
"tr",
|
|
452
|
+
{
|
|
453
|
+
ref,
|
|
454
|
+
className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className),
|
|
455
|
+
...props
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
);
|
|
459
|
+
TableRow.displayName = "TableRow";
|
|
460
|
+
var TableHead = React3.forwardRef(
|
|
461
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10(
|
|
462
|
+
"th",
|
|
463
|
+
{
|
|
464
|
+
ref,
|
|
465
|
+
className: cn("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0", className),
|
|
466
|
+
...props
|
|
467
|
+
}
|
|
468
|
+
)
|
|
469
|
+
);
|
|
470
|
+
TableHead.displayName = "TableHead";
|
|
471
|
+
var TableCell = React3.forwardRef(
|
|
472
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props })
|
|
473
|
+
);
|
|
474
|
+
TableCell.displayName = "TableCell";
|
|
475
|
+
var TableCaption = React3.forwardRef(
|
|
476
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx10("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
|
|
477
|
+
);
|
|
478
|
+
TableCaption.displayName = "TableCaption";
|
|
479
|
+
|
|
480
|
+
// src/components/feedback/loading-state.tsx
|
|
481
|
+
import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
482
|
+
function LoadingState({
|
|
483
|
+
className,
|
|
484
|
+
title = "Cargando datos",
|
|
485
|
+
description = "Estamos preparando la informacion para ti.",
|
|
486
|
+
size = "md",
|
|
487
|
+
icon
|
|
488
|
+
}) {
|
|
489
|
+
return /* @__PURE__ */ jsxs5(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
role: "status",
|
|
493
|
+
"aria-live": "polite",
|
|
494
|
+
className: cn("flex items-center gap-3 rounded-xl border border-border bg-card px-4 py-3 text-foreground", className),
|
|
495
|
+
children: [
|
|
496
|
+
icon ?? /* @__PURE__ */ jsx11(Spinner, { size, className: "text-primary" }),
|
|
497
|
+
/* @__PURE__ */ jsxs5("div", { className: "grid gap-0.5", children: [
|
|
498
|
+
/* @__PURE__ */ jsx11("p", { className: "text-sm font-medium", children: title }),
|
|
499
|
+
/* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground", children: description })
|
|
500
|
+
] })
|
|
501
|
+
]
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
function LoadingCard({ className, rows = 3 }) {
|
|
506
|
+
return /* @__PURE__ */ jsx11(Card, { className, children: /* @__PURE__ */ jsxs5(CardContent, { className: "grid gap-3 p-5", children: [
|
|
507
|
+
/* @__PURE__ */ jsx11(Skeleton, { className: "h-6 w-40" }),
|
|
508
|
+
Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsx11(Skeleton, { className: cn("h-4", index === rows - 1 ? "w-2/3" : "w-full") }, index)),
|
|
509
|
+
/* @__PURE__ */ jsx11(Skeleton, { className: "mt-1 h-10 w-full rounded-lg" })
|
|
510
|
+
] }) });
|
|
511
|
+
}
|
|
512
|
+
function LoadingTableRows({ className, columns = 5, rows = 4 }) {
|
|
513
|
+
return /* @__PURE__ */ jsx11("div", { className: cn("rounded-xl border", className), children: /* @__PURE__ */ jsxs5(Table, { children: [
|
|
514
|
+
/* @__PURE__ */ jsx11(TableHeader, { children: /* @__PURE__ */ jsx11(TableRow, { children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ jsx11(TableHead, { children: /* @__PURE__ */ jsx11(Skeleton, { className: "h-4 w-20" }) }, index)) }) }),
|
|
515
|
+
/* @__PURE__ */ jsx11(TableBody, { children: Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx11(TableRow, { children: Array.from({ length: columns }).map((_2, columnIndex) => /* @__PURE__ */ jsx11(TableCell, { children: /* @__PURE__ */ jsx11(Skeleton, { className: cn("h-4", columnIndex === 0 ? "w-24" : "w-full") }) }, columnIndex)) }, rowIndex)) })
|
|
516
|
+
] }) });
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/components/feedback/notification.tsx
|
|
520
|
+
import { AlertCircle, AlertTriangle, CheckCircle2, Info, Loader2 as Loader22 } from "lucide-react";
|
|
521
|
+
import { toast } from "sonner";
|
|
522
|
+
|
|
523
|
+
// src/components/primitives/button.tsx
|
|
524
|
+
import * as React4 from "react";
|
|
525
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
526
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
527
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
528
|
+
var buttonVariants = cva2(
|
|
529
|
+
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium shadow-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
530
|
+
{
|
|
531
|
+
variants: {
|
|
532
|
+
variant: {
|
|
533
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
534
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
535
|
+
outline: "border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground",
|
|
536
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
537
|
+
ghost: "text-foreground shadow-none hover:bg-accent hover:text-accent-foreground",
|
|
538
|
+
link: "h-auto px-0 py-0 text-primary underline-offset-4 shadow-none hover:underline"
|
|
539
|
+
},
|
|
540
|
+
size: {
|
|
541
|
+
default: "h-10 px-4 py-2",
|
|
542
|
+
sm: "h-9 rounded-md px-3",
|
|
543
|
+
lg: "h-11 rounded-md px-8",
|
|
544
|
+
icon: "h-10 w-10"
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
defaultVariants: {
|
|
548
|
+
variant: "default",
|
|
549
|
+
size: "default"
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
var Button = React4.forwardRef(
|
|
554
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
555
|
+
const Comp = asChild ? Slot : "button";
|
|
556
|
+
return /* @__PURE__ */ jsx12(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
|
|
557
|
+
}
|
|
558
|
+
);
|
|
559
|
+
Button.displayName = "Button";
|
|
560
|
+
|
|
561
|
+
// src/components/feedback/notification.tsx
|
|
562
|
+
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
563
|
+
var notificationStyles = {
|
|
564
|
+
info: "bg-[var(--color-info-bg)] text-[var(--color-accent-blue)] border-[var(--color-accent-blue)]/30",
|
|
565
|
+
success: "bg-[var(--color-success-bg)] text-[var(--color-success)] border-[var(--color-success)]/30",
|
|
566
|
+
warning: "bg-[var(--color-warning-bg)] text-[var(--color-warning)] border-[var(--color-warning)]/30",
|
|
567
|
+
danger: "bg-destructive/10 text-destructive border-destructive/30",
|
|
568
|
+
loading: "bg-[var(--color-info-bg)] text-[var(--color-accent-blue)] border-[var(--color-accent-blue)]/30"
|
|
569
|
+
};
|
|
570
|
+
var notificationIcons = {
|
|
571
|
+
info: Info,
|
|
572
|
+
success: CheckCircle2,
|
|
573
|
+
warning: AlertTriangle,
|
|
574
|
+
danger: AlertCircle,
|
|
575
|
+
loading: Loader22
|
|
576
|
+
};
|
|
577
|
+
function NotificationMessage({
|
|
578
|
+
className,
|
|
579
|
+
tone = "info",
|
|
580
|
+
title,
|
|
581
|
+
description,
|
|
582
|
+
action,
|
|
583
|
+
icon
|
|
584
|
+
}) {
|
|
585
|
+
const Icon2 = icon ?? notificationIcons[tone];
|
|
586
|
+
return /* @__PURE__ */ jsxs6(
|
|
587
|
+
"div",
|
|
588
|
+
{
|
|
589
|
+
role: "status",
|
|
590
|
+
className: cn("flex items-start justify-between gap-3 rounded-lg border px-4 py-3", notificationStyles[tone], className),
|
|
591
|
+
children: [
|
|
592
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-3", children: [
|
|
593
|
+
/* @__PURE__ */ jsx13(Icon2, { className: cn("mt-0.5 h-4 w-4 shrink-0", tone === "loading" && "animate-spin") }),
|
|
594
|
+
/* @__PURE__ */ jsxs6("div", { className: "grid gap-1", children: [
|
|
595
|
+
/* @__PURE__ */ jsx13("p", { className: "text-sm font-medium", children: title }),
|
|
596
|
+
description ? /* @__PURE__ */ jsx13("div", { className: "text-xs opacity-85", children: description }) : null
|
|
597
|
+
] })
|
|
598
|
+
] }),
|
|
599
|
+
action ? /* @__PURE__ */ jsx13("div", { className: "shrink-0", children: action }) : null
|
|
600
|
+
]
|
|
601
|
+
}
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
function buildToastOptions(payload) {
|
|
605
|
+
return {
|
|
606
|
+
description: payload.description,
|
|
607
|
+
action: payload.actionLabel ? {
|
|
608
|
+
label: payload.actionLabel,
|
|
609
|
+
onClick: payload.onAction ?? (() => void 0)
|
|
610
|
+
} : void 0
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
var notify = {
|
|
614
|
+
info: (payload) => toast(payload.title, buildToastOptions(payload)),
|
|
615
|
+
success: (payload) => toast.success(payload.title, buildToastOptions(payload)),
|
|
616
|
+
warning: (payload) => toast(payload.title, {
|
|
617
|
+
...buildToastOptions(payload),
|
|
618
|
+
icon: /* @__PURE__ */ jsx13(AlertTriangle, { className: "h-4 w-4 text-[var(--color-warning)]" })
|
|
619
|
+
}),
|
|
620
|
+
danger: (payload) => toast.error(payload.title, buildToastOptions(payload)),
|
|
621
|
+
loading: (payload) => toast.loading(payload.title, buildToastOptions(payload))
|
|
622
|
+
};
|
|
623
|
+
function NotificationAction({ children, variant = "outline", size = "sm", ...props }) {
|
|
624
|
+
return /* @__PURE__ */ jsx13(Button, { variant, size, ...props, children });
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/components/feedback/status-badge.tsx
|
|
628
|
+
import { AlertCircle as AlertCircle2, CheckCircle2 as CheckCircle22, Clock3, Loader2 as Loader23 } from "lucide-react";
|
|
629
|
+
import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
630
|
+
var toneStyles2 = {
|
|
631
|
+
success: "border-transparent bg-[var(--color-success-bg)] text-[var(--color-success)]",
|
|
632
|
+
warning: "border-transparent bg-[var(--color-warning-bg)] text-[var(--color-warning)]",
|
|
633
|
+
danger: "border-transparent bg-destructive/10 text-destructive",
|
|
634
|
+
info: "border-transparent bg-[var(--color-info-bg)] text-[var(--color-accent-blue)]",
|
|
635
|
+
loading: "border-transparent bg-muted text-muted-foreground"
|
|
636
|
+
};
|
|
637
|
+
var toneIcons = {
|
|
638
|
+
success: CheckCircle22,
|
|
639
|
+
warning: Clock3,
|
|
640
|
+
danger: AlertCircle2,
|
|
641
|
+
info: CheckCircle22,
|
|
642
|
+
loading: Loader23
|
|
643
|
+
};
|
|
644
|
+
function StatusBadge({ children, tone = "info", className }) {
|
|
645
|
+
const Icon2 = toneIcons[tone];
|
|
646
|
+
return /* @__PURE__ */ jsxs7(
|
|
647
|
+
"span",
|
|
648
|
+
{
|
|
649
|
+
className: cn(
|
|
650
|
+
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium",
|
|
651
|
+
toneStyles2[tone],
|
|
652
|
+
className
|
|
653
|
+
),
|
|
654
|
+
children: [
|
|
655
|
+
/* @__PURE__ */ jsx14(Icon2, { className: cn("h-3.5 w-3.5", tone === "loading" && "animate-spin") }),
|
|
656
|
+
children
|
|
657
|
+
]
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// src/components/feedback/toaster.tsx
|
|
663
|
+
import { Toaster as Sonner } from "sonner";
|
|
664
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
665
|
+
function Toaster(props) {
|
|
666
|
+
const { resolvedTheme } = useTheme();
|
|
667
|
+
return /* @__PURE__ */ jsx15(
|
|
668
|
+
Sonner,
|
|
669
|
+
{
|
|
670
|
+
theme: resolvedTheme,
|
|
671
|
+
className: "toaster group",
|
|
672
|
+
closeButton: true,
|
|
673
|
+
toastOptions: {
|
|
674
|
+
classNames: {
|
|
675
|
+
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
|
676
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
677
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
678
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
...props
|
|
682
|
+
}
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/components/forms/searchable-select.tsx
|
|
687
|
+
import * as React6 from "react";
|
|
688
|
+
import { Check, ChevronDown, ChevronUp, Loader2 as Loader24, Search } from "lucide-react";
|
|
689
|
+
|
|
690
|
+
// src/components/primitives/input.tsx
|
|
691
|
+
import * as React5 from "react";
|
|
692
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
693
|
+
var Input = React5.forwardRef(
|
|
694
|
+
({ className, type, ...props }, ref) => {
|
|
695
|
+
return /* @__PURE__ */ jsx16(
|
|
696
|
+
"input",
|
|
697
|
+
{
|
|
698
|
+
type,
|
|
699
|
+
className: cn(
|
|
700
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
701
|
+
className
|
|
702
|
+
),
|
|
703
|
+
ref,
|
|
704
|
+
...props
|
|
705
|
+
}
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
Input.displayName = "Input";
|
|
710
|
+
|
|
711
|
+
// src/components/forms/searchable-select.tsx
|
|
712
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
713
|
+
function normalize(str) {
|
|
714
|
+
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
715
|
+
}
|
|
716
|
+
var SearchableSelect = React6.forwardRef(
|
|
717
|
+
({
|
|
718
|
+
options: options2,
|
|
719
|
+
value,
|
|
720
|
+
onValueChange,
|
|
721
|
+
placeholder = "Select an option...",
|
|
722
|
+
searchPlaceholder = "Search...",
|
|
723
|
+
disabled = false,
|
|
724
|
+
loading = false,
|
|
725
|
+
emptyMessage = "No results found.",
|
|
726
|
+
id,
|
|
727
|
+
className
|
|
728
|
+
}, ref) => {
|
|
729
|
+
const [open, setOpen] = React6.useState(false);
|
|
730
|
+
const [search, setSearch] = React6.useState("");
|
|
731
|
+
const wrapperRef = React6.useRef(null);
|
|
732
|
+
const searchRef = React6.useRef(null);
|
|
733
|
+
const selected = React6.useMemo(() => options2.find((option) => option.value === value) ?? null, [options2, value]);
|
|
734
|
+
const filtered = React6.useMemo(() => {
|
|
735
|
+
if (!search.trim()) {
|
|
736
|
+
return options2;
|
|
737
|
+
}
|
|
738
|
+
const query = normalize(search);
|
|
739
|
+
return options2.filter(
|
|
740
|
+
(option) => normalize(option.label).includes(query) || normalize(option.sublabel ?? "").includes(query)
|
|
741
|
+
);
|
|
742
|
+
}, [options2, search]);
|
|
743
|
+
function handleOpen() {
|
|
744
|
+
if (disabled || loading) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
setOpen((previous) => !previous);
|
|
748
|
+
}
|
|
749
|
+
function handleSelect(optionValue) {
|
|
750
|
+
onValueChange(optionValue);
|
|
751
|
+
setOpen(false);
|
|
752
|
+
setSearch("");
|
|
753
|
+
}
|
|
754
|
+
function handleKeyDown(event) {
|
|
755
|
+
if (event.key === "Escape") {
|
|
756
|
+
setOpen(false);
|
|
757
|
+
setSearch("");
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
React6.useEffect(() => {
|
|
761
|
+
if (!open) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
function handleMouseDown(event) {
|
|
765
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
766
|
+
setOpen(false);
|
|
767
|
+
setSearch("");
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
771
|
+
return () => document.removeEventListener("mousedown", handleMouseDown);
|
|
772
|
+
}, [open]);
|
|
773
|
+
React6.useEffect(() => {
|
|
774
|
+
if (!open) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
const timer = setTimeout(() => searchRef.current?.focus(), 50);
|
|
778
|
+
return () => clearTimeout(timer);
|
|
779
|
+
}, [open]);
|
|
780
|
+
return /* @__PURE__ */ jsxs8("div", { ref: wrapperRef, className: cn("relative w-full", className), onKeyDown: handleKeyDown, children: [
|
|
781
|
+
/* @__PURE__ */ jsxs8(
|
|
782
|
+
"button",
|
|
783
|
+
{
|
|
784
|
+
ref,
|
|
785
|
+
id,
|
|
786
|
+
type: "button",
|
|
787
|
+
role: "combobox",
|
|
788
|
+
"aria-expanded": open,
|
|
789
|
+
"aria-haspopup": "listbox",
|
|
790
|
+
disabled: disabled || loading,
|
|
791
|
+
onClick: handleOpen,
|
|
792
|
+
className: cn(
|
|
793
|
+
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-left text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
794
|
+
),
|
|
795
|
+
children: [
|
|
796
|
+
loading ? /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2 text-muted-foreground", children: [
|
|
797
|
+
/* @__PURE__ */ jsx17(Loader24, { className: "h-4 w-4 animate-spin" }),
|
|
798
|
+
"Loading..."
|
|
799
|
+
] }) : selected ? /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2 truncate", children: [
|
|
800
|
+
selected.sublabel ? /* @__PURE__ */ jsx17("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: selected.sublabel }) : null,
|
|
801
|
+
/* @__PURE__ */ jsx17("span", { className: "truncate", children: selected.label })
|
|
802
|
+
] }) : /* @__PURE__ */ jsx17("span", { className: "text-muted-foreground", children: placeholder }),
|
|
803
|
+
/* @__PURE__ */ jsx17("span", { className: "ml-2 shrink-0 opacity-50", children: open ? /* @__PURE__ */ jsx17(ChevronUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx17(ChevronDown, { className: "h-4 w-4" }) })
|
|
804
|
+
]
|
|
805
|
+
}
|
|
806
|
+
),
|
|
807
|
+
open ? /* @__PURE__ */ jsxs8(
|
|
808
|
+
"div",
|
|
809
|
+
{
|
|
810
|
+
role: "listbox",
|
|
811
|
+
className: "animate-in fade-in-0 zoom-in-95 absolute z-50 mt-1 w-full rounded-md border border-border bg-popover text-popover-foreground shadow-md",
|
|
812
|
+
children: [
|
|
813
|
+
/* @__PURE__ */ jsxs8("div", { className: "sticky top-0 flex items-center gap-2 border-b border-border bg-popover px-3 py-2", children: [
|
|
814
|
+
/* @__PURE__ */ jsx17(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
815
|
+
/* @__PURE__ */ jsx17(
|
|
816
|
+
Input,
|
|
817
|
+
{
|
|
818
|
+
ref: searchRef,
|
|
819
|
+
type: "text",
|
|
820
|
+
value: search,
|
|
821
|
+
onChange: (event) => setSearch(event.target.value),
|
|
822
|
+
placeholder: searchPlaceholder,
|
|
823
|
+
className: "h-7 border-0 bg-transparent px-0 text-sm shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-muted-foreground"
|
|
824
|
+
}
|
|
825
|
+
)
|
|
826
|
+
] }),
|
|
827
|
+
/* @__PURE__ */ jsx17("ul", { className: "max-h-60 overflow-y-auto overscroll-contain p-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx17("li", { className: "px-4 py-3 text-center text-xs text-muted-foreground", children: emptyMessage }) : filtered.map((option) => {
|
|
828
|
+
const isSelected = option.value === value;
|
|
829
|
+
return /* @__PURE__ */ jsxs8(
|
|
830
|
+
"li",
|
|
831
|
+
{
|
|
832
|
+
role: "option",
|
|
833
|
+
"aria-selected": isSelected,
|
|
834
|
+
onClick: () => handleSelect(option.value),
|
|
835
|
+
className: cn(
|
|
836
|
+
"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
|
837
|
+
isSelected && "bg-accent/50 font-medium"
|
|
838
|
+
),
|
|
839
|
+
children: [
|
|
840
|
+
/* @__PURE__ */ jsx17("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: isSelected ? /* @__PURE__ */ jsx17(Check, { className: "h-4 w-4" }) : null }),
|
|
841
|
+
/* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-2 truncate", children: [
|
|
842
|
+
option.sublabel ? /* @__PURE__ */ jsx17("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: option.sublabel }) : null,
|
|
843
|
+
/* @__PURE__ */ jsx17("span", { className: "truncate", children: option.label })
|
|
844
|
+
] })
|
|
845
|
+
]
|
|
846
|
+
},
|
|
847
|
+
option.value
|
|
848
|
+
);
|
|
849
|
+
}) })
|
|
850
|
+
]
|
|
851
|
+
}
|
|
852
|
+
) : null
|
|
853
|
+
] });
|
|
854
|
+
}
|
|
855
|
+
);
|
|
856
|
+
SearchableSelect.displayName = "SearchableSelect";
|
|
857
|
+
|
|
858
|
+
// src/components/forms/select.tsx
|
|
859
|
+
import * as React7 from "react";
|
|
860
|
+
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
861
|
+
import { Check as Check2, ChevronDown as ChevronDown2, ChevronUp as ChevronUp2 } from "lucide-react";
|
|
862
|
+
import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
863
|
+
var Select = SelectPrimitive.Root;
|
|
864
|
+
var SelectGroup = SelectPrimitive.Group;
|
|
865
|
+
var SelectValue = SelectPrimitive.Value;
|
|
866
|
+
var SelectTrigger = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs9(
|
|
867
|
+
SelectPrimitive.Trigger,
|
|
868
|
+
{
|
|
869
|
+
ref,
|
|
870
|
+
className: cn(
|
|
871
|
+
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
872
|
+
className
|
|
873
|
+
),
|
|
874
|
+
...props,
|
|
875
|
+
children: [
|
|
876
|
+
children,
|
|
877
|
+
/* @__PURE__ */ jsx18(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx18(ChevronDown2, { className: "h-4 w-4 opacity-50" }) })
|
|
878
|
+
]
|
|
879
|
+
}
|
|
880
|
+
));
|
|
881
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
882
|
+
var SelectScrollUpButton = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(SelectPrimitive.ScrollUpButton, { ref, className: cn("flex cursor-default items-center justify-center py-1", className), ...props, children: /* @__PURE__ */ jsx18(ChevronUp2, { className: "h-4 w-4" }) }));
|
|
883
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
884
|
+
var SelectScrollDownButton = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
|
|
885
|
+
SelectPrimitive.ScrollDownButton,
|
|
886
|
+
{
|
|
887
|
+
ref,
|
|
888
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
889
|
+
...props,
|
|
890
|
+
children: /* @__PURE__ */ jsx18(ChevronDown2, { className: "h-4 w-4" })
|
|
891
|
+
}
|
|
892
|
+
));
|
|
893
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
894
|
+
var SelectContent = React7.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx18(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs9(
|
|
895
|
+
SelectPrimitive.Content,
|
|
896
|
+
{
|
|
897
|
+
ref,
|
|
898
|
+
className: cn(
|
|
899
|
+
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-select-content-transform-origin]",
|
|
900
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
901
|
+
className
|
|
902
|
+
),
|
|
903
|
+
position,
|
|
904
|
+
...props,
|
|
905
|
+
children: [
|
|
906
|
+
/* @__PURE__ */ jsx18(SelectScrollUpButton, {}),
|
|
907
|
+
/* @__PURE__ */ jsx18(
|
|
908
|
+
SelectPrimitive.Viewport,
|
|
909
|
+
{
|
|
910
|
+
className: cn(
|
|
911
|
+
"p-1",
|
|
912
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
913
|
+
),
|
|
914
|
+
children
|
|
915
|
+
}
|
|
916
|
+
),
|
|
917
|
+
/* @__PURE__ */ jsx18(SelectScrollDownButton, {})
|
|
918
|
+
]
|
|
919
|
+
}
|
|
920
|
+
) }));
|
|
921
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
922
|
+
var SelectLabel = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(SelectPrimitive.Label, { ref, className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className), ...props }));
|
|
923
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
924
|
+
var SelectItem = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs9(
|
|
925
|
+
SelectPrimitive.Item,
|
|
926
|
+
{
|
|
927
|
+
ref,
|
|
928
|
+
className: cn(
|
|
929
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
930
|
+
className
|
|
931
|
+
),
|
|
932
|
+
...props,
|
|
933
|
+
children: [
|
|
934
|
+
/* @__PURE__ */ jsx18("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx18(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx18(Check2, { className: "h-4 w-4" }) }) }),
|
|
935
|
+
/* @__PURE__ */ jsx18(SelectPrimitive.ItemText, { children })
|
|
936
|
+
]
|
|
937
|
+
}
|
|
938
|
+
));
|
|
939
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
940
|
+
var SelectSeparator = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(SelectPrimitive.Separator, { ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props }));
|
|
941
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
942
|
+
|
|
943
|
+
// src/components/layout/app-shell.tsx
|
|
944
|
+
import { useState as useState3 } from "react";
|
|
945
|
+
|
|
946
|
+
// src/components/overlays/drawer.tsx
|
|
947
|
+
import * as React8 from "react";
|
|
948
|
+
import { Drawer as DrawerPrimitive } from "vaul";
|
|
949
|
+
import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
950
|
+
var Drawer = ({ shouldScaleBackground = true, ...props }) => /* @__PURE__ */ jsx19(DrawerPrimitive.Root, { shouldScaleBackground, ...props });
|
|
951
|
+
Drawer.displayName = "Drawer";
|
|
952
|
+
var DrawerTrigger = DrawerPrimitive.Trigger;
|
|
953
|
+
var DrawerPortal = DrawerPrimitive.Portal;
|
|
954
|
+
var DrawerClose = DrawerPrimitive.Close;
|
|
955
|
+
var DrawerOverlay = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(DrawerPrimitive.Overlay, { ref, className: cn("fixed inset-0 z-50 bg-black/80", className), ...props }));
|
|
956
|
+
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
|
957
|
+
var DrawerContent = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs10(DrawerPortal, { children: [
|
|
958
|
+
/* @__PURE__ */ jsx19(DrawerOverlay, {}),
|
|
959
|
+
/* @__PURE__ */ jsxs10(
|
|
960
|
+
DrawerPrimitive.Content,
|
|
961
|
+
{
|
|
962
|
+
ref,
|
|
963
|
+
className: cn("fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background", className),
|
|
964
|
+
...props,
|
|
965
|
+
children: [
|
|
966
|
+
/* @__PURE__ */ jsx19("div", { className: "mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" }),
|
|
967
|
+
children
|
|
968
|
+
]
|
|
969
|
+
}
|
|
970
|
+
)
|
|
971
|
+
] }));
|
|
972
|
+
DrawerContent.displayName = "DrawerContent";
|
|
973
|
+
var DrawerHeader = ({ className, ...props }) => /* @__PURE__ */ jsx19("div", { className: cn("grid gap-1.5 p-4 text-center sm:text-left", className), ...props });
|
|
974
|
+
DrawerHeader.displayName = "DrawerHeader";
|
|
975
|
+
var DrawerFooter = ({ className, ...props }) => /* @__PURE__ */ jsx19("div", { className: cn("mt-auto flex flex-col gap-2 p-4", className), ...props });
|
|
976
|
+
DrawerFooter.displayName = "DrawerFooter";
|
|
977
|
+
var DrawerTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(DrawerPrimitive.Title, { ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props }));
|
|
978
|
+
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
|
979
|
+
var DrawerDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(DrawerPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
980
|
+
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
|
981
|
+
|
|
982
|
+
// src/components/navigation/navbar.tsx
|
|
983
|
+
import { Menu } from "lucide-react";
|
|
984
|
+
import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
985
|
+
function Navbar({ brand, actions, onMenuClick, className }) {
|
|
986
|
+
return /* @__PURE__ */ jsx20("header", { className: cn("h-14 shrink-0 border-b border-border bg-card/80 px-4 backdrop-blur-sm", className), children: /* @__PURE__ */ jsxs11("div", { className: "mx-auto flex h-full w-full max-w-7xl items-center justify-between gap-3", children: [
|
|
987
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
988
|
+
onMenuClick ? /* @__PURE__ */ jsx20(Button, { type: "button", variant: "ghost", size: "icon", onClick: onMenuClick, "aria-label": "Open navigation", children: /* @__PURE__ */ jsx20(Menu, { size: 20 }) }) : null,
|
|
989
|
+
brand
|
|
990
|
+
] }),
|
|
991
|
+
actions ? /* @__PURE__ */ jsx20("div", { className: "flex shrink-0 items-center gap-3", children: actions }) : null
|
|
992
|
+
] }) });
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// src/components/navigation/sidebar.tsx
|
|
996
|
+
import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
997
|
+
function getInitials2(name) {
|
|
998
|
+
return name.trim().split(" ").filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase() ?? "").join("");
|
|
999
|
+
}
|
|
1000
|
+
function Sidebar({ brand, groups, user, footerAction, className }) {
|
|
1001
|
+
return /* @__PURE__ */ jsxs12("aside", { className: cn("flex h-full w-72 max-w-[85vw] flex-col border-r border-border bg-background", className), children: [
|
|
1002
|
+
/* @__PURE__ */ jsx21("div", { className: "border-b border-border px-5 py-4", children: brand }),
|
|
1003
|
+
/* @__PURE__ */ jsx21("nav", { className: "flex-1 space-y-6 overflow-y-auto px-3 py-4", children: groups.map((group) => /* @__PURE__ */ jsxs12("div", { children: [
|
|
1004
|
+
/* @__PURE__ */ jsx21("p", { className: "mb-2 px-2 text-xs font-semibold uppercase tracking-widest text-muted-foreground", children: group.label }),
|
|
1005
|
+
/* @__PURE__ */ jsx21("ul", { className: "space-y-0.5", children: group.items.map((item) => {
|
|
1006
|
+
const Icon2 = item.icon;
|
|
1007
|
+
return /* @__PURE__ */ jsx21("li", { children: /* @__PURE__ */ jsxs12(
|
|
1008
|
+
"a",
|
|
1009
|
+
{
|
|
1010
|
+
href: item.href,
|
|
1011
|
+
onClick: item.onClick,
|
|
1012
|
+
className: cn(
|
|
1013
|
+
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
|
1014
|
+
item.active ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-accent hover:text-accent-foreground"
|
|
1015
|
+
),
|
|
1016
|
+
children: [
|
|
1017
|
+
Icon2 ? /* @__PURE__ */ jsx21(Icon2, { size: 17, className: "shrink-0" }) : null,
|
|
1018
|
+
/* @__PURE__ */ jsx21("span", { className: "flex-1", children: item.label })
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
) }, `${group.label}-${item.label}`);
|
|
1022
|
+
}) })
|
|
1023
|
+
] }, group.label)) }),
|
|
1024
|
+
user ? /* @__PURE__ */ jsx21("div", { className: "border-t border-border px-5 py-4", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3", children: [
|
|
1025
|
+
/* @__PURE__ */ jsx21(Avatar, { className: "h-9 w-9 shrink-0", children: /* @__PURE__ */ jsx21(AvatarFallback, { className: "bg-primary text-xs font-semibold text-primary-foreground", children: user.initials ?? getInitials2(user.name) }) }),
|
|
1026
|
+
/* @__PURE__ */ jsxs12("div", { className: "min-w-0 flex-1", children: [
|
|
1027
|
+
/* @__PURE__ */ jsx21("p", { className: "truncate text-sm font-medium text-foreground", children: user.name }),
|
|
1028
|
+
user.role ? /* @__PURE__ */ jsx21("p", { className: "truncate text-xs text-muted-foreground", children: user.role }) : null
|
|
1029
|
+
] }),
|
|
1030
|
+
footerAction ? /* @__PURE__ */ jsx21(Button, { type: "button", variant: "ghost", size: "sm", onClick: footerAction.onClick, children: footerAction.label }) : null
|
|
1031
|
+
] }) }) : null
|
|
1032
|
+
] });
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// src/components/layout/app-shell.tsx
|
|
1036
|
+
import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1037
|
+
function AppShell({
|
|
1038
|
+
brand,
|
|
1039
|
+
actions,
|
|
1040
|
+
sidebarGroups,
|
|
1041
|
+
sidebarUser,
|
|
1042
|
+
sidebarFooterAction,
|
|
1043
|
+
children
|
|
1044
|
+
}) {
|
|
1045
|
+
const [open, setOpen] = useState3(false);
|
|
1046
|
+
return /* @__PURE__ */ jsxs13("div", { className: "min-h-screen bg-background", children: [
|
|
1047
|
+
/* @__PURE__ */ jsx22(Navbar, { brand, actions, onMenuClick: () => setOpen(true) }),
|
|
1048
|
+
/* @__PURE__ */ jsx22(Drawer, { open, onOpenChange: setOpen, direction: "left", children: /* @__PURE__ */ jsx22(DrawerContent, { className: "h-full w-72 rounded-none border-r border-border p-0", children: /* @__PURE__ */ jsx22(Sidebar, { brand, groups: sidebarGroups, user: sidebarUser, footerAction: sidebarFooterAction }) }) }),
|
|
1049
|
+
/* @__PURE__ */ jsx22("main", { className: "mx-auto w-full max-w-7xl px-4 py-6 sm:px-6", children })
|
|
1050
|
+
] });
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// src/components/layout/form-section.tsx
|
|
1054
|
+
import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1055
|
+
function FormSection({ title, description, children }) {
|
|
1056
|
+
return /* @__PURE__ */ jsxs14(Card, { children: [
|
|
1057
|
+
/* @__PURE__ */ jsxs14(CardHeader, { children: [
|
|
1058
|
+
/* @__PURE__ */ jsx23(CardTitle, { children: title }),
|
|
1059
|
+
description ? /* @__PURE__ */ jsx23(CardDescription, { children: description }) : null
|
|
1060
|
+
] }),
|
|
1061
|
+
/* @__PURE__ */ jsx23(CardContent, { children })
|
|
1062
|
+
] });
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// src/components/layout/page-header.tsx
|
|
1066
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1067
|
+
function PageHeader({ title, description, action }) {
|
|
1068
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex items-start justify-between gap-4 sm:flex-row sm:items-center", children: [
|
|
1069
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1070
|
+
/* @__PURE__ */ jsx24("h1", { className: "text-2xl font-semibold text-foreground", style: { fontFamily: "var(--font-display)" }, children: title }),
|
|
1071
|
+
description ? /* @__PURE__ */ jsx24("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
1072
|
+
] }),
|
|
1073
|
+
action ? /* @__PURE__ */ jsx24("div", { children: action }) : null
|
|
1074
|
+
] });
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// src/components/layout/theme-toggle.tsx
|
|
1078
|
+
import { Moon, Sun } from "lucide-react";
|
|
1079
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1080
|
+
var options = [
|
|
1081
|
+
{ value: "light", Icon: Sun, label: "Light" },
|
|
1082
|
+
{ value: "dark", Icon: Moon, label: "Dark" }
|
|
1083
|
+
];
|
|
1084
|
+
function ThemeToggle({ className }) {
|
|
1085
|
+
const { theme, setTheme } = useTheme();
|
|
1086
|
+
return /* @__PURE__ */ jsx25("div", { className: cn("flex items-center gap-1 rounded-lg border border-border bg-muted p-1", className), children: options.map(({ value, Icon: Icon2, label }) => /* @__PURE__ */ jsxs16(
|
|
1087
|
+
"button",
|
|
1088
|
+
{
|
|
1089
|
+
type: "button",
|
|
1090
|
+
onClick: () => setTheme(value),
|
|
1091
|
+
"aria-label": label,
|
|
1092
|
+
className: cn(
|
|
1093
|
+
"flex cursor-pointer items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-all",
|
|
1094
|
+
theme === value ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
1095
|
+
),
|
|
1096
|
+
children: [
|
|
1097
|
+
/* @__PURE__ */ jsx25(Icon2, { size: 13 }),
|
|
1098
|
+
/* @__PURE__ */ jsx25("span", { children: label })
|
|
1099
|
+
]
|
|
1100
|
+
},
|
|
1101
|
+
value
|
|
1102
|
+
)) });
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/components/navigation/breadcrumb.tsx
|
|
1106
|
+
import * as React9 from "react";
|
|
1107
|
+
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
1108
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
|
1109
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1110
|
+
var Breadcrumb = React9.forwardRef(({ ...props }, ref) => /* @__PURE__ */ jsx26("nav", { ref, "aria-label": "breadcrumb", ...props }));
|
|
1111
|
+
Breadcrumb.displayName = "Breadcrumb";
|
|
1112
|
+
var BreadcrumbList = React9.forwardRef(
|
|
1113
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx26(
|
|
1114
|
+
"ol",
|
|
1115
|
+
{
|
|
1116
|
+
ref,
|
|
1117
|
+
className: cn("flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5", className),
|
|
1118
|
+
...props
|
|
1119
|
+
}
|
|
1120
|
+
)
|
|
1121
|
+
);
|
|
1122
|
+
BreadcrumbList.displayName = "BreadcrumbList";
|
|
1123
|
+
var BreadcrumbItem = React9.forwardRef(
|
|
1124
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx26("li", { ref, className: cn("inline-flex items-center gap-1.5", className), ...props })
|
|
1125
|
+
);
|
|
1126
|
+
BreadcrumbItem.displayName = "BreadcrumbItem";
|
|
1127
|
+
var BreadcrumbLink = React9.forwardRef(({ asChild, className, ...props }, ref) => {
|
|
1128
|
+
const Comp = asChild ? Slot2 : "a";
|
|
1129
|
+
return /* @__PURE__ */ jsx26(Comp, { ref, className: cn("transition-colors hover:text-foreground", className), ...props });
|
|
1130
|
+
});
|
|
1131
|
+
BreadcrumbLink.displayName = "BreadcrumbLink";
|
|
1132
|
+
var BreadcrumbPage = React9.forwardRef(
|
|
1133
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx26(
|
|
1134
|
+
"span",
|
|
1135
|
+
{
|
|
1136
|
+
ref,
|
|
1137
|
+
role: "link",
|
|
1138
|
+
"aria-disabled": "true",
|
|
1139
|
+
"aria-current": "page",
|
|
1140
|
+
className: cn("font-normal text-foreground", className),
|
|
1141
|
+
...props
|
|
1142
|
+
}
|
|
1143
|
+
)
|
|
1144
|
+
);
|
|
1145
|
+
BreadcrumbPage.displayName = "BreadcrumbPage";
|
|
1146
|
+
var BreadcrumbSeparator = ({ children, className, ...props }) => /* @__PURE__ */ jsx26("li", { role: "presentation", "aria-hidden": "true", className: cn("[&>svg]:h-3.5 [&>svg]:w-3.5", className), ...props, children: children ?? /* @__PURE__ */ jsx26(ChevronRight, {}) });
|
|
1147
|
+
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
|
|
1148
|
+
var BreadcrumbEllipsis = ({ className, ...props }) => /* @__PURE__ */ jsxs17("span", { role: "presentation", "aria-hidden": "true", className: cn("flex h-9 w-9 items-center justify-center", className), ...props, children: [
|
|
1149
|
+
/* @__PURE__ */ jsx26(MoreHorizontal, { className: "h-4 w-4" }),
|
|
1150
|
+
/* @__PURE__ */ jsx26("span", { className: "sr-only", children: "More" })
|
|
1151
|
+
] });
|
|
1152
|
+
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
|
|
1153
|
+
|
|
1154
|
+
// src/components/navigation/page-breadcrumb.tsx
|
|
1155
|
+
import { Fragment as Fragment2 } from "react";
|
|
1156
|
+
import { jsx as jsx27, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1157
|
+
function PageBreadcrumb({ items }) {
|
|
1158
|
+
return /* @__PURE__ */ jsx27(Breadcrumb, { children: /* @__PURE__ */ jsx27(BreadcrumbList, { children: items.map((item, index) => {
|
|
1159
|
+
const isLast = index === items.length - 1;
|
|
1160
|
+
return /* @__PURE__ */ jsxs18(Fragment2, { children: [
|
|
1161
|
+
/* @__PURE__ */ jsx27(BreadcrumbItem, { children: !isLast && item.href ? /* @__PURE__ */ jsx27(BreadcrumbLink, { href: item.href, children: item.label }) : /* @__PURE__ */ jsx27(BreadcrumbPage, { children: item.label }) }),
|
|
1162
|
+
!isLast ? /* @__PURE__ */ jsx27(BreadcrumbSeparator, {}) : null
|
|
1163
|
+
] }, `${item.label}-${index}`);
|
|
1164
|
+
}) }) });
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// src/components/navigation/steps.tsx
|
|
1168
|
+
import { AlertCircle as AlertCircle3, Check as Check3 } from "lucide-react";
|
|
1169
|
+
import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1170
|
+
var indicatorStyles = {
|
|
1171
|
+
complete: "border-primary bg-primary text-primary-foreground",
|
|
1172
|
+
current: "border-primary bg-primary/10 text-primary",
|
|
1173
|
+
upcoming: "border-border bg-background text-muted-foreground",
|
|
1174
|
+
error: "border-destructive bg-destructive/10 text-destructive"
|
|
1175
|
+
};
|
|
1176
|
+
function Steps({ className, items, orientation = "horizontal" }) {
|
|
1177
|
+
return /* @__PURE__ */ jsx28("ol", { className: cn("flex", orientation === "horizontal" ? "flex-col gap-4 md:flex-row" : "flex-col", className), children: items.map((item, index) => {
|
|
1178
|
+
const status = item.status ?? "upcoming";
|
|
1179
|
+
const isLast = index === items.length - 1;
|
|
1180
|
+
return /* @__PURE__ */ jsxs19(
|
|
1181
|
+
"li",
|
|
1182
|
+
{
|
|
1183
|
+
className: cn("relative", orientation === "horizontal" ? "flex-1" : "pb-6 last:pb-0"),
|
|
1184
|
+
children: [
|
|
1185
|
+
!isLast ? /* @__PURE__ */ jsx28(
|
|
1186
|
+
"span",
|
|
1187
|
+
{
|
|
1188
|
+
"aria-hidden": "true",
|
|
1189
|
+
className: cn(
|
|
1190
|
+
"absolute bg-border",
|
|
1191
|
+
orientation === "horizontal" ? "left-[calc(50%+1rem)] top-4 hidden h-px w-[calc(100%-1rem)] md:block" : "left-4 top-9 h-[calc(100%-1rem)] w-px"
|
|
1192
|
+
)
|
|
1193
|
+
}
|
|
1194
|
+
) : null,
|
|
1195
|
+
/* @__PURE__ */ jsxs19("div", { className: cn(
|
|
1196
|
+
orientation === "horizontal" ? "flex flex-col items-center gap-2 text-center" : "flex items-start gap-3"
|
|
1197
|
+
), children: [
|
|
1198
|
+
/* @__PURE__ */ jsxs19(
|
|
1199
|
+
"span",
|
|
1200
|
+
{
|
|
1201
|
+
className: cn(
|
|
1202
|
+
"relative z-10 inline-flex h-8 w-8 items-center justify-center rounded-full border text-sm font-semibold shadow-sm",
|
|
1203
|
+
indicatorStyles[status]
|
|
1204
|
+
),
|
|
1205
|
+
children: [
|
|
1206
|
+
status === "complete" ? /* @__PURE__ */ jsx28(Check3, { className: "h-4 w-4" }) : null,
|
|
1207
|
+
status === "error" ? /* @__PURE__ */ jsx28(AlertCircle3, { className: "h-4 w-4" }) : null,
|
|
1208
|
+
status === "current" || status === "upcoming" ? index + 1 : null
|
|
1209
|
+
]
|
|
1210
|
+
}
|
|
1211
|
+
),
|
|
1212
|
+
/* @__PURE__ */ jsxs19("div", { className: cn("grid gap-1", orientation === "vertical" && "pt-1"), children: [
|
|
1213
|
+
/* @__PURE__ */ jsx28("p", { className: cn("text-sm font-medium", status === "upcoming" ? "text-muted-foreground" : "text-foreground"), children: item.title }),
|
|
1214
|
+
item.description ? /* @__PURE__ */ jsx28("p", { className: "text-xs text-muted-foreground", children: item.description }) : null
|
|
1215
|
+
] })
|
|
1216
|
+
] })
|
|
1217
|
+
]
|
|
1218
|
+
},
|
|
1219
|
+
item.id ?? item.title
|
|
1220
|
+
);
|
|
1221
|
+
}) });
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/components/overlays/dialog.tsx
|
|
1225
|
+
import * as React10 from "react";
|
|
1226
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
1227
|
+
import { X } from "lucide-react";
|
|
1228
|
+
import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1229
|
+
var Dialog = DialogPrimitive.Root;
|
|
1230
|
+
var DialogTrigger = DialogPrimitive.Trigger;
|
|
1231
|
+
var DialogPortal = DialogPrimitive.Portal;
|
|
1232
|
+
var DialogClose = DialogPrimitive.Close;
|
|
1233
|
+
var DialogOverlay = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(
|
|
1234
|
+
DialogPrimitive.Overlay,
|
|
1235
|
+
{
|
|
1236
|
+
ref,
|
|
1237
|
+
className: cn(
|
|
1238
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1239
|
+
className
|
|
1240
|
+
),
|
|
1241
|
+
...props
|
|
1242
|
+
}
|
|
1243
|
+
));
|
|
1244
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
1245
|
+
var DialogContent = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs20(DialogPortal, { children: [
|
|
1246
|
+
/* @__PURE__ */ jsx29(DialogOverlay, {}),
|
|
1247
|
+
/* @__PURE__ */ jsxs20(
|
|
1248
|
+
DialogPrimitive.Content,
|
|
1249
|
+
{
|
|
1250
|
+
ref,
|
|
1251
|
+
className: cn(
|
|
1252
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
1253
|
+
className
|
|
1254
|
+
),
|
|
1255
|
+
...props,
|
|
1256
|
+
children: [
|
|
1257
|
+
children,
|
|
1258
|
+
/* @__PURE__ */ jsxs20(DialogPrimitive.Close, { className: "absolute right-4 top-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: [
|
|
1259
|
+
/* @__PURE__ */ jsx29(X, { className: "h-4 w-4" }),
|
|
1260
|
+
/* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Close" })
|
|
1261
|
+
] })
|
|
1262
|
+
]
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
] }));
|
|
1266
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
1267
|
+
var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx29("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
|
|
1268
|
+
DialogHeader.displayName = "DialogHeader";
|
|
1269
|
+
var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx29("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
|
|
1270
|
+
DialogFooter.displayName = "DialogFooter";
|
|
1271
|
+
var DialogTitle = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props }));
|
|
1272
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
1273
|
+
var DialogDescription = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx29(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
1274
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
1275
|
+
|
|
1276
|
+
// src/components/overlays/dropdown-menu.tsx
|
|
1277
|
+
import * as React11 from "react";
|
|
1278
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
1279
|
+
import { Check as Check4, ChevronRight as ChevronRight2, Circle } from "lucide-react";
|
|
1280
|
+
import { jsx as jsx30, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1281
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
1282
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
1283
|
+
var DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
1284
|
+
var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
1285
|
+
var DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
1286
|
+
var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
1287
|
+
var DropdownMenuSubTrigger = React11.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs21(
|
|
1288
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
1289
|
+
{
|
|
1290
|
+
ref,
|
|
1291
|
+
className: cn(
|
|
1292
|
+
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
1293
|
+
inset && "pl-8",
|
|
1294
|
+
className
|
|
1295
|
+
),
|
|
1296
|
+
...props,
|
|
1297
|
+
children: [
|
|
1298
|
+
children,
|
|
1299
|
+
/* @__PURE__ */ jsx30(ChevronRight2, { className: "ml-auto" })
|
|
1300
|
+
]
|
|
1301
|
+
}
|
|
1302
|
+
));
|
|
1303
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
1304
|
+
var DropdownMenuSubContent = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(
|
|
1305
|
+
DropdownMenuPrimitive.SubContent,
|
|
1306
|
+
{
|
|
1307
|
+
ref,
|
|
1308
|
+
className: cn(
|
|
1309
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
1310
|
+
className
|
|
1311
|
+
),
|
|
1312
|
+
...props
|
|
1313
|
+
}
|
|
1314
|
+
));
|
|
1315
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
1316
|
+
var DropdownMenuContent = React11.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx30(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx30(
|
|
1317
|
+
DropdownMenuPrimitive.Content,
|
|
1318
|
+
{
|
|
1319
|
+
ref,
|
|
1320
|
+
sideOffset,
|
|
1321
|
+
className: cn(
|
|
1322
|
+
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out 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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
1323
|
+
className
|
|
1324
|
+
),
|
|
1325
|
+
...props
|
|
1326
|
+
}
|
|
1327
|
+
) }));
|
|
1328
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
1329
|
+
var DropdownMenuItem = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx30(
|
|
1330
|
+
DropdownMenuPrimitive.Item,
|
|
1331
|
+
{
|
|
1332
|
+
ref,
|
|
1333
|
+
className: cn(
|
|
1334
|
+
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
1335
|
+
inset && "pl-8",
|
|
1336
|
+
className
|
|
1337
|
+
),
|
|
1338
|
+
...props
|
|
1339
|
+
}
|
|
1340
|
+
));
|
|
1341
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
1342
|
+
var DropdownMenuCheckboxItem = React11.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs21(
|
|
1343
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
1344
|
+
{
|
|
1345
|
+
ref,
|
|
1346
|
+
className: cn(
|
|
1347
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1348
|
+
className
|
|
1349
|
+
),
|
|
1350
|
+
...checked !== void 0 ? { checked } : {},
|
|
1351
|
+
...props,
|
|
1352
|
+
children: [
|
|
1353
|
+
/* @__PURE__ */ jsx30("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx30(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx30(Check4, { className: "h-4 w-4" }) }) }),
|
|
1354
|
+
children
|
|
1355
|
+
]
|
|
1356
|
+
}
|
|
1357
|
+
));
|
|
1358
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
1359
|
+
var DropdownMenuRadioItem = React11.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs21(
|
|
1360
|
+
DropdownMenuPrimitive.RadioItem,
|
|
1361
|
+
{
|
|
1362
|
+
ref,
|
|
1363
|
+
className: cn(
|
|
1364
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1365
|
+
className
|
|
1366
|
+
),
|
|
1367
|
+
...props,
|
|
1368
|
+
children: [
|
|
1369
|
+
/* @__PURE__ */ jsx30("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx30(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx30(Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
1370
|
+
children
|
|
1371
|
+
]
|
|
1372
|
+
}
|
|
1373
|
+
));
|
|
1374
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
1375
|
+
var DropdownMenuLabel = React11.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx30(DropdownMenuPrimitive.Label, { ref, className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className), ...props }));
|
|
1376
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
1377
|
+
var DropdownMenuSeparator = React11.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx30(DropdownMenuPrimitive.Separator, { ref, className: cn("-mx-1 my-1 h-px bg-muted", className), ...props }));
|
|
1378
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
1379
|
+
var DropdownMenuShortcut = ({ className, ...props }) => /* @__PURE__ */ jsx30("span", { className: cn("ml-auto text-xs tracking-widest opacity-60", className), ...props });
|
|
1380
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
1381
|
+
|
|
1382
|
+
// src/components/overlays/sheet.tsx
|
|
1383
|
+
import * as React12 from "react";
|
|
1384
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
1385
|
+
import { cva as cva3 } from "class-variance-authority";
|
|
1386
|
+
import { X as X2 } from "lucide-react";
|
|
1387
|
+
import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1388
|
+
var Sheet = SheetPrimitive.Root;
|
|
1389
|
+
var SheetTrigger = SheetPrimitive.Trigger;
|
|
1390
|
+
var SheetClose = SheetPrimitive.Close;
|
|
1391
|
+
var SheetPortal = SheetPrimitive.Portal;
|
|
1392
|
+
var SheetOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(
|
|
1393
|
+
SheetPrimitive.Overlay,
|
|
1394
|
+
{
|
|
1395
|
+
className: cn(
|
|
1396
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1397
|
+
className
|
|
1398
|
+
),
|
|
1399
|
+
...props,
|
|
1400
|
+
ref
|
|
1401
|
+
}
|
|
1402
|
+
));
|
|
1403
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
1404
|
+
var sheetVariants = cva3(
|
|
1405
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
1406
|
+
{
|
|
1407
|
+
variants: {
|
|
1408
|
+
side: {
|
|
1409
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
1410
|
+
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
1411
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
1412
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
defaultVariants: {
|
|
1416
|
+
side: "right"
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1420
|
+
var SheetContent = React12.forwardRef(
|
|
1421
|
+
({ side = "right", className, children, ...props }, ref) => /* @__PURE__ */ jsxs22(SheetPortal, { children: [
|
|
1422
|
+
/* @__PURE__ */ jsx31(SheetOverlay, {}),
|
|
1423
|
+
/* @__PURE__ */ jsxs22(SheetPrimitive.Content, { ref, className: cn(sheetVariants({ side }), className), ...props, children: [
|
|
1424
|
+
children,
|
|
1425
|
+
/* @__PURE__ */ jsxs22(SheetPrimitive.Close, { className: "absolute right-4 top-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-secondary", children: [
|
|
1426
|
+
/* @__PURE__ */ jsx31(X2, { className: "h-4 w-4" }),
|
|
1427
|
+
/* @__PURE__ */ jsx31("span", { className: "sr-only", children: "Close" })
|
|
1428
|
+
] })
|
|
1429
|
+
] })
|
|
1430
|
+
] })
|
|
1431
|
+
);
|
|
1432
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
1433
|
+
var SheetHeader = ({ className, ...props }) => /* @__PURE__ */ jsx31("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props });
|
|
1434
|
+
SheetHeader.displayName = "SheetHeader";
|
|
1435
|
+
var SheetFooter = ({ className, ...props }) => /* @__PURE__ */ jsx31("div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props });
|
|
1436
|
+
SheetFooter.displayName = "SheetFooter";
|
|
1437
|
+
var SheetTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(SheetPrimitive.Title, { ref, className: cn("text-lg font-semibold text-foreground", className), ...props }));
|
|
1438
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
1439
|
+
var SheetDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx31(SheetPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
1440
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
1441
|
+
|
|
1442
|
+
// src/components/primitives/alert.tsx
|
|
1443
|
+
import * as React13 from "react";
|
|
1444
|
+
import { cva as cva4 } from "class-variance-authority";
|
|
1445
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
1446
|
+
var alertVariants = cva4("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", {
|
|
1447
|
+
variants: {
|
|
1448
|
+
variant: {
|
|
1449
|
+
default: "bg-background text-foreground",
|
|
1450
|
+
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
|
|
1451
|
+
}
|
|
1452
|
+
},
|
|
1453
|
+
defaultVariants: {
|
|
1454
|
+
variant: "default"
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
var Alert = React13.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx32("div", { ref, role: "alert", className: cn(alertVariants({ variant }), className), ...props }));
|
|
1458
|
+
Alert.displayName = "Alert";
|
|
1459
|
+
var AlertTitle = React13.forwardRef(
|
|
1460
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx32("h5", { ref, className: cn("mb-1 font-medium leading-none tracking-tight", className), ...props })
|
|
1461
|
+
);
|
|
1462
|
+
AlertTitle.displayName = "AlertTitle";
|
|
1463
|
+
var AlertDescription = React13.forwardRef(
|
|
1464
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx32("div", { ref, className: cn("text-sm [&_p]:leading-relaxed", className), ...props })
|
|
1465
|
+
);
|
|
1466
|
+
AlertDescription.displayName = "AlertDescription";
|
|
1467
|
+
|
|
1468
|
+
// src/components/primitives/badge.tsx
|
|
1469
|
+
import { cva as cva5 } from "class-variance-authority";
|
|
1470
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1471
|
+
var badgeVariants = cva5("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", {
|
|
1472
|
+
variants: {
|
|
1473
|
+
variant: {
|
|
1474
|
+
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
1475
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1476
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
1477
|
+
outline: "text-foreground"
|
|
1478
|
+
}
|
|
1479
|
+
},
|
|
1480
|
+
defaultVariants: {
|
|
1481
|
+
variant: "default"
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
function Badge({ className, variant, ...props }) {
|
|
1485
|
+
return /* @__PURE__ */ jsx33("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// src/components/primitives/checkbox.tsx
|
|
1489
|
+
import * as React14 from "react";
|
|
1490
|
+
import { Check as Check5 } from "lucide-react";
|
|
1491
|
+
import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1492
|
+
var Checkbox = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs23("span", { className: "relative inline-flex h-4 w-4 shrink-0", children: [
|
|
1493
|
+
/* @__PURE__ */ jsx34(
|
|
1494
|
+
"input",
|
|
1495
|
+
{
|
|
1496
|
+
ref,
|
|
1497
|
+
type: "checkbox",
|
|
1498
|
+
className: cn(
|
|
1499
|
+
"peer absolute inset-0 h-4 w-4 cursor-pointer appearance-none rounded-[4px] border border-input bg-background shadow-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 checked:border-primary checked:bg-primary",
|
|
1500
|
+
className
|
|
1501
|
+
),
|
|
1502
|
+
...props
|
|
1503
|
+
}
|
|
1504
|
+
),
|
|
1505
|
+
/* @__PURE__ */ jsx34(
|
|
1506
|
+
Check5,
|
|
1507
|
+
{
|
|
1508
|
+
"aria-hidden": "true",
|
|
1509
|
+
className: "pointer-events-none absolute left-1/2 top-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 text-primary-foreground opacity-0 transition-opacity peer-checked:opacity-100"
|
|
1510
|
+
}
|
|
1511
|
+
)
|
|
1512
|
+
] }));
|
|
1513
|
+
Checkbox.displayName = "Checkbox";
|
|
1514
|
+
function CheckboxField({ id, label, description, containerClassName, className, ...props }) {
|
|
1515
|
+
const generatedId = React14.useId();
|
|
1516
|
+
const inputId = id ?? generatedId;
|
|
1517
|
+
return /* @__PURE__ */ jsxs23(
|
|
1518
|
+
"label",
|
|
1519
|
+
{
|
|
1520
|
+
htmlFor: inputId,
|
|
1521
|
+
className: cn("flex items-center gap-3 rounded-lg border border-border bg-card p-3 transition-colors hover:bg-accent/30", containerClassName),
|
|
1522
|
+
children: [
|
|
1523
|
+
/* @__PURE__ */ jsx34(Checkbox, { id: inputId, className, ...props }),
|
|
1524
|
+
/* @__PURE__ */ jsxs23("span", { className: "grid gap-1", children: [
|
|
1525
|
+
/* @__PURE__ */ jsx34("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
1526
|
+
description ? /* @__PURE__ */ jsx34("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
1527
|
+
] })
|
|
1528
|
+
]
|
|
1529
|
+
}
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// src/components/primitives/label.tsx
|
|
1534
|
+
import * as React15 from "react";
|
|
1535
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
1536
|
+
import { cva as cva6 } from "class-variance-authority";
|
|
1537
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
1538
|
+
var labelVariants = cva6("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
|
1539
|
+
var Label3 = React15.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx35(LabelPrimitive.Root, { ref, className: cn(labelVariants(), className), ...props }));
|
|
1540
|
+
Label3.displayName = LabelPrimitive.Root.displayName;
|
|
1541
|
+
|
|
1542
|
+
// src/components/primitives/radio-group.tsx
|
|
1543
|
+
import * as React16 from "react";
|
|
1544
|
+
import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1545
|
+
var RadioGroup2 = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx36("div", { ref, role: "radiogroup", className: cn("grid gap-3", className), ...props }));
|
|
1546
|
+
RadioGroup2.displayName = "RadioGroup";
|
|
1547
|
+
var RadioGroupItem = React16.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs24("span", { className: "relative inline-flex h-4 w-4 shrink-0", children: [
|
|
1548
|
+
/* @__PURE__ */ jsx36(
|
|
1549
|
+
"input",
|
|
1550
|
+
{
|
|
1551
|
+
ref,
|
|
1552
|
+
type: "radio",
|
|
1553
|
+
className: cn(
|
|
1554
|
+
"peer absolute inset-0 h-4 w-4 cursor-pointer appearance-none rounded-full border border-input bg-background shadow-sm ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 checked:border-primary",
|
|
1555
|
+
className
|
|
1556
|
+
),
|
|
1557
|
+
...props
|
|
1558
|
+
}
|
|
1559
|
+
),
|
|
1560
|
+
/* @__PURE__ */ jsx36(
|
|
1561
|
+
"span",
|
|
1562
|
+
{
|
|
1563
|
+
"aria-hidden": "true",
|
|
1564
|
+
className: "pointer-events-none absolute left-1/2 top-1/2 h-2 w-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary opacity-0 transition-opacity peer-checked:opacity-100"
|
|
1565
|
+
}
|
|
1566
|
+
)
|
|
1567
|
+
] }));
|
|
1568
|
+
RadioGroupItem.displayName = "RadioGroupItem";
|
|
1569
|
+
function RadioField({ id, label, description, containerClassName, className, ...props }) {
|
|
1570
|
+
const generatedId = React16.useId();
|
|
1571
|
+
const inputId = id ?? generatedId;
|
|
1572
|
+
return /* @__PURE__ */ jsxs24(
|
|
1573
|
+
"label",
|
|
1574
|
+
{
|
|
1575
|
+
htmlFor: inputId,
|
|
1576
|
+
className: cn("flex items-center gap-3 rounded-lg border border-border bg-card p-3 transition-colors hover:bg-accent/30", containerClassName),
|
|
1577
|
+
children: [
|
|
1578
|
+
/* @__PURE__ */ jsx36(RadioGroupItem, { id: inputId, className, ...props }),
|
|
1579
|
+
/* @__PURE__ */ jsxs24("span", { className: "grid gap-1", children: [
|
|
1580
|
+
/* @__PURE__ */ jsx36("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
1581
|
+
description ? /* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
1582
|
+
] })
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/components/primitives/separator.tsx
|
|
1589
|
+
import * as React17 from "react";
|
|
1590
|
+
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
1591
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
1592
|
+
var Separator3 = React17.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx37(
|
|
1593
|
+
SeparatorPrimitive.Root,
|
|
1594
|
+
{
|
|
1595
|
+
ref,
|
|
1596
|
+
decorative,
|
|
1597
|
+
orientation,
|
|
1598
|
+
className: cn("shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className),
|
|
1599
|
+
...props
|
|
1600
|
+
}
|
|
1601
|
+
));
|
|
1602
|
+
Separator3.displayName = SeparatorPrimitive.Root.displayName;
|
|
1603
|
+
|
|
1604
|
+
// src/components/primitives/switch.tsx
|
|
1605
|
+
import * as React18 from "react";
|
|
1606
|
+
import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1607
|
+
var Switch = React18.forwardRef(({ className, size = "default", ...props }, ref) => {
|
|
1608
|
+
const isSm = size === "sm";
|
|
1609
|
+
return /* @__PURE__ */ jsxs25(
|
|
1610
|
+
"span",
|
|
1611
|
+
{
|
|
1612
|
+
className: cn(
|
|
1613
|
+
"relative inline-flex shrink-0",
|
|
1614
|
+
isSm ? "h-4 w-7" : "h-6 w-10"
|
|
1615
|
+
),
|
|
1616
|
+
children: [
|
|
1617
|
+
/* @__PURE__ */ jsx38(
|
|
1618
|
+
"input",
|
|
1619
|
+
{
|
|
1620
|
+
ref,
|
|
1621
|
+
type: "checkbox",
|
|
1622
|
+
role: "switch",
|
|
1623
|
+
className: cn(
|
|
1624
|
+
"peer absolute inset-0 cursor-pointer appearance-none rounded-full border border-input bg-input",
|
|
1625
|
+
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1626
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1627
|
+
"checked:border-primary checked:bg-primary",
|
|
1628
|
+
className
|
|
1629
|
+
),
|
|
1630
|
+
...props
|
|
1631
|
+
}
|
|
1632
|
+
),
|
|
1633
|
+
/* @__PURE__ */ jsx38(
|
|
1634
|
+
"span",
|
|
1635
|
+
{
|
|
1636
|
+
"aria-hidden": "true",
|
|
1637
|
+
className: cn(
|
|
1638
|
+
"pointer-events-none absolute rounded-full bg-background shadow-sm transition-transform",
|
|
1639
|
+
isSm ? "top-0.5 left-0.5 h-3 w-3 peer-checked:translate-x-3" : "top-1 left-1 h-4 w-4 peer-checked:translate-x-4"
|
|
1640
|
+
)
|
|
1641
|
+
}
|
|
1642
|
+
)
|
|
1643
|
+
]
|
|
1644
|
+
}
|
|
1645
|
+
);
|
|
1646
|
+
});
|
|
1647
|
+
Switch.displayName = "Switch";
|
|
1648
|
+
function SwitchField({ id, label, description, containerClassName, size, className, ...props }) {
|
|
1649
|
+
const generatedId = React18.useId();
|
|
1650
|
+
const inputId = id ?? generatedId;
|
|
1651
|
+
return /* @__PURE__ */ jsxs25(
|
|
1652
|
+
"label",
|
|
1653
|
+
{
|
|
1654
|
+
htmlFor: inputId,
|
|
1655
|
+
className: cn(
|
|
1656
|
+
"flex cursor-pointer items-center justify-between gap-4 rounded-lg border border-border bg-card p-3 transition-colors hover:bg-accent/30",
|
|
1657
|
+
props.disabled && "cursor-not-allowed opacity-50 hover:bg-card",
|
|
1658
|
+
containerClassName
|
|
1659
|
+
),
|
|
1660
|
+
children: [
|
|
1661
|
+
/* @__PURE__ */ jsxs25("span", { className: "grid gap-0.5", children: [
|
|
1662
|
+
/* @__PURE__ */ jsx38("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
1663
|
+
description ? /* @__PURE__ */ jsx38("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
1664
|
+
] }),
|
|
1665
|
+
/* @__PURE__ */ jsx38(Switch, { id: inputId, size, className, ...props })
|
|
1666
|
+
]
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// src/components/primitives/textarea.tsx
|
|
1672
|
+
import * as React19 from "react";
|
|
1673
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
1674
|
+
var Textarea = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx39(
|
|
1675
|
+
"textarea",
|
|
1676
|
+
{
|
|
1677
|
+
ref,
|
|
1678
|
+
className: cn(
|
|
1679
|
+
"flex min-h-24 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
1680
|
+
className
|
|
1681
|
+
),
|
|
1682
|
+
...props
|
|
1683
|
+
}
|
|
1684
|
+
));
|
|
1685
|
+
Textarea.displayName = "Textarea";
|
|
1686
|
+
|
|
1687
|
+
// src/components/tables/data-table.tsx
|
|
1688
|
+
import { useMemo as useMemo3, useState as useState4 } from "react";
|
|
1689
|
+
import { ChevronLeft, ChevronRight as ChevronRight3, Search as Search2 } from "lucide-react";
|
|
1690
|
+
import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1691
|
+
function getCellContent(row, column) {
|
|
1692
|
+
if (column.render) {
|
|
1693
|
+
return column.render(row);
|
|
1694
|
+
}
|
|
1695
|
+
const value = row[column.key];
|
|
1696
|
+
if (value === null || value === void 0) {
|
|
1697
|
+
return /* @__PURE__ */ jsx40("span", { className: "text-muted-foreground/40", children: "-" });
|
|
1698
|
+
}
|
|
1699
|
+
if (typeof value === "boolean") {
|
|
1700
|
+
return value ? "Yes" : "No";
|
|
1701
|
+
}
|
|
1702
|
+
return String(value);
|
|
1703
|
+
}
|
|
1704
|
+
var SKELETON_ROWS = 5;
|
|
1705
|
+
function DataTable({
|
|
1706
|
+
data,
|
|
1707
|
+
columns,
|
|
1708
|
+
isLoading = false,
|
|
1709
|
+
actions,
|
|
1710
|
+
emptyMessage = "No records found",
|
|
1711
|
+
pageSize = 10
|
|
1712
|
+
}) {
|
|
1713
|
+
const [search, setSearch] = useState4("");
|
|
1714
|
+
const [page, setPage] = useState4(0);
|
|
1715
|
+
const filtered = useMemo3(() => {
|
|
1716
|
+
const query = search.toLowerCase().trim();
|
|
1717
|
+
if (!query) {
|
|
1718
|
+
return data;
|
|
1719
|
+
}
|
|
1720
|
+
return data.filter(
|
|
1721
|
+
(row) => Object.values(row).some(
|
|
1722
|
+
(value) => value != null && String(value).toLowerCase().includes(query)
|
|
1723
|
+
)
|
|
1724
|
+
);
|
|
1725
|
+
}, [data, search]);
|
|
1726
|
+
const totalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
|
|
1727
|
+
const currentPage = Math.min(page, totalPages - 1);
|
|
1728
|
+
const paginated = filtered.slice(currentPage * pageSize, (currentPage + 1) * pageSize);
|
|
1729
|
+
const mobileColumns = columns.filter((column) => !column.mobileHide);
|
|
1730
|
+
function handleSearch(value) {
|
|
1731
|
+
setSearch(value);
|
|
1732
|
+
setPage(0);
|
|
1733
|
+
}
|
|
1734
|
+
return /* @__PURE__ */ jsxs26("div", { className: "space-y-4", children: [
|
|
1735
|
+
/* @__PURE__ */ jsxs26("div", { className: "relative", children: [
|
|
1736
|
+
/* @__PURE__ */ jsx40(Search2, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1737
|
+
/* @__PURE__ */ jsx40(
|
|
1738
|
+
Input,
|
|
1739
|
+
{
|
|
1740
|
+
placeholder: "Search...",
|
|
1741
|
+
value: search,
|
|
1742
|
+
onChange: (event) => handleSearch(event.target.value),
|
|
1743
|
+
className: "pl-9"
|
|
1744
|
+
}
|
|
1745
|
+
)
|
|
1746
|
+
] }),
|
|
1747
|
+
/* @__PURE__ */ jsx40("div", { className: "hidden rounded-lg border md:block", children: /* @__PURE__ */ jsxs26(Table, { children: [
|
|
1748
|
+
/* @__PURE__ */ jsx40(TableHeader, { children: /* @__PURE__ */ jsxs26(TableRow, { children: [
|
|
1749
|
+
columns.map((column) => /* @__PURE__ */ jsx40(TableHead, { children: column.label }, String(column.key))),
|
|
1750
|
+
actions ? /* @__PURE__ */ jsx40(TableHead, { className: "w-[100px] text-right", children: "Actions" }) : null
|
|
1751
|
+
] }) }),
|
|
1752
|
+
/* @__PURE__ */ jsx40(TableBody, { children: isLoading ? Array.from({ length: SKELETON_ROWS }).map((_, index) => /* @__PURE__ */ jsxs26(TableRow, { children: [
|
|
1753
|
+
columns.map((column) => /* @__PURE__ */ jsx40(TableCell, { children: /* @__PURE__ */ jsx40(Skeleton, { className: "h-4 w-full" }) }, String(column.key))),
|
|
1754
|
+
actions ? /* @__PURE__ */ jsx40(TableCell, { children: /* @__PURE__ */ jsx40(Skeleton, { className: "ml-auto h-8 w-20" }) }) : null
|
|
1755
|
+
] }, index)) : paginated.length === 0 ? /* @__PURE__ */ jsx40(TableRow, { children: /* @__PURE__ */ jsx40(TableCell, { colSpan: columns.length + (actions ? 1 : 0), className: "py-12 text-center text-muted-foreground", children: emptyMessage }) }) : paginated.map((row, index) => /* @__PURE__ */ jsxs26(TableRow, { children: [
|
|
1756
|
+
columns.map((column) => /* @__PURE__ */ jsx40(TableCell, { children: getCellContent(row, column) }, String(column.key))),
|
|
1757
|
+
actions ? /* @__PURE__ */ jsx40(TableCell, { children: /* @__PURE__ */ jsx40("div", { className: "flex justify-end gap-1.5", children: actions(row) }) }) : null
|
|
1758
|
+
] }, index)) })
|
|
1759
|
+
] }) }),
|
|
1760
|
+
/* @__PURE__ */ jsx40("div", { className: "space-y-3 md:hidden", children: isLoading ? Array.from({ length: SKELETON_ROWS }).map((_, index) => /* @__PURE__ */ jsx40(Card, { children: /* @__PURE__ */ jsxs26(CardContent, { className: "space-y-2 p-4", children: [
|
|
1761
|
+
/* @__PURE__ */ jsx40(Skeleton, { className: "h-5 w-1/2" }),
|
|
1762
|
+
/* @__PURE__ */ jsx40(Skeleton, { className: "h-4 w-2/3" }),
|
|
1763
|
+
/* @__PURE__ */ jsx40(Skeleton, { className: "h-4 w-1/3" })
|
|
1764
|
+
] }) }, index)) : paginated.length === 0 ? /* @__PURE__ */ jsx40("p", { className: "py-10 text-center text-muted-foreground", children: emptyMessage }) : paginated.map((row, index) => /* @__PURE__ */ jsx40(Card, { children: /* @__PURE__ */ jsxs26(CardContent, { className: "space-y-3 p-4", children: [
|
|
1765
|
+
/* @__PURE__ */ jsx40("div", { className: "space-y-1.5", children: mobileColumns.map((column, mobileIndex) => /* @__PURE__ */ jsxs26(
|
|
1766
|
+
"div",
|
|
1767
|
+
{
|
|
1768
|
+
className: cn(
|
|
1769
|
+
"flex items-center gap-1.5",
|
|
1770
|
+
mobileIndex === 0 ? "text-sm font-medium text-foreground" : "text-xs text-muted-foreground"
|
|
1771
|
+
),
|
|
1772
|
+
children: [
|
|
1773
|
+
mobileIndex > 0 ? /* @__PURE__ */ jsxs26("span", { className: "shrink-0 font-medium text-foreground/50", children: [
|
|
1774
|
+
column.label,
|
|
1775
|
+
":"
|
|
1776
|
+
] }) : null,
|
|
1777
|
+
/* @__PURE__ */ jsx40("span", { className: "truncate", children: getCellContent(row, column) })
|
|
1778
|
+
]
|
|
1779
|
+
},
|
|
1780
|
+
String(column.key)
|
|
1781
|
+
)) }),
|
|
1782
|
+
actions ? /* @__PURE__ */ jsx40("div", { className: "flex gap-2 border-t border-border pt-2", children: actions(row) }) : null
|
|
1783
|
+
] }) }, index)) }),
|
|
1784
|
+
!isLoading && filtered.length > pageSize ? /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between", children: [
|
|
1785
|
+
/* @__PURE__ */ jsxs26("span", { className: "text-sm text-muted-foreground", children: [
|
|
1786
|
+
filtered.length,
|
|
1787
|
+
" records \xB7 Page ",
|
|
1788
|
+
currentPage + 1,
|
|
1789
|
+
" of ",
|
|
1790
|
+
totalPages
|
|
1791
|
+
] }),
|
|
1792
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex gap-1", children: [
|
|
1793
|
+
/* @__PURE__ */ jsx40(
|
|
1794
|
+
Button,
|
|
1795
|
+
{
|
|
1796
|
+
variant: "outline",
|
|
1797
|
+
size: "icon",
|
|
1798
|
+
className: "h-8 w-8",
|
|
1799
|
+
onClick: () => setPage((previous) => Math.max(0, previous - 1)),
|
|
1800
|
+
disabled: currentPage === 0,
|
|
1801
|
+
children: /* @__PURE__ */ jsx40(ChevronLeft, { className: "h-4 w-4" })
|
|
1802
|
+
}
|
|
1803
|
+
),
|
|
1804
|
+
/* @__PURE__ */ jsx40(
|
|
1805
|
+
Button,
|
|
1806
|
+
{
|
|
1807
|
+
variant: "outline",
|
|
1808
|
+
size: "icon",
|
|
1809
|
+
className: "h-8 w-8",
|
|
1810
|
+
onClick: () => setPage((previous) => Math.min(totalPages - 1, previous + 1)),
|
|
1811
|
+
disabled: currentPage >= totalPages - 1,
|
|
1812
|
+
children: /* @__PURE__ */ jsx40(ChevronRight3, { className: "h-4 w-4" })
|
|
1813
|
+
}
|
|
1814
|
+
)
|
|
1815
|
+
] })
|
|
1816
|
+
] }) : null
|
|
1817
|
+
] });
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/components/tables/table-row-actions.tsx
|
|
1821
|
+
import { MoreHorizontal as MoreHorizontal2 } from "lucide-react";
|
|
1822
|
+
import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1823
|
+
function TableRowActions({ className, label = "Abrir acciones", menuLabel = "Acciones", items }) {
|
|
1824
|
+
return /* @__PURE__ */ jsxs27(DropdownMenu, { children: [
|
|
1825
|
+
/* @__PURE__ */ jsx41(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx41(Button, { variant: "ghost", size: "icon", className: cn("h-8 w-8 shadow-none", className), "aria-label": label, children: /* @__PURE__ */ jsx41(MoreHorizontal2, { className: "h-4 w-4" }) }) }),
|
|
1826
|
+
/* @__PURE__ */ jsxs27(DropdownMenuContent, { align: "end", className: "w-48", children: [
|
|
1827
|
+
/* @__PURE__ */ jsx41(DropdownMenuLabel, { children: menuLabel }),
|
|
1828
|
+
/* @__PURE__ */ jsx41(DropdownMenuSeparator, {}),
|
|
1829
|
+
items.map((item) => /* @__PURE__ */ jsxs27(
|
|
1830
|
+
DropdownMenuItem,
|
|
1831
|
+
{
|
|
1832
|
+
disabled: item.disabled,
|
|
1833
|
+
onSelect: item.onSelect,
|
|
1834
|
+
className: cn(item.destructive && "text-destructive focus:bg-destructive/10 focus:text-destructive"),
|
|
1835
|
+
children: [
|
|
1836
|
+
item.icon,
|
|
1837
|
+
item.label,
|
|
1838
|
+
item.shortcut ? /* @__PURE__ */ jsx41(DropdownMenuShortcut, { children: item.shortcut }) : null
|
|
1839
|
+
]
|
|
1840
|
+
},
|
|
1841
|
+
item.label
|
|
1842
|
+
))
|
|
1843
|
+
] })
|
|
1844
|
+
] });
|
|
1845
|
+
}
|
|
1846
|
+
export {
|
|
1847
|
+
Alert,
|
|
1848
|
+
AlertDescription,
|
|
1849
|
+
AlertTitle,
|
|
1850
|
+
AppShell,
|
|
1851
|
+
Avatar,
|
|
1852
|
+
AvatarFallback,
|
|
1853
|
+
AvatarGroup,
|
|
1854
|
+
AvatarImage,
|
|
1855
|
+
Badge,
|
|
1856
|
+
BrandLogo,
|
|
1857
|
+
Breadcrumb,
|
|
1858
|
+
BreadcrumbEllipsis,
|
|
1859
|
+
BreadcrumbItem,
|
|
1860
|
+
BreadcrumbLink,
|
|
1861
|
+
BreadcrumbList,
|
|
1862
|
+
BreadcrumbPage,
|
|
1863
|
+
BreadcrumbSeparator,
|
|
1864
|
+
Button,
|
|
1865
|
+
Card,
|
|
1866
|
+
CardContent,
|
|
1867
|
+
CardDescription,
|
|
1868
|
+
CardFooter,
|
|
1869
|
+
CardHeader,
|
|
1870
|
+
CardTitle,
|
|
1871
|
+
CenteredIconCard,
|
|
1872
|
+
Checkbox,
|
|
1873
|
+
CheckboxField,
|
|
1874
|
+
ClickableCard,
|
|
1875
|
+
DataTable,
|
|
1876
|
+
Dialog,
|
|
1877
|
+
DialogClose,
|
|
1878
|
+
DialogContent,
|
|
1879
|
+
DialogDescription,
|
|
1880
|
+
DialogFooter,
|
|
1881
|
+
DialogHeader,
|
|
1882
|
+
DialogOverlay,
|
|
1883
|
+
DialogPortal,
|
|
1884
|
+
DialogTitle,
|
|
1885
|
+
DialogTrigger,
|
|
1886
|
+
Drawer,
|
|
1887
|
+
DrawerClose,
|
|
1888
|
+
DrawerContent,
|
|
1889
|
+
DrawerDescription,
|
|
1890
|
+
DrawerFooter,
|
|
1891
|
+
DrawerHeader,
|
|
1892
|
+
DrawerOverlay,
|
|
1893
|
+
DrawerPortal,
|
|
1894
|
+
DrawerTitle,
|
|
1895
|
+
DrawerTrigger,
|
|
1896
|
+
DropdownMenu,
|
|
1897
|
+
DropdownMenuCheckboxItem,
|
|
1898
|
+
DropdownMenuContent,
|
|
1899
|
+
DropdownMenuGroup,
|
|
1900
|
+
DropdownMenuItem,
|
|
1901
|
+
DropdownMenuLabel,
|
|
1902
|
+
DropdownMenuPortal,
|
|
1903
|
+
DropdownMenuRadioGroup,
|
|
1904
|
+
DropdownMenuRadioItem,
|
|
1905
|
+
DropdownMenuSeparator,
|
|
1906
|
+
DropdownMenuShortcut,
|
|
1907
|
+
DropdownMenuSub,
|
|
1908
|
+
DropdownMenuSubContent,
|
|
1909
|
+
DropdownMenuSubTrigger,
|
|
1910
|
+
DropdownMenuTrigger,
|
|
1911
|
+
FeatureIcon,
|
|
1912
|
+
FormSection,
|
|
1913
|
+
Input,
|
|
1914
|
+
Label3 as Label,
|
|
1915
|
+
LoadingCard,
|
|
1916
|
+
LoadingState,
|
|
1917
|
+
LoadingTableRows,
|
|
1918
|
+
ModuleIconButton,
|
|
1919
|
+
Navbar,
|
|
1920
|
+
NotificationAction,
|
|
1921
|
+
NotificationMessage,
|
|
1922
|
+
PageBreadcrumb,
|
|
1923
|
+
PageHeader,
|
|
1924
|
+
ProfileAvatar,
|
|
1925
|
+
ProfileAvatarRow,
|
|
1926
|
+
RadioField,
|
|
1927
|
+
RadioGroup2 as RadioGroup,
|
|
1928
|
+
RadioGroupItem,
|
|
1929
|
+
SearchableSelect,
|
|
1930
|
+
Select,
|
|
1931
|
+
SelectContent,
|
|
1932
|
+
SelectGroup,
|
|
1933
|
+
SelectItem,
|
|
1934
|
+
SelectLabel,
|
|
1935
|
+
SelectScrollDownButton,
|
|
1936
|
+
SelectScrollUpButton,
|
|
1937
|
+
SelectSeparator,
|
|
1938
|
+
SelectTrigger,
|
|
1939
|
+
SelectValue,
|
|
1940
|
+
Separator3 as Separator,
|
|
1941
|
+
Sheet,
|
|
1942
|
+
SheetClose,
|
|
1943
|
+
SheetContent,
|
|
1944
|
+
SheetDescription,
|
|
1945
|
+
SheetFooter,
|
|
1946
|
+
SheetHeader,
|
|
1947
|
+
SheetOverlay,
|
|
1948
|
+
SheetPortal,
|
|
1949
|
+
SheetTitle,
|
|
1950
|
+
SheetTrigger,
|
|
1951
|
+
Sidebar,
|
|
1952
|
+
Skeleton,
|
|
1953
|
+
Spinner,
|
|
1954
|
+
StatusBadge,
|
|
1955
|
+
Steps,
|
|
1956
|
+
Switch,
|
|
1957
|
+
SwitchField,
|
|
1958
|
+
Table,
|
|
1959
|
+
TableBody,
|
|
1960
|
+
TableCaption,
|
|
1961
|
+
TableCell,
|
|
1962
|
+
TableFooter,
|
|
1963
|
+
TableHead,
|
|
1964
|
+
TableHeader,
|
|
1965
|
+
TableRow,
|
|
1966
|
+
TableRowActions,
|
|
1967
|
+
Textarea,
|
|
1968
|
+
ThemeProvider,
|
|
1969
|
+
ThemeToggle,
|
|
1970
|
+
Toaster,
|
|
1971
|
+
Typography,
|
|
1972
|
+
badgeVariants,
|
|
1973
|
+
buttonVariants,
|
|
1974
|
+
cn,
|
|
1975
|
+
notify,
|
|
1976
|
+
useTheme
|
|
1977
|
+
};
|