@acsrocha/ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -0
- package/dist/index.cjs +1637 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +395 -0
- package/dist/index.d.ts +395 -0
- package/dist/index.js +1576 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +3242 -0
- package/dist/theme.css +3242 -0
- package/package.json +60 -0
- package/tailwind.preset.cjs +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1576 @@
|
|
|
1
|
+
import * as React3 from 'react';
|
|
2
|
+
import React3__default, { forwardRef, useState, useEffect, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
3
|
+
import { Check, Grid3x3, List, Table, LayoutGrid, RefreshCw, Loader2, Filter, Bookmark, History, Download, Upload, Save, XCircle, ChevronDown, ChevronRight, Activity, Trash2, X, AlertTriangle, CheckCircle, Database, Plus, Edit, Shield } from 'lucide-react';
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { clsx } from 'clsx';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import { AnimatePresence, motion } from 'framer-motion';
|
|
9
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
10
|
+
import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
|
|
11
|
+
import { createPortal } from 'react-dom';
|
|
12
|
+
|
|
13
|
+
function cn(...inputs) {
|
|
14
|
+
return twMerge(clsx(inputs));
|
|
15
|
+
}
|
|
16
|
+
var buttonVariants = cva(
|
|
17
|
+
"relative inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-semibold ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:scale-[1.03] active:scale-[0.98] overflow-hidden group",
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: "bg-gradient-to-br from-blue-500 via-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/25 hover:shadow-xl hover:shadow-blue-500/40 border border-blue-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
22
|
+
destructive: "bg-gradient-to-br from-red-500 via-red-600 to-red-700 text-white shadow-lg shadow-red-500/25 hover:shadow-xl hover:shadow-red-500/40 border border-red-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
23
|
+
outline: "border-2 border-slate-300 bg-white/80 backdrop-blur-sm hover:bg-white hover:border-blue-400 hover:text-blue-700 text-slate-700 shadow-sm hover:shadow-lg hover:shadow-blue-500/10 before:absolute before:inset-0 before:bg-gradient-to-br before:from-blue-50/50 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
24
|
+
secondary: "bg-gradient-to-br from-slate-500 via-slate-600 to-slate-700 text-white shadow-lg shadow-slate-500/25 hover:shadow-xl hover:shadow-slate-500/40 border border-slate-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
25
|
+
ghost: "hover:bg-slate-100/80 hover:text-slate-900 shadow-none hover:shadow-md text-slate-600 backdrop-blur-sm before:absolute before:inset-0 before:bg-gradient-to-br before:from-slate-100/50 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
26
|
+
link: "text-blue-600 underline-offset-4 hover:underline shadow-none hover:shadow-none hover:scale-100 hover:text-blue-700 relative z-10",
|
|
27
|
+
success: "bg-gradient-to-br from-emerald-500 via-emerald-600 to-emerald-700 text-white shadow-lg shadow-emerald-500/25 hover:shadow-xl hover:shadow-emerald-500/40 border border-emerald-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity",
|
|
28
|
+
warning: "bg-gradient-to-br from-amber-500 via-amber-600 to-amber-700 text-white shadow-lg shadow-amber-500/25 hover:shadow-xl hover:shadow-amber-500/40 border border-amber-400/20 before:absolute before:inset-0 before:bg-gradient-to-br before:from-white/20 before:to-transparent before:opacity-0 hover:before:opacity-100 before:transition-opacity"
|
|
29
|
+
},
|
|
30
|
+
size: {
|
|
31
|
+
default: "h-11 px-6 py-2.5 text-sm",
|
|
32
|
+
sm: "h-9 px-4 text-xs",
|
|
33
|
+
lg: "h-13 px-8 text-base",
|
|
34
|
+
icon: "h-11 w-11"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: "default",
|
|
39
|
+
size: "default"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
var Button = React3.forwardRef(
|
|
44
|
+
({ className, variant, size, ...props }, ref) => {
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
"button",
|
|
47
|
+
{
|
|
48
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
49
|
+
ref,
|
|
50
|
+
...props,
|
|
51
|
+
children: /* @__PURE__ */ jsx("span", { className: "relative z-10 flex items-center justify-center gap-2", children: props.children })
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
Button.displayName = "Button";
|
|
57
|
+
var badgeVariants = cva(
|
|
58
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
|
|
59
|
+
{
|
|
60
|
+
variants: {
|
|
61
|
+
variant: {
|
|
62
|
+
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
63
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
64
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
65
|
+
outline: "text-foreground",
|
|
66
|
+
success: "border-transparent bg-emerald-500 text-white hover:bg-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400",
|
|
67
|
+
warning: "border-transparent bg-amber-500 text-white hover:bg-amber-600 dark:bg-amber-900/30 dark:text-amber-400"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
defaultVariants: {
|
|
71
|
+
variant: "default"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
function Badge({ className, variant, ...props }) {
|
|
76
|
+
return /* @__PURE__ */ jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
77
|
+
}
|
|
78
|
+
var VIEW_MODE_CONFIG = {
|
|
79
|
+
cards: { value: "cards", icon: LayoutGrid, label: "Cards" },
|
|
80
|
+
table: { value: "table", icon: Table, label: "Tabela" },
|
|
81
|
+
list: { value: "list", icon: List, label: "Lista" },
|
|
82
|
+
grid: { value: "grid", icon: Grid3x3, label: "Grade" }
|
|
83
|
+
};
|
|
84
|
+
var BTN_H = "h-9";
|
|
85
|
+
var CTRL_BTN = `relative z-10 inline-flex items-center justify-center gap-1.5 px-3 text-xs font-semibold whitespace-nowrap transition-colors duration-150`;
|
|
86
|
+
function SelectorBar({ children, activeIndex }) {
|
|
87
|
+
const containerRef = useRef(null);
|
|
88
|
+
const [highlight, setHighlight] = useState({ left: 0, width: 0 });
|
|
89
|
+
const measure = () => {
|
|
90
|
+
const container = containerRef.current;
|
|
91
|
+
if (!container) return;
|
|
92
|
+
const buttons = container.querySelectorAll("button");
|
|
93
|
+
const active = buttons[activeIndex];
|
|
94
|
+
if (!active) return;
|
|
95
|
+
setHighlight({ left: active.offsetLeft, width: active.offsetWidth });
|
|
96
|
+
};
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
|
+
measure();
|
|
99
|
+
}, [activeIndex, children]);
|
|
100
|
+
useLayoutEffect(() => {
|
|
101
|
+
const container = containerRef.current;
|
|
102
|
+
if (!container) return;
|
|
103
|
+
const observer = new ResizeObserver(measure);
|
|
104
|
+
observer.observe(container);
|
|
105
|
+
return () => observer.disconnect();
|
|
106
|
+
}, []);
|
|
107
|
+
return /* @__PURE__ */ jsxs(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
ref: containerRef,
|
|
111
|
+
className: `relative inline-flex items-stretch border border-input bg-background rounded-md ${BTN_H} p-0.5 gap-0.5`,
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
"div",
|
|
115
|
+
{
|
|
116
|
+
className: "absolute top-0.5 bottom-0.5 bg-blue-600 rounded transition-all duration-200 ease-out pointer-events-none",
|
|
117
|
+
style: { left: highlight.left, width: highlight.width }
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
children
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
function PageHeader({
|
|
126
|
+
title,
|
|
127
|
+
subtitle,
|
|
128
|
+
icon: Icon,
|
|
129
|
+
actions,
|
|
130
|
+
badge,
|
|
131
|
+
viewMode,
|
|
132
|
+
onViewModeChange,
|
|
133
|
+
viewModeOptions = ["table", "cards"],
|
|
134
|
+
loading = false,
|
|
135
|
+
tabs,
|
|
136
|
+
activeTab,
|
|
137
|
+
onTabChange,
|
|
138
|
+
onRefresh
|
|
139
|
+
}) {
|
|
140
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between", children: [
|
|
141
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
142
|
+
Icon && /* @__PURE__ */ jsx("div", { className: "bg-primary/10 rounded-lg flex-shrink-0 p-2", children: /* @__PURE__ */ jsx(Icon, { className: `w-6 h-6 text-primary ${loading ? "animate-pulse" : ""}` }) }),
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
144
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
145
|
+
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold whitespace-nowrap", children: title }),
|
|
146
|
+
badge && /* @__PURE__ */ jsx(Badge, { variant: badge.variant || "secondary", className: "whitespace-nowrap", children: badge.label })
|
|
147
|
+
] }),
|
|
148
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs mt-0.5", children: subtitle })
|
|
149
|
+
] })
|
|
150
|
+
] }),
|
|
151
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
152
|
+
actions,
|
|
153
|
+
tabs && onTabChange && /* @__PURE__ */ jsx(SelectorBar, { activeIndex: tabs.findIndex((t) => t.value === activeTab), children: tabs.map((t) => /* @__PURE__ */ jsxs(
|
|
154
|
+
"button",
|
|
155
|
+
{
|
|
156
|
+
onClick: () => onTabChange(t.value),
|
|
157
|
+
className: `${CTRL_BTN} ${activeTab === t.value ? "text-white" : "text-muted-foreground hover:text-foreground"}`,
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ jsx(t.icon, { className: "w-3.5 h-3.5 shrink-0" }),
|
|
160
|
+
t.label,
|
|
161
|
+
(t.badge ?? 0) > 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 bg-red-500 text-white text-[10px] font-bold rounded-full min-w-[18px] h-[18px] flex items-center justify-center px-1", children: t.badge })
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
t.value
|
|
165
|
+
)) }),
|
|
166
|
+
viewMode && onViewModeChange && viewModeOptions.length > 1 && /* @__PURE__ */ jsx(SelectorBar, { activeIndex: viewModeOptions.indexOf(viewMode), children: viewModeOptions.map((mode) => {
|
|
167
|
+
const config = VIEW_MODE_CONFIG[mode];
|
|
168
|
+
return /* @__PURE__ */ jsxs(
|
|
169
|
+
"button",
|
|
170
|
+
{
|
|
171
|
+
onClick: () => onViewModeChange(mode),
|
|
172
|
+
className: `${CTRL_BTN} ${viewMode === mode ? "text-white" : "text-muted-foreground hover:text-foreground"}`,
|
|
173
|
+
children: [
|
|
174
|
+
/* @__PURE__ */ jsx(config.icon, { className: "w-3.5 h-3.5" }),
|
|
175
|
+
config.label
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
mode
|
|
179
|
+
);
|
|
180
|
+
}) }),
|
|
181
|
+
onRefresh && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onRefresh, disabled: loading, className: "gap-1.5 text-xs font-semibold", children: [
|
|
182
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `w-3.5 h-3.5 ${loading ? "animate-spin" : ""}` }),
|
|
183
|
+
" Atualizar"
|
|
184
|
+
] })
|
|
185
|
+
] })
|
|
186
|
+
] });
|
|
187
|
+
}
|
|
188
|
+
var Card = React3.forwardRef(
|
|
189
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
190
|
+
"div",
|
|
191
|
+
{
|
|
192
|
+
ref,
|
|
193
|
+
className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className),
|
|
194
|
+
...props
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
Card.displayName = "Card";
|
|
199
|
+
var CardHeader = React3.forwardRef(
|
|
200
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
|
|
201
|
+
);
|
|
202
|
+
CardHeader.displayName = "CardHeader";
|
|
203
|
+
var CardTitle = React3.forwardRef(
|
|
204
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
205
|
+
"h3",
|
|
206
|
+
{
|
|
207
|
+
ref,
|
|
208
|
+
className: cn("text-2xl font-semibold leading-none tracking-tight", className),
|
|
209
|
+
...props
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
CardTitle.displayName = "CardTitle";
|
|
214
|
+
var CardDescription = React3.forwardRef(
|
|
215
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props })
|
|
216
|
+
);
|
|
217
|
+
CardDescription.displayName = "CardDescription";
|
|
218
|
+
var CardContent = React3.forwardRef(
|
|
219
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props })
|
|
220
|
+
);
|
|
221
|
+
CardContent.displayName = "CardContent";
|
|
222
|
+
var CardFooter = React3.forwardRef(
|
|
223
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
|
|
224
|
+
);
|
|
225
|
+
CardFooter.displayName = "CardFooter";
|
|
226
|
+
var STAT_ACCENT_SEQUENCE = ["blue", "green", "amber", "purple", "teal", "rose"];
|
|
227
|
+
var accentLight = {
|
|
228
|
+
blue: { border: "border-l-blue-400", icon: "bg-blue-100 text-blue-600", text: "text-blue-600" },
|
|
229
|
+
purple: { border: "border-l-purple-400", icon: "bg-purple-100 text-purple-600", text: "text-purple-600" },
|
|
230
|
+
green: { border: "border-l-emerald-400", icon: "bg-emerald-100 text-emerald-600", text: "text-emerald-600" },
|
|
231
|
+
amber: { border: "border-l-amber-400", icon: "bg-amber-100 text-amber-600", text: "text-amber-600" },
|
|
232
|
+
teal: { border: "border-l-teal-400", icon: "bg-teal-100 text-teal-600", text: "text-teal-600" },
|
|
233
|
+
rose: { border: "border-l-rose-400", icon: "bg-rose-100 text-rose-600", text: "text-rose-600" }
|
|
234
|
+
};
|
|
235
|
+
var accentDark = {
|
|
236
|
+
blue: { gradient: "bg-gradient-to-br from-blue-950 to-blue-900", icon: "bg-black/20 text-white/70" },
|
|
237
|
+
purple: { gradient: "bg-gradient-to-br from-purple-950 to-purple-900", icon: "bg-black/20 text-white/70" },
|
|
238
|
+
green: { gradient: "bg-gradient-to-br from-green-950 to-green-900", icon: "bg-black/20 text-white/70" },
|
|
239
|
+
amber: { gradient: "bg-gradient-to-br from-orange-950 to-orange-900", icon: "bg-black/20 text-white/70" },
|
|
240
|
+
teal: { gradient: "bg-gradient-to-br from-emerald-950 to-emerald-900", icon: "bg-black/20 text-white/70" },
|
|
241
|
+
rose: { gradient: "bg-gradient-to-br from-red-950 to-red-900", icon: "bg-black/20 text-white/70" }
|
|
242
|
+
};
|
|
243
|
+
function StatCard({
|
|
244
|
+
icon: Icon,
|
|
245
|
+
title,
|
|
246
|
+
label,
|
|
247
|
+
value,
|
|
248
|
+
subtitle,
|
|
249
|
+
sublabel,
|
|
250
|
+
gradient,
|
|
251
|
+
accentColor,
|
|
252
|
+
color,
|
|
253
|
+
onClick,
|
|
254
|
+
variant = "default",
|
|
255
|
+
loading = false,
|
|
256
|
+
active = false
|
|
257
|
+
}) {
|
|
258
|
+
const displayLabel = title || label;
|
|
259
|
+
const displaySublabel = subtitle || sublabel;
|
|
260
|
+
const isClickable = !!onClick;
|
|
261
|
+
const [isDark, setIsDark] = useState(
|
|
262
|
+
() => document.documentElement.classList.contains("dark")
|
|
263
|
+
);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
const observer = new MutationObserver(() => {
|
|
266
|
+
setIsDark(document.documentElement.classList.contains("dark"));
|
|
267
|
+
});
|
|
268
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
|
|
269
|
+
return () => observer.disconnect();
|
|
270
|
+
}, []);
|
|
271
|
+
if (variant === "slim") {
|
|
272
|
+
return /* @__PURE__ */ jsx(
|
|
273
|
+
Card,
|
|
274
|
+
{
|
|
275
|
+
className: `border-0 shadow-md transition-all ${isClickable ? "cursor-pointer hover:shadow-lg" : ""} ${active ? "ring-2 ring-primary" : ""}`,
|
|
276
|
+
onClick,
|
|
277
|
+
children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
278
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide text-muted-foreground mb-1", children: displayLabel }),
|
|
279
|
+
/* @__PURE__ */ jsx("p", { className: "text-base font-bold", children: loading ? /* @__PURE__ */ jsx(Loader2, { className: "w-4 h-4 animate-spin mx-auto" }) : value })
|
|
280
|
+
] }) })
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
let cardClass = "";
|
|
285
|
+
let iconClass = "";
|
|
286
|
+
let valueClass = "";
|
|
287
|
+
if (accentColor) {
|
|
288
|
+
if (isDark) {
|
|
289
|
+
cardClass = `border-0 ${accentDark[accentColor].gradient}`;
|
|
290
|
+
iconClass = accentDark[accentColor].icon;
|
|
291
|
+
valueClass = "text-foreground";
|
|
292
|
+
} else {
|
|
293
|
+
cardClass = `border border-border border-l-4 ${accentLight[accentColor].border} bg-card shadow-sm`;
|
|
294
|
+
iconClass = accentLight[accentColor].icon;
|
|
295
|
+
valueClass = accentLight[accentColor].text;
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
cardClass = `border-0 ${gradient ? `bg-gradient-to-br ${gradient}` : "shadow-md"}`;
|
|
299
|
+
iconClass = color || (gradient ? "bg-black/10 dark:bg-white/10" : "bg-primary/10");
|
|
300
|
+
valueClass = "";
|
|
301
|
+
}
|
|
302
|
+
return /* @__PURE__ */ jsx(
|
|
303
|
+
Card,
|
|
304
|
+
{
|
|
305
|
+
className: `transition-all overflow-hidden ${cardClass} ${isClickable ? "cursor-pointer hover:shadow-md hover:scale-[1.02]" : ""} ${active ? "ring-2 ring-primary shadow-md scale-[1.02]" : ""}`,
|
|
306
|
+
onClick,
|
|
307
|
+
children: /* @__PURE__ */ jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
308
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
309
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide font-medium text-muted-foreground mb-1", children: displayLabel }),
|
|
310
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-baseline gap-2", children: /* @__PURE__ */ jsx("h3", { className: `text-2xl font-bold leading-none ${valueClass}`, children: loading ? /* @__PURE__ */ jsx(Loader2, { className: "w-5 h-5 animate-spin" }) : value }) }),
|
|
311
|
+
displaySublabel && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground mt-1", children: displaySublabel })
|
|
312
|
+
] }),
|
|
313
|
+
Icon && /* @__PURE__ */ jsx("div", { className: `p-1.5 rounded-lg ${iconClass}`, children: /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }) })
|
|
314
|
+
] }) })
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
var COLS_CLASS = {
|
|
319
|
+
2: "grid-cols-1 md:grid-cols-2",
|
|
320
|
+
3: "grid-cols-1 md:grid-cols-3",
|
|
321
|
+
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4",
|
|
322
|
+
5: "grid-cols-1 md:grid-cols-3 lg:grid-cols-5",
|
|
323
|
+
6: "grid-cols-1 md:grid-cols-3 lg:grid-cols-6"
|
|
324
|
+
};
|
|
325
|
+
function resolveStatsCols(count, override) {
|
|
326
|
+
const cols = override ?? Math.min(count, 6);
|
|
327
|
+
return COLS_CLASS[cols] ?? COLS_CLASS[6];
|
|
328
|
+
}
|
|
329
|
+
function PageLayout({
|
|
330
|
+
header,
|
|
331
|
+
stats,
|
|
332
|
+
statsCols,
|
|
333
|
+
content,
|
|
334
|
+
viewMode,
|
|
335
|
+
tableContent,
|
|
336
|
+
cardContent,
|
|
337
|
+
paddingX = "px-3",
|
|
338
|
+
paddingTop = "pt-3",
|
|
339
|
+
paddingBottom = "pb-[2px]",
|
|
340
|
+
gapHeaderStats = "mt-4",
|
|
341
|
+
gapStatsContent = "mt-4",
|
|
342
|
+
maxWidth = "max-w-[1600px]",
|
|
343
|
+
extras,
|
|
344
|
+
fillHeight = true
|
|
345
|
+
}) {
|
|
346
|
+
const mainContent = viewMode !== void 0 ? viewMode === "table" ? tableContent : cardContent : content;
|
|
347
|
+
return /* @__PURE__ */ jsxs("main", { className: `gradient-bg ${fillHeight ? "h-full flex flex-col" : ""} ${paddingX} ${paddingTop} ${paddingBottom}`, children: [
|
|
348
|
+
/* @__PURE__ */ jsxs("div", { className: `${maxWidth} mx-auto w-full ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
|
|
349
|
+
header,
|
|
350
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid ${resolveStatsCols(stats.length, statsCols)} gap-3 ${gapHeaderStats}`, children: stats.map((stat, i) => {
|
|
351
|
+
const needsDefault = !stat.accentColor && !stat.gradient;
|
|
352
|
+
return /* @__PURE__ */ jsx(
|
|
353
|
+
StatCard,
|
|
354
|
+
{
|
|
355
|
+
...stat,
|
|
356
|
+
accentColor: needsDefault ? STAT_ACCENT_SEQUENCE[i % STAT_ACCENT_SEQUENCE.length] : stat.accentColor
|
|
357
|
+
},
|
|
358
|
+
stat.title ?? stat.label ?? i
|
|
359
|
+
);
|
|
360
|
+
}) }),
|
|
361
|
+
/* @__PURE__ */ jsx("div", { className: `${gapStatsContent} ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: mainContent })
|
|
362
|
+
] }),
|
|
363
|
+
extras
|
|
364
|
+
] });
|
|
365
|
+
}
|
|
366
|
+
var Table2 = React3.forwardRef(
|
|
367
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full", children: /* @__PURE__ */ jsx(
|
|
368
|
+
"table",
|
|
369
|
+
{
|
|
370
|
+
ref,
|
|
371
|
+
className: cn("w-full caption-bottom text-sm bg-transparent", className),
|
|
372
|
+
...props
|
|
373
|
+
}
|
|
374
|
+
) })
|
|
375
|
+
);
|
|
376
|
+
Table2.displayName = "Table";
|
|
377
|
+
var TableHeader = React3.forwardRef(
|
|
378
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
379
|
+
"thead",
|
|
380
|
+
{
|
|
381
|
+
ref,
|
|
382
|
+
className: cn(
|
|
383
|
+
"[&_tr]:border-b [&_tr]:border-border [&_tr]:bg-muted/60 dark:[&_tr]:bg-gradient-to-b dark:[&_tr]:from-slate-700 dark:[&_tr]:to-slate-800 dark:[&_tr]:border-cyan-400/60 dark:[&_tr]:border-b-2",
|
|
384
|
+
className
|
|
385
|
+
),
|
|
386
|
+
...props
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
);
|
|
390
|
+
TableHeader.displayName = "TableHeader";
|
|
391
|
+
var TableBody = React3.forwardRef(
|
|
392
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0 bg-transparent", className), ...props })
|
|
393
|
+
);
|
|
394
|
+
TableBody.displayName = "TableBody";
|
|
395
|
+
var TableFooter = React3.forwardRef(
|
|
396
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
397
|
+
"tfoot",
|
|
398
|
+
{
|
|
399
|
+
ref,
|
|
400
|
+
className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className),
|
|
401
|
+
...props
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
);
|
|
405
|
+
TableFooter.displayName = "TableFooter";
|
|
406
|
+
var TableRow = React3.forwardRef(
|
|
407
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
408
|
+
"tr",
|
|
409
|
+
{
|
|
410
|
+
ref,
|
|
411
|
+
className: cn(
|
|
412
|
+
"border-b border-border/60 transition-colors hover:bg-muted/40 data-[state=selected]:bg-muted/30 text-foreground even:bg-muted/20",
|
|
413
|
+
className
|
|
414
|
+
),
|
|
415
|
+
...props
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
);
|
|
419
|
+
TableRow.displayName = "TableRow";
|
|
420
|
+
var TableHead = React3.forwardRef(
|
|
421
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
422
|
+
"th",
|
|
423
|
+
{
|
|
424
|
+
ref,
|
|
425
|
+
className: cn(
|
|
426
|
+
"h-9 px-4 text-left align-middle font-medium text-muted-foreground dark:text-slate-300 uppercase text-[10px] tracking-wide border-r border-border/50 dark:border-slate-600/70 last:border-r-0 [&:has([role=checkbox])]:pr-0",
|
|
427
|
+
className
|
|
428
|
+
),
|
|
429
|
+
...props
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
);
|
|
433
|
+
TableHead.displayName = "TableHead";
|
|
434
|
+
var TableCell = React3.forwardRef(
|
|
435
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
436
|
+
"td",
|
|
437
|
+
{
|
|
438
|
+
ref,
|
|
439
|
+
className: cn("px-4 py-1.5 align-middle [&:has([role=checkbox])]:pr-0 text-foreground/90 text-xs", className),
|
|
440
|
+
...props
|
|
441
|
+
}
|
|
442
|
+
)
|
|
443
|
+
);
|
|
444
|
+
TableCell.displayName = "TableCell";
|
|
445
|
+
var TableCaption = React3.forwardRef(
|
|
446
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })
|
|
447
|
+
);
|
|
448
|
+
TableCaption.displayName = "TableCaption";
|
|
449
|
+
var Checkbox = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
450
|
+
CheckboxPrimitive.Root,
|
|
451
|
+
{
|
|
452
|
+
ref,
|
|
453
|
+
className: cn(
|
|
454
|
+
"peer h-4 w-4 shrink-0 rounded-sm border border-primary 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 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
|
455
|
+
className
|
|
456
|
+
),
|
|
457
|
+
...props,
|
|
458
|
+
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: cn("flex items-center justify-center text-current"), children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) })
|
|
459
|
+
}
|
|
460
|
+
));
|
|
461
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
462
|
+
var SmartFilterPanel = ({
|
|
463
|
+
filterGroups,
|
|
464
|
+
searchValue = "",
|
|
465
|
+
onSearchChange,
|
|
466
|
+
searchPlaceholder = "Buscar...",
|
|
467
|
+
resultsCount,
|
|
468
|
+
onClearAll,
|
|
469
|
+
defaultExpanded = false,
|
|
470
|
+
persistKey,
|
|
471
|
+
enablePresets = false,
|
|
472
|
+
enableUrlSync = false,
|
|
473
|
+
enableHistory = false,
|
|
474
|
+
maxHistoryItems = 10,
|
|
475
|
+
onFiltersChange
|
|
476
|
+
}) => {
|
|
477
|
+
const [showFilters, setShowFilters] = useState(() => {
|
|
478
|
+
if (!persistKey) return defaultExpanded;
|
|
479
|
+
const saved = localStorage.getItem(`showFilters_${persistKey}`);
|
|
480
|
+
return saved !== null ? saved === "true" : defaultExpanded;
|
|
481
|
+
});
|
|
482
|
+
const [presets, setPresets] = useState([]);
|
|
483
|
+
const [showPresets, setShowPresets] = useState(false);
|
|
484
|
+
const [history, setHistory] = useState([]);
|
|
485
|
+
const [showHistory, setShowHistory] = useState(false);
|
|
486
|
+
const [showSavePresetModal, setShowSavePresetModal] = useState(false);
|
|
487
|
+
const [presetName, setPresetName] = useState("");
|
|
488
|
+
const [localSearch, setLocalSearch] = useState(searchValue);
|
|
489
|
+
const debounceRef = useRef(null);
|
|
490
|
+
useEffect(() => {
|
|
491
|
+
if (searchValue === "") setLocalSearch("");
|
|
492
|
+
}, [searchValue]);
|
|
493
|
+
const activeFiltersCount = useMemo(
|
|
494
|
+
() => filterGroups.filter((g) => g.selectedValues.length > 0).length + (searchValue ? 1 : 0),
|
|
495
|
+
[filterGroups, searchValue]
|
|
496
|
+
);
|
|
497
|
+
const hasActiveFilters = activeFiltersCount > 0;
|
|
498
|
+
const currentFiltersState = useMemo(
|
|
499
|
+
() => filterGroups.reduce((acc, group) => {
|
|
500
|
+
acc[group.key] = group.selectedValues;
|
|
501
|
+
return acc;
|
|
502
|
+
}, {}),
|
|
503
|
+
[filterGroups]
|
|
504
|
+
);
|
|
505
|
+
useEffect(() => {
|
|
506
|
+
if (!persistKey) return;
|
|
507
|
+
const saved = localStorage.getItem(`filters_${persistKey}`);
|
|
508
|
+
if (saved) {
|
|
509
|
+
try {
|
|
510
|
+
const parsed = JSON.parse(saved);
|
|
511
|
+
Object.entries(parsed).forEach(([key, values]) => {
|
|
512
|
+
const group = filterGroups.find((g) => g.key === key);
|
|
513
|
+
if (group) group.onChange(values);
|
|
514
|
+
});
|
|
515
|
+
} catch (e) {
|
|
516
|
+
console.error("Erro ao carregar filtros:", e);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (enablePresets) {
|
|
520
|
+
const savedPresets = localStorage.getItem(`presets_${persistKey}`);
|
|
521
|
+
if (savedPresets) {
|
|
522
|
+
try {
|
|
523
|
+
setPresets(JSON.parse(savedPresets));
|
|
524
|
+
} catch (e) {
|
|
525
|
+
console.error(e);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (enableHistory) {
|
|
530
|
+
const savedHistory = localStorage.getItem(`history_${persistKey}`);
|
|
531
|
+
if (savedHistory) {
|
|
532
|
+
try {
|
|
533
|
+
setHistory(JSON.parse(savedHistory));
|
|
534
|
+
} catch (e) {
|
|
535
|
+
console.error(e);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}, [persistKey]);
|
|
540
|
+
useEffect(() => {
|
|
541
|
+
if (!persistKey) return;
|
|
542
|
+
localStorage.setItem(`filters_${persistKey}`, JSON.stringify(currentFiltersState));
|
|
543
|
+
onFiltersChange?.(currentFiltersState);
|
|
544
|
+
}, [currentFiltersState, persistKey, onFiltersChange]);
|
|
545
|
+
useEffect(() => {
|
|
546
|
+
if (!enableUrlSync) return;
|
|
547
|
+
const params = new URLSearchParams(window.location.search);
|
|
548
|
+
Object.entries(currentFiltersState).forEach(([key, values]) => {
|
|
549
|
+
if (values.length > 0) params.set(key, values.join(","));
|
|
550
|
+
else params.delete(key);
|
|
551
|
+
});
|
|
552
|
+
if (searchValue) params.set("search", searchValue);
|
|
553
|
+
else params.delete("search");
|
|
554
|
+
window.history.replaceState({}, "", `${window.location.pathname}?${params.toString()}`);
|
|
555
|
+
}, [currentFiltersState, searchValue, enableUrlSync]);
|
|
556
|
+
const handleClearAll = useCallback(() => {
|
|
557
|
+
filterGroups.forEach((group) => group.onChange([]));
|
|
558
|
+
onSearchChange?.("");
|
|
559
|
+
onClearAll?.();
|
|
560
|
+
}, [filterGroups, onSearchChange, onClearAll]);
|
|
561
|
+
const toggleOption = useCallback((group, value) => {
|
|
562
|
+
if (group.selectedValues.includes(value)) group.onChange(group.selectedValues.filter((v) => v !== value));
|
|
563
|
+
else group.onChange([...group.selectedValues, value]);
|
|
564
|
+
}, []);
|
|
565
|
+
const toggleAll = useCallback((group) => {
|
|
566
|
+
const allValues = group.options.map((o) => o.value);
|
|
567
|
+
if (group.selectedValues.length === allValues.length) group.onChange([]);
|
|
568
|
+
else group.onChange(allValues);
|
|
569
|
+
}, []);
|
|
570
|
+
const confirmSavePreset = useCallback(() => {
|
|
571
|
+
if (!presetName.trim()) return;
|
|
572
|
+
const newPreset = { id: Date.now().toString(), name: presetName.trim(), filters: currentFiltersState, searchValue, createdAt: /* @__PURE__ */ new Date() };
|
|
573
|
+
const updated = [...presets, newPreset];
|
|
574
|
+
setPresets(updated);
|
|
575
|
+
if (persistKey) localStorage.setItem(`presets_${persistKey}`, JSON.stringify(updated));
|
|
576
|
+
setPresetName("");
|
|
577
|
+
setShowSavePresetModal(false);
|
|
578
|
+
}, [presets, currentFiltersState, searchValue, persistKey, presetName]);
|
|
579
|
+
const loadPreset = useCallback((preset) => {
|
|
580
|
+
Object.entries(preset.filters).forEach(([key, values]) => {
|
|
581
|
+
const group = filterGroups.find((g) => g.key === key);
|
|
582
|
+
if (group) group.onChange(values);
|
|
583
|
+
});
|
|
584
|
+
if (preset.searchValue) onSearchChange?.(preset.searchValue);
|
|
585
|
+
setShowPresets(false);
|
|
586
|
+
setShowHistory(false);
|
|
587
|
+
}, [filterGroups, onSearchChange]);
|
|
588
|
+
const deletePreset = useCallback((id) => {
|
|
589
|
+
const updated = presets.filter((p) => p.id !== id);
|
|
590
|
+
setPresets(updated);
|
|
591
|
+
if (persistKey) localStorage.setItem(`presets_${persistKey}`, JSON.stringify(updated));
|
|
592
|
+
}, [presets, persistKey]);
|
|
593
|
+
const addToHistory = useCallback(() => {
|
|
594
|
+
if (!enableHistory || !hasActiveFilters) return;
|
|
595
|
+
const newEntry = { id: Date.now().toString(), name: `Filtro ${(/* @__PURE__ */ new Date()).toLocaleString()}`, filters: currentFiltersState, searchValue, createdAt: /* @__PURE__ */ new Date() };
|
|
596
|
+
const updated = [newEntry, ...history].slice(0, maxHistoryItems);
|
|
597
|
+
setHistory(updated);
|
|
598
|
+
if (persistKey) localStorage.setItem(`history_${persistKey}`, JSON.stringify(updated));
|
|
599
|
+
}, [enableHistory, hasActiveFilters, currentFiltersState, searchValue, history, maxHistoryItems, persistKey]);
|
|
600
|
+
useEffect(() => {
|
|
601
|
+
if (hasActiveFilters) {
|
|
602
|
+
const timer = setTimeout(addToHistory, 2e3);
|
|
603
|
+
return () => clearTimeout(timer);
|
|
604
|
+
}
|
|
605
|
+
}, [hasActiveFilters, addToHistory]);
|
|
606
|
+
const exportFilters = useCallback(() => {
|
|
607
|
+
const data = { filters: currentFiltersState, searchValue, exportedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
608
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
|
|
609
|
+
const url = URL.createObjectURL(blob);
|
|
610
|
+
const a = document.createElement("a");
|
|
611
|
+
a.href = url;
|
|
612
|
+
a.download = `filters_${persistKey || "export"}_${Date.now()}.json`;
|
|
613
|
+
a.click();
|
|
614
|
+
URL.revokeObjectURL(url);
|
|
615
|
+
}, [currentFiltersState, searchValue, persistKey]);
|
|
616
|
+
const importFilters = useCallback(() => {
|
|
617
|
+
const input = document.createElement("input");
|
|
618
|
+
input.type = "file";
|
|
619
|
+
input.accept = "application/json";
|
|
620
|
+
input.onchange = (e) => {
|
|
621
|
+
const file = e.target.files?.[0];
|
|
622
|
+
if (!file) return;
|
|
623
|
+
const reader = new FileReader();
|
|
624
|
+
reader.onload = (e2) => {
|
|
625
|
+
try {
|
|
626
|
+
const data = JSON.parse(e2.target?.result);
|
|
627
|
+
Object.entries(data.filters).forEach(([key, values]) => {
|
|
628
|
+
const group = filterGroups.find((g) => g.key === key);
|
|
629
|
+
if (group) group.onChange(values);
|
|
630
|
+
});
|
|
631
|
+
if (data.searchValue) onSearchChange?.(data.searchValue);
|
|
632
|
+
} catch {
|
|
633
|
+
alert("Erro ao importar filtros");
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
reader.readAsText(file);
|
|
637
|
+
};
|
|
638
|
+
input.click();
|
|
639
|
+
}, [filterGroups, onSearchChange]);
|
|
640
|
+
const defaultAllColor = { bg: "bg-slate-100", text: "text-slate-800", border: "border-slate-300", darkBg: "dark:bg-slate-900/30", darkText: "dark:text-slate-300", darkBorder: "dark:border-slate-800" };
|
|
641
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
642
|
+
/* @__PURE__ */ jsx(Card, { className: "border-border/30 shadow-xl", children: /* @__PURE__ */ jsxs(CardContent, { className: `transition-all ${showFilters ? "p-3" : "p-2.5"}`, children: [
|
|
643
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
644
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
645
|
+
/* @__PURE__ */ jsx("div", { className: "p-1 bg-primary/10 rounded", children: /* @__PURE__ */ jsx(Filter, { className: "w-3 h-3 text-primary" }) }),
|
|
646
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Filtros" }),
|
|
647
|
+
hasActiveFilters && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "bg-primary/10 text-primary border-primary/20", children: [
|
|
648
|
+
activeFiltersCount,
|
|
649
|
+
" ativo",
|
|
650
|
+
activeFiltersCount > 1 ? "s" : ""
|
|
651
|
+
] })
|
|
652
|
+
] }),
|
|
653
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
654
|
+
enablePresets && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowPresets(!showPresets), title: "Presets", disabled: !showFilters, children: /* @__PURE__ */ jsx(Bookmark, { className: "w-4 h-4" }) }),
|
|
655
|
+
enableHistory && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowHistory(!showHistory), title: "Hist\xF3rico", disabled: !showFilters, children: /* @__PURE__ */ jsx(History, { className: "w-4 h-4" }) }),
|
|
656
|
+
persistKey && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
657
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: exportFilters, title: "Exportar", disabled: !showFilters, children: /* @__PURE__ */ jsx(Download, { className: "w-4 h-4" }) }),
|
|
658
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: importFilters, title: "Importar", disabled: !showFilters, children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4" }) })
|
|
659
|
+
] }),
|
|
660
|
+
enablePresets && hasActiveFilters && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setShowSavePresetModal(true), title: "Salvar Preset", disabled: !showFilters, children: /* @__PURE__ */ jsx(Save, { className: "w-4 h-4" }) }),
|
|
661
|
+
hasActiveFilters && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleClearAll, children: [
|
|
662
|
+
/* @__PURE__ */ jsx(XCircle, { className: "w-4 h-4 mr-2" }),
|
|
663
|
+
"Limpar"
|
|
664
|
+
] }),
|
|
665
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
666
|
+
const next = !showFilters;
|
|
667
|
+
setShowFilters(next);
|
|
668
|
+
if (persistKey) localStorage.setItem(`showFilters_${persistKey}`, String(next));
|
|
669
|
+
}, children: showFilters ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4" }) })
|
|
670
|
+
] })
|
|
671
|
+
] }),
|
|
672
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showPresets && presets.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "mt-3 p-3 bg-muted/30 rounded-lg border", children: [
|
|
673
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-semibold mb-2", children: "Presets Salvos" }),
|
|
674
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1 bg-background rounded border", children: [
|
|
675
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => loadPreset(preset), className: "h-6 px-2", children: preset.name }),
|
|
676
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => deletePreset(preset.id), className: "h-6 w-6 p-0", children: /* @__PURE__ */ jsx(XCircle, { className: "w-3 h-3" }) })
|
|
677
|
+
] }, preset.id)) })
|
|
678
|
+
] }) }),
|
|
679
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showHistory && history.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "mt-3 p-3 bg-muted/30 rounded-lg border", children: [
|
|
680
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-semibold mb-2", children: "Hist\xF3rico Recente" }),
|
|
681
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1", children: history.map((entry) => /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => loadPreset(entry), className: "w-full justify-start h-8 text-xs", children: [
|
|
682
|
+
/* @__PURE__ */ jsx(History, { className: "w-3 h-3 mr-2" }),
|
|
683
|
+
entry.name
|
|
684
|
+
] }, entry.id)) })
|
|
685
|
+
] }) }),
|
|
686
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showFilters && /* @__PURE__ */ jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, transition: { duration: 0.3 }, style: { overflow: "visible" }, children: /* @__PURE__ */ jsxs("div", { className: "space-y-3 mt-3", children: [
|
|
687
|
+
onSearchChange && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
688
|
+
/* @__PURE__ */ jsx("span", { className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground text-xs pointer-events-none", children: "\u{1F50D}" }),
|
|
689
|
+
/* @__PURE__ */ jsx(
|
|
690
|
+
"input",
|
|
691
|
+
{
|
|
692
|
+
type: "text",
|
|
693
|
+
placeholder: searchPlaceholder,
|
|
694
|
+
value: localSearch,
|
|
695
|
+
onChange: (e) => {
|
|
696
|
+
const val = e.target.value;
|
|
697
|
+
setLocalSearch(val);
|
|
698
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
699
|
+
debounceRef.current = setTimeout(() => onSearchChange(val), 900);
|
|
700
|
+
},
|
|
701
|
+
className: "w-full pl-8 pr-3 h-8 text-xs py-1.5 border border-input rounded-md bg-slate-900/50 dark:bg-slate-950/50 text-foreground focus:outline-none focus:border-primary/50"
|
|
702
|
+
}
|
|
703
|
+
)
|
|
704
|
+
] }),
|
|
705
|
+
filterGroups.map((group) => {
|
|
706
|
+
const allValues = group.options.map((o) => o.value);
|
|
707
|
+
const allSelected = group.selectedValues.length === allValues.length;
|
|
708
|
+
const allColor = group.allColor || defaultAllColor;
|
|
709
|
+
if (group.renderType === "select") {
|
|
710
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
711
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: group.label }),
|
|
712
|
+
/* @__PURE__ */ jsx(
|
|
713
|
+
"select",
|
|
714
|
+
{
|
|
715
|
+
value: group.selectedValues[0] || "",
|
|
716
|
+
onChange: (e) => group.onChange(e.target.value ? [e.target.value] : []),
|
|
717
|
+
className: "w-full px-3 py-2 text-sm border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring",
|
|
718
|
+
children: group.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
|
|
719
|
+
}
|
|
720
|
+
)
|
|
721
|
+
] }, group.key);
|
|
722
|
+
}
|
|
723
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
724
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: group.label }),
|
|
725
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
726
|
+
group.allLabel && /* @__PURE__ */ jsxs(
|
|
727
|
+
Button,
|
|
728
|
+
{
|
|
729
|
+
variant: "outline",
|
|
730
|
+
size: "sm",
|
|
731
|
+
onClick: () => toggleAll(group),
|
|
732
|
+
className: `rounded-full ${allColor.bg} ${allColor.text} ${allColor.darkBg} ${allColor.darkText} ${allSelected ? `${allColor.border} ${allColor.darkBorder}` : "border-transparent"}`,
|
|
733
|
+
children: [
|
|
734
|
+
group.allLabel,
|
|
735
|
+
" ",
|
|
736
|
+
allSelected && "\u2713"
|
|
737
|
+
]
|
|
738
|
+
}
|
|
739
|
+
),
|
|
740
|
+
group.options.map((option) => {
|
|
741
|
+
const isSelected = group.selectedValues.includes(option.value);
|
|
742
|
+
return /* @__PURE__ */ jsxs(
|
|
743
|
+
Button,
|
|
744
|
+
{
|
|
745
|
+
variant: "outline",
|
|
746
|
+
size: "sm",
|
|
747
|
+
onClick: () => toggleOption(group, option.value),
|
|
748
|
+
className: `rounded-full ${option.color.bg} ${option.color.text} ${option.color.darkBg} ${option.color.darkText} ${isSelected ? `${option.color.border} ${option.color.darkBorder}` : "border-transparent"}`,
|
|
749
|
+
children: [
|
|
750
|
+
option.emoji && `${option.emoji} `,
|
|
751
|
+
option.label
|
|
752
|
+
]
|
|
753
|
+
},
|
|
754
|
+
option.value
|
|
755
|
+
);
|
|
756
|
+
})
|
|
757
|
+
] })
|
|
758
|
+
] }, group.key);
|
|
759
|
+
}),
|
|
760
|
+
resultsCount !== void 0 && /* @__PURE__ */ jsx("div", { className: "pt-2 border-t", children: /* @__PURE__ */ jsxs(Badge, { className: "px-3 py-1.5 bg-primary/10 text-primary border-primary/20", children: [
|
|
761
|
+
/* @__PURE__ */ jsx(Activity, { className: "w-3.5 h-3.5 mr-1.5" }),
|
|
762
|
+
resultsCount,
|
|
763
|
+
" resultado",
|
|
764
|
+
resultsCount !== 1 ? "s" : ""
|
|
765
|
+
] }) })
|
|
766
|
+
] }) }) })
|
|
767
|
+
] }) }),
|
|
768
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showSavePresetModal && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, className: "fixed inset-0 bg-black/50 flex items-center justify-center z-[9999]", onClick: () => setShowSavePresetModal(false), children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.9, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.9, opacity: 0 }, onClick: (e) => e.stopPropagation(), className: "bg-background border rounded-lg p-6 w-96 shadow-2xl", children: [
|
|
769
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-bold mb-4", children: "Salvar Preset" }),
|
|
770
|
+
/* @__PURE__ */ jsx(
|
|
771
|
+
"input",
|
|
772
|
+
{
|
|
773
|
+
type: "text",
|
|
774
|
+
placeholder: "Nome do preset",
|
|
775
|
+
value: presetName,
|
|
776
|
+
onChange: (e) => setPresetName(e.target.value),
|
|
777
|
+
onKeyDown: (e) => e.key === "Enter" && confirmSavePreset(),
|
|
778
|
+
className: "w-full px-3 py-2 border border-input rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring mb-4",
|
|
779
|
+
autoFocus: true
|
|
780
|
+
}
|
|
781
|
+
),
|
|
782
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-end", children: [
|
|
783
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
784
|
+
setShowSavePresetModal(false);
|
|
785
|
+
setPresetName("");
|
|
786
|
+
}, children: "Cancelar" }),
|
|
787
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", onClick: confirmSavePreset, disabled: !presetName.trim(), children: "Salvar" })
|
|
788
|
+
] })
|
|
789
|
+
] }) }) })
|
|
790
|
+
] });
|
|
791
|
+
};
|
|
792
|
+
var SmartFilterPanel_default = SmartFilterPanel;
|
|
793
|
+
function DataTable({
|
|
794
|
+
data = [],
|
|
795
|
+
columns,
|
|
796
|
+
title,
|
|
797
|
+
subtitle,
|
|
798
|
+
icon: Icon,
|
|
799
|
+
loading = false,
|
|
800
|
+
total = 0,
|
|
801
|
+
page = 1,
|
|
802
|
+
pageSize = 25,
|
|
803
|
+
onPageChange,
|
|
804
|
+
onPageSizeChange,
|
|
805
|
+
search = "",
|
|
806
|
+
onSearchChange,
|
|
807
|
+
filters = [],
|
|
808
|
+
actions = [],
|
|
809
|
+
selectable = false,
|
|
810
|
+
selectedItems = [],
|
|
811
|
+
onSelectionChange,
|
|
812
|
+
onBulkDelete,
|
|
813
|
+
bulkDeleteLabel = "Excluir selecionados",
|
|
814
|
+
onRefresh,
|
|
815
|
+
onExport,
|
|
816
|
+
emptyMessage = "Nenhum registro encontrado",
|
|
817
|
+
emptyIcon: EmptyIcon,
|
|
818
|
+
stats = [],
|
|
819
|
+
enablePagination = true,
|
|
820
|
+
customActions,
|
|
821
|
+
sortBy,
|
|
822
|
+
sortOrder,
|
|
823
|
+
onSort,
|
|
824
|
+
hideHeader = false,
|
|
825
|
+
searchDebounce = true,
|
|
826
|
+
tableBodyHeight,
|
|
827
|
+
fillHeight = true,
|
|
828
|
+
onRowClick,
|
|
829
|
+
renderDrawer
|
|
830
|
+
}) {
|
|
831
|
+
const [drawerItem, setDrawerItem] = useState(null);
|
|
832
|
+
const [showBulkDeleteConfirm, setShowBulkDeleteConfirm] = useState(false);
|
|
833
|
+
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
834
|
+
const [searchInput, setSearchInput] = useState(search);
|
|
835
|
+
const handleRowClick = (item) => {
|
|
836
|
+
if (renderDrawer) {
|
|
837
|
+
setDrawerItem(item);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
onRowClick?.(item);
|
|
841
|
+
};
|
|
842
|
+
React3__default.useEffect(() => {
|
|
843
|
+
setSearchInput(search);
|
|
844
|
+
}, [search]);
|
|
845
|
+
React3__default.useEffect(() => {
|
|
846
|
+
if (!searchDebounce) return;
|
|
847
|
+
const timer = setTimeout(() => {
|
|
848
|
+
if (onSearchChange && searchInput !== search) onSearchChange(searchInput);
|
|
849
|
+
}, 600);
|
|
850
|
+
return () => clearTimeout(timer);
|
|
851
|
+
}, [searchInput, searchDebounce]);
|
|
852
|
+
const handleSearchChange = (value) => {
|
|
853
|
+
if (searchDebounce) setSearchInput(value);
|
|
854
|
+
else onSearchChange?.(value);
|
|
855
|
+
};
|
|
856
|
+
const toggleSelectAll = () => {
|
|
857
|
+
const currentPageIds = data.map((item) => item.id);
|
|
858
|
+
const allCurrentSelected = currentPageIds.every((id) => selectedItems.includes(id));
|
|
859
|
+
if (allCurrentSelected) onSelectionChange?.(selectedItems.filter((id) => !currentPageIds.includes(id)));
|
|
860
|
+
else onSelectionChange?.([.../* @__PURE__ */ new Set([...selectedItems, ...currentPageIds])]);
|
|
861
|
+
};
|
|
862
|
+
const toggleSelectItem = (itemId) => {
|
|
863
|
+
if (selectedItems.includes(itemId)) onSelectionChange?.(selectedItems.filter((id) => id !== itemId));
|
|
864
|
+
else onSelectionChange?.([...selectedItems, itemId]);
|
|
865
|
+
};
|
|
866
|
+
if (loading) {
|
|
867
|
+
return /* @__PURE__ */ jsx("div", { className: "min-h-96 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
868
|
+
/* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-16 w-16 border-b-2 border-primary mx-auto mb-4" }),
|
|
869
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Carregando dados..." })
|
|
870
|
+
] }) });
|
|
871
|
+
}
|
|
872
|
+
const handleBulkDelete = () => {
|
|
873
|
+
if (onBulkDelete && selectedItems.length > 0) {
|
|
874
|
+
onBulkDelete(selectedItems);
|
|
875
|
+
setShowBulkDeleteConfirm(false);
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
return /* @__PURE__ */ jsxs("div", { className: fillHeight ? "flex flex-col h-full gap-4" : "space-y-4", children: [
|
|
879
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: selectable && selectedItems.length > 0 && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 20 }, className: "fixed bottom-6 left-1/2 -translate-x-1/2 z-50", children: /* @__PURE__ */ jsxs("div", { className: "bg-gradient-to-r from-slate-900 to-slate-800 dark:from-slate-800 dark:to-slate-900 text-white rounded-full shadow-2xl px-6 py-4 flex items-center gap-4 border border-slate-700", children: [
|
|
880
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
881
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-primary", children: selectedItems.length }) }),
|
|
882
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: selectedItems.length === 1 ? "1 item selecionado" : `${selectedItems.length} itens selecionados` })
|
|
883
|
+
] }),
|
|
884
|
+
/* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-slate-600" }),
|
|
885
|
+
onBulkDelete && /* @__PURE__ */ jsxs(Button, { onClick: () => setShowBulkDeleteConfirm(true), variant: "ghost", size: "sm", className: "text-red-400 hover:text-red-300 hover:bg-red-500/10 gap-2", children: [
|
|
886
|
+
/* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
|
|
887
|
+
bulkDeleteLabel
|
|
888
|
+
] }),
|
|
889
|
+
/* @__PURE__ */ jsxs(Button, { onClick: () => onSelectionChange?.([]), variant: "ghost", size: "sm", className: "text-slate-400 hover:text-slate-300 hover:bg-slate-700 gap-2", children: [
|
|
890
|
+
/* @__PURE__ */ jsx(X, { className: "w-4 h-4" }),
|
|
891
|
+
"Cancelar"
|
|
892
|
+
] })
|
|
893
|
+
] }) }) }),
|
|
894
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showBulkDeleteConfirm && /* @__PURE__ */ jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, className: "fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4", onClick: () => setShowBulkDeleteConfirm(false), children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.95, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.95, opacity: 0 }, onClick: (e) => e.stopPropagation(), className: "bg-background rounded-lg shadow-xl max-w-md w-full p-6 space-y-4", children: [
|
|
895
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
896
|
+
/* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center", children: /* @__PURE__ */ jsx(Trash2, { className: "w-6 h-6 text-red-600 dark:text-red-400" }) }),
|
|
897
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
898
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: "Confirmar Exclus\xE3o" }),
|
|
899
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
|
|
900
|
+
"Tem certeza que deseja excluir ",
|
|
901
|
+
selectedItems.length,
|
|
902
|
+
" ",
|
|
903
|
+
selectedItems.length === 1 ? "item" : "itens",
|
|
904
|
+
"?"
|
|
905
|
+
] })
|
|
906
|
+
] })
|
|
907
|
+
] }),
|
|
908
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Esta a\xE7\xE3o n\xE3o pode ser desfeita." }),
|
|
909
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-end", children: [
|
|
910
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setShowBulkDeleteConfirm(false), children: "Cancelar" }),
|
|
911
|
+
/* @__PURE__ */ jsxs(Button, { variant: "destructive", onClick: handleBulkDelete, className: "bg-red-600 hover:bg-red-700", children: [
|
|
912
|
+
/* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4 mr-2" }),
|
|
913
|
+
"Excluir ",
|
|
914
|
+
selectedItems.length,
|
|
915
|
+
" ",
|
|
916
|
+
selectedItems.length === 1 ? "item" : "itens"
|
|
917
|
+
] })
|
|
918
|
+
] })
|
|
919
|
+
] }) }) }),
|
|
920
|
+
!hideHeader && title && /* @__PURE__ */ jsx(
|
|
921
|
+
PageHeader,
|
|
922
|
+
{
|
|
923
|
+
title,
|
|
924
|
+
subtitle,
|
|
925
|
+
icon: Icon,
|
|
926
|
+
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
927
|
+
onRefresh && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => {
|
|
928
|
+
setIsRefreshing(true);
|
|
929
|
+
onRefresh();
|
|
930
|
+
setTimeout(() => setIsRefreshing(false), 500);
|
|
931
|
+
}, children: [
|
|
932
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `w-4 h-4 mr-2 transition-transform ${isRefreshing ? "animate-[spin_0.5s_ease-in-out]" : ""}` }),
|
|
933
|
+
"Atualizar"
|
|
934
|
+
] }),
|
|
935
|
+
onExport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onExport, children: [
|
|
936
|
+
/* @__PURE__ */ jsx(Download, { className: "w-4 h-4 mr-2" }),
|
|
937
|
+
"Exportar"
|
|
938
|
+
] })
|
|
939
|
+
] })
|
|
940
|
+
}
|
|
941
|
+
),
|
|
942
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid grid-cols-2 md:grid-cols-3 lg:grid-cols-${Math.min(stats.length, 6)} gap-4`, children: stats.map((stat, index) => /* @__PURE__ */ jsx(StatCard, { ...stat, variant: stat.variant || "slim" }, stat.label || index)) }),
|
|
943
|
+
(onSearchChange || filters.length > 0) && /* @__PURE__ */ jsx(
|
|
944
|
+
SmartFilterPanel_default,
|
|
945
|
+
{
|
|
946
|
+
filterGroups: filters.map((f) => ({
|
|
947
|
+
key: f.key,
|
|
948
|
+
label: f.label,
|
|
949
|
+
renderType: f.type === "select" ? "select" : "badges",
|
|
950
|
+
options: f.options?.map((opt) => {
|
|
951
|
+
const colorClasses = opt.color?.split(" ") || [];
|
|
952
|
+
const bgClass = colorClasses.find((c) => c.startsWith("bg-")) || "bg-slate-100";
|
|
953
|
+
const textClass = colorClasses.find((c) => c.startsWith("text-")) || "text-slate-800";
|
|
954
|
+
const borderClass = colorClasses.find((c) => c.startsWith("border-") && !c.includes("dark:")) || "border-slate-300";
|
|
955
|
+
const darkBgClass = colorClasses.find((c) => c.startsWith("dark:bg-")) || "dark:bg-slate-900/30";
|
|
956
|
+
const darkTextClass = colorClasses.find((c) => c.startsWith("dark:text-")) || "dark:text-slate-300";
|
|
957
|
+
const darkBorderClass = colorClasses.find((c) => c.startsWith("dark:border-")) || "dark:border-slate-800";
|
|
958
|
+
return { value: opt.value, label: opt.label, color: { bg: bgClass, text: textClass, border: borderClass, darkBg: darkBgClass, darkText: darkTextClass, darkBorder: darkBorderClass } };
|
|
959
|
+
}) || [],
|
|
960
|
+
selectedValues: Array.isArray(f.value) ? f.value : f.value ? [f.value] : [],
|
|
961
|
+
onChange: (values) => f.onChange(f.type === "select" ? values[0] || "" : values),
|
|
962
|
+
allLabel: f.type === "multiselect" ? "Todos" : void 0
|
|
963
|
+
})),
|
|
964
|
+
searchValue: searchDebounce ? searchInput : search,
|
|
965
|
+
onSearchChange: handleSearchChange,
|
|
966
|
+
searchPlaceholder: "Buscar...",
|
|
967
|
+
persistKey: title ? title.toLowerCase().replace(/\s+/g, "-") : "datatable"
|
|
968
|
+
}
|
|
969
|
+
),
|
|
970
|
+
/* @__PURE__ */ jsxs(Card, { className: `shadow-lg ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
|
|
971
|
+
(title || customActions || selectable && selectedItems.length > 0) && /* @__PURE__ */ jsx(CardHeader, { className: `py-2 px-4 ${fillHeight ? "shrink-0" : ""}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
972
|
+
/* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-sm font-semibold", children: [
|
|
973
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
|
|
974
|
+
title,
|
|
975
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary border-primary/20 text-[11px]", children: total || data.length })
|
|
976
|
+
] }),
|
|
977
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
978
|
+
customActions,
|
|
979
|
+
selectable && selectedItems.length > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "bg-blue-50 text-blue-700 border-blue-200 text-[11px]", children: [
|
|
980
|
+
selectedItems.length,
|
|
981
|
+
" selecionado",
|
|
982
|
+
selectedItems.length > 1 ? "s" : ""
|
|
983
|
+
] })
|
|
984
|
+
] })
|
|
985
|
+
] }) }),
|
|
986
|
+
/* @__PURE__ */ jsxs(CardContent, { className: `p-0 overflow-hidden ${fillHeight ? "flex flex-col flex-1 min-h-0" : ""}`, children: [
|
|
987
|
+
/* @__PURE__ */ jsx("div", { className: `overflow-x-auto ${fillHeight ? "flex-1 min-h-0 overflow-y-auto" : ""}`, children: /* @__PURE__ */ jsx("div", { className: "w-full", style: tableBodyHeight ? { height: tableBodyHeight, overflowY: "auto" } : {}, children: /* @__PURE__ */ jsxs(Table2, { className: "w-full", children: [
|
|
988
|
+
/* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10", children: /* @__PURE__ */ jsxs(TableRow, { className: "bg-muted/50", children: [
|
|
989
|
+
selectable && /* @__PURE__ */ jsx(TableHead, { className: "w-12", children: /* @__PURE__ */ jsx(Checkbox, { checked: data?.length > 0 && data.every((item) => selectedItems.includes(item.id)), onCheckedChange: toggleSelectAll }) }),
|
|
990
|
+
columns.map((column) => /* @__PURE__ */ jsx(
|
|
991
|
+
TableHead,
|
|
992
|
+
{
|
|
993
|
+
className: `${column.width} ${column.sortable && onSort ? "cursor-pointer hover:bg-muted/70 select-none" : ""}`,
|
|
994
|
+
onClick: () => column.sortable && onSort && onSort(String(column.key)),
|
|
995
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
996
|
+
column.label,
|
|
997
|
+
column.sortable && onSort && sortBy === String(column.key) && /* @__PURE__ */ jsx("span", { className: "text-xs", children: sortOrder === "asc" ? "\u2191" : "\u2193" })
|
|
998
|
+
] })
|
|
999
|
+
},
|
|
1000
|
+
String(column.key)
|
|
1001
|
+
)),
|
|
1002
|
+
actions.length > 0 && /* @__PURE__ */ jsx(TableHead, { className: "w-16", children: "A\xE7\xF5es" })
|
|
1003
|
+
] }) }),
|
|
1004
|
+
/* @__PURE__ */ jsx(TableBody, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: data?.map((item, index) => /* @__PURE__ */ jsxs(
|
|
1005
|
+
motion.tr,
|
|
1006
|
+
{
|
|
1007
|
+
initial: { opacity: 0, y: 20 },
|
|
1008
|
+
animate: { opacity: 1, y: 0 },
|
|
1009
|
+
exit: { opacity: 0, y: -20 },
|
|
1010
|
+
transition: { delay: index * 0.05 },
|
|
1011
|
+
className: `hover:bg-muted/30 transition-colors ${onRowClick || renderDrawer ? "cursor-pointer" : ""}`,
|
|
1012
|
+
onClick: () => handleRowClick(item),
|
|
1013
|
+
children: [
|
|
1014
|
+
selectable && /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Checkbox, { checked: selectedItems.includes(item.id), onCheckedChange: () => toggleSelectItem(item.id) }) }),
|
|
1015
|
+
columns.map((column) => /* @__PURE__ */ jsx(TableCell, { onClick: column.key === "actions" ? (e) => e.stopPropagation() : void 0, children: column.render ? column.render(item, index) : String(item[column.key] || "") }, String(column.key))),
|
|
1016
|
+
actions.length > 0 && /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: actions.filter((action) => !action.condition || action.condition(item)).map((action, actionIndex) => {
|
|
1017
|
+
const label = typeof action.label === "function" ? action.label(item) : action.label;
|
|
1018
|
+
const className = typeof action.className === "function" ? action.className(item) : action.className;
|
|
1019
|
+
return /* @__PURE__ */ jsx(Button, { variant: action.variant || "ghost", size: "sm", onClick: () => action.onClick(item), title: label, className, children: /* @__PURE__ */ jsx(action.icon, { className: "w-4 h-4" }) }, actionIndex);
|
|
1020
|
+
}) }) })
|
|
1021
|
+
]
|
|
1022
|
+
},
|
|
1023
|
+
`${item.id}-${index}`
|
|
1024
|
+
)) }) })
|
|
1025
|
+
] }) }) }),
|
|
1026
|
+
(!data || data.length === 0) && /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
|
|
1027
|
+
EmptyIcon && /* @__PURE__ */ jsx(EmptyIcon, { className: "w-10 h-10 text-muted-foreground mx-auto mb-3" }),
|
|
1028
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
|
|
1029
|
+
] })
|
|
1030
|
+
] }),
|
|
1031
|
+
enablePagination && total > 0 && onPageChange && /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-2 px-4 py-2 border-t bg-muted/20", children: [
|
|
1032
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
|
|
1033
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1034
|
+
"Mostrando ",
|
|
1035
|
+
(page - 1) * pageSize + 1,
|
|
1036
|
+
"\u2013",
|
|
1037
|
+
Math.min(page * pageSize, total),
|
|
1038
|
+
" de ",
|
|
1039
|
+
total
|
|
1040
|
+
] }),
|
|
1041
|
+
onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx("span", { children: "Por p\xE1gina:" }),
|
|
1043
|
+
/* @__PURE__ */ jsxs("select", { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), className: "px-1.5 py-0.5 border border-border rounded text-xs bg-background", children: [
|
|
1044
|
+
/* @__PURE__ */ jsx("option", { value: 10, children: "10" }),
|
|
1045
|
+
/* @__PURE__ */ jsx("option", { value: 25, children: "25" }),
|
|
1046
|
+
/* @__PURE__ */ jsx("option", { value: 50, children: "50" }),
|
|
1047
|
+
/* @__PURE__ */ jsx("option", { value: 100, children: "100" })
|
|
1048
|
+
] })
|
|
1049
|
+
] })
|
|
1050
|
+
] }),
|
|
1051
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1052
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(1), disabled: page === 1, className: "hidden sm:flex h-7 text-xs px-2", children: "Primeira" }),
|
|
1053
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(page - 1), disabled: page === 1, className: "h-7 text-xs px-2", children: "\u2039 Anterior" }),
|
|
1054
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: Array.from({ length: Math.min(5, Math.ceil(total / pageSize)) }, (_, i) => {
|
|
1055
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
1056
|
+
let pageNum;
|
|
1057
|
+
if (totalPages <= 5) pageNum = i + 1;
|
|
1058
|
+
else if (page <= 3) pageNum = i + 1;
|
|
1059
|
+
else if (page >= totalPages - 2) pageNum = totalPages - 4 + i;
|
|
1060
|
+
else pageNum = page - 2 + i;
|
|
1061
|
+
return /* @__PURE__ */ jsx(Button, { variant: page === pageNum ? "default" : "outline", size: "sm", onClick: () => onPageChange(pageNum), className: "w-7 h-7 p-0 text-xs", children: pageNum }, pageNum);
|
|
1062
|
+
}) }),
|
|
1063
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(page + 1), disabled: page >= Math.ceil(total / pageSize), className: "h-7 text-xs px-2", children: "Pr\xF3xima \u203A" }),
|
|
1064
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => onPageChange(Math.ceil(total / pageSize)), disabled: page >= Math.ceil(total / pageSize), className: "hidden sm:flex h-7 text-xs px-2", children: "\xDAltima" })
|
|
1065
|
+
] })
|
|
1066
|
+
] })
|
|
1067
|
+
] }),
|
|
1068
|
+
renderDrawer && drawerItem && renderDrawer(drawerItem, () => setDrawerItem(null))
|
|
1069
|
+
] });
|
|
1070
|
+
}
|
|
1071
|
+
var DataTable_default = DataTable;
|
|
1072
|
+
var Toast = ({ message, type, onClose, duration = 4e3, entity, action }) => {
|
|
1073
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
1074
|
+
const [progress, setProgress] = useState(100);
|
|
1075
|
+
const getAutoMessage = () => {
|
|
1076
|
+
if (message) return message;
|
|
1077
|
+
if (!entity || !action) return "Opera\xE7\xE3o realizada";
|
|
1078
|
+
const messages = {
|
|
1079
|
+
created: `${entity} criado com sucesso!`,
|
|
1080
|
+
updated: `${entity} atualizado com sucesso!`,
|
|
1081
|
+
deleted: `${entity} removido com sucesso!`,
|
|
1082
|
+
error: `Erro ao processar ${entity.toLowerCase()}`
|
|
1083
|
+
};
|
|
1084
|
+
return messages[action] || "Opera\xE7\xE3o realizada";
|
|
1085
|
+
};
|
|
1086
|
+
useEffect(() => {
|
|
1087
|
+
setIsVisible(true);
|
|
1088
|
+
const progressInterval = setInterval(() => {
|
|
1089
|
+
setProgress((prev) => Math.max(0, prev - 100 / (duration / 100)));
|
|
1090
|
+
}, 100);
|
|
1091
|
+
const timer = setTimeout(() => {
|
|
1092
|
+
setIsVisible(false);
|
|
1093
|
+
setTimeout(onClose, 300);
|
|
1094
|
+
}, duration);
|
|
1095
|
+
return () => {
|
|
1096
|
+
clearTimeout(timer);
|
|
1097
|
+
clearInterval(progressInterval);
|
|
1098
|
+
};
|
|
1099
|
+
}, [duration, onClose]);
|
|
1100
|
+
const handleClose = () => {
|
|
1101
|
+
setIsVisible(false);
|
|
1102
|
+
setTimeout(onClose, 300);
|
|
1103
|
+
};
|
|
1104
|
+
const config = {
|
|
1105
|
+
success: { bg: "bg-gradient-to-r from-emerald-500 to-green-600", icon: CheckCircle, shadow: "shadow-emerald-500/25" },
|
|
1106
|
+
error: { bg: "bg-gradient-to-r from-red-500 to-rose-600", icon: AlertTriangle, shadow: "shadow-red-500/25" }
|
|
1107
|
+
};
|
|
1108
|
+
const { bg, icon: Icon, shadow } = config[type];
|
|
1109
|
+
return createPortal(
|
|
1110
|
+
/* @__PURE__ */ jsx("div", { className: "fixed top-24 right-6 z-[9999]", children: /* @__PURE__ */ jsxs("div", { className: `${bg} ${shadow} min-w-80 max-w-md p-4 rounded-2xl shadow-2xl backdrop-blur-sm transform transition-all duration-300 ease-out ${isVisible ? "translate-x-0 opacity-100 scale-100" : "translate-x-full opacity-0 scale-95"}`, children: [
|
|
1111
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
1112
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 mt-0.5", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-white/20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4 text-white" }) }) }),
|
|
1113
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-white font-medium text-sm leading-relaxed", children: getAutoMessage() }) }),
|
|
1114
|
+
/* @__PURE__ */ jsx("button", { onClick: handleClose, className: "flex-shrink-0 text-white/70 hover:text-white transition-colors p-1 hover:bg-white/10 rounded-full", children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4" }) })
|
|
1115
|
+
] }),
|
|
1116
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 h-1 bg-white/20 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "h-full bg-white/40 rounded-full transition-all duration-100 ease-linear", style: { width: `${progress}%` } }) })
|
|
1117
|
+
] }) }),
|
|
1118
|
+
document.body
|
|
1119
|
+
);
|
|
1120
|
+
};
|
|
1121
|
+
var Toast_default = Toast;
|
|
1122
|
+
function Dialog({ open, onOpenChange, children }) {
|
|
1123
|
+
useEffect(() => {
|
|
1124
|
+
if (open) {
|
|
1125
|
+
const scrollY = window.scrollY;
|
|
1126
|
+
document.body.style.position = "fixed";
|
|
1127
|
+
document.body.style.top = `-${scrollY}px`;
|
|
1128
|
+
document.body.style.width = "100%";
|
|
1129
|
+
document.body.classList.add("modal-open");
|
|
1130
|
+
} else {
|
|
1131
|
+
const scrollY = document.body.style.top;
|
|
1132
|
+
document.body.style.position = "";
|
|
1133
|
+
document.body.style.top = "";
|
|
1134
|
+
document.body.style.width = "";
|
|
1135
|
+
document.body.classList.remove("modal-open");
|
|
1136
|
+
if (scrollY) {
|
|
1137
|
+
window.scrollTo(0, parseInt(scrollY || "0") * -1);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return () => {
|
|
1141
|
+
document.body.style.position = "";
|
|
1142
|
+
document.body.style.top = "";
|
|
1143
|
+
document.body.style.width = "";
|
|
1144
|
+
document.body.classList.remove("modal-open");
|
|
1145
|
+
};
|
|
1146
|
+
}, [open]);
|
|
1147
|
+
if (!open) return null;
|
|
1148
|
+
const handleBackdropClick = (e) => {
|
|
1149
|
+
if (e.target === e.currentTarget) onOpenChange(false);
|
|
1150
|
+
};
|
|
1151
|
+
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", onClick: handleBackdropClick, children: [
|
|
1152
|
+
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm transition-all duration-300" }),
|
|
1153
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-50 animate-in fade-in-0 zoom-in-95 duration-300", children })
|
|
1154
|
+
] });
|
|
1155
|
+
}
|
|
1156
|
+
var DialogContent = forwardRef(
|
|
1157
|
+
({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
1158
|
+
"div",
|
|
1159
|
+
{
|
|
1160
|
+
ref,
|
|
1161
|
+
className: cn(
|
|
1162
|
+
"bg-card/95 backdrop-blur-none border border-border/50 rounded-2xl shadow-2xl w-full p-0 max-h-[90vh] overflow-y-auto",
|
|
1163
|
+
className
|
|
1164
|
+
),
|
|
1165
|
+
onClick: (e) => e.stopPropagation(),
|
|
1166
|
+
onWheel: (e) => e.stopPropagation(),
|
|
1167
|
+
...props,
|
|
1168
|
+
children
|
|
1169
|
+
}
|
|
1170
|
+
)
|
|
1171
|
+
);
|
|
1172
|
+
DialogContent.displayName = "DialogContent";
|
|
1173
|
+
function DialogHeader({ className, children }) {
|
|
1174
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 p-6 pb-4 border-b border-border/30", className), children });
|
|
1175
|
+
}
|
|
1176
|
+
function DialogTitle({ className, children }) {
|
|
1177
|
+
return /* @__PURE__ */ jsx("h2", { className: cn("text-xl font-semibold text-foreground leading-none tracking-tight", className), children });
|
|
1178
|
+
}
|
|
1179
|
+
function DialogDescription({ children }) {
|
|
1180
|
+
return /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children });
|
|
1181
|
+
}
|
|
1182
|
+
function DialogFooter({ children }) {
|
|
1183
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 p-6 pt-4", children });
|
|
1184
|
+
}
|
|
1185
|
+
function DialogTrigger({ asChild, children, onClick }) {
|
|
1186
|
+
if (asChild) {
|
|
1187
|
+
const child = children;
|
|
1188
|
+
return React3__default.cloneElement(child, {
|
|
1189
|
+
onClick: (e) => {
|
|
1190
|
+
if (child.props.onClick) child.props.onClick(e);
|
|
1191
|
+
if (onClick) onClick();
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
return /* @__PURE__ */ jsx("button", { onClick, children });
|
|
1196
|
+
}
|
|
1197
|
+
var Input = React3.forwardRef(
|
|
1198
|
+
({ className, type, ...props }, ref) => {
|
|
1199
|
+
return /* @__PURE__ */ jsx(
|
|
1200
|
+
"input",
|
|
1201
|
+
{
|
|
1202
|
+
type,
|
|
1203
|
+
className: cn(
|
|
1204
|
+
"flex h-9 w-full rounded-md border border-input bg-[hsl(var(--input-bg))] px-3 py-2 text-xs text-foreground ring-offset-background file:border-0 file:bg-transparent file:text-xs file:font-medium placeholder:text-muted-foreground/50 focus-visible:outline-none focus-visible:border-primary/60 focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 transition-colors duration-150",
|
|
1205
|
+
className
|
|
1206
|
+
),
|
|
1207
|
+
ref,
|
|
1208
|
+
...props
|
|
1209
|
+
}
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
);
|
|
1213
|
+
Input.displayName = "Input";
|
|
1214
|
+
var ConfirmDialog = ({
|
|
1215
|
+
isOpen,
|
|
1216
|
+
onClose,
|
|
1217
|
+
onConfirm,
|
|
1218
|
+
title,
|
|
1219
|
+
message,
|
|
1220
|
+
type = "warning",
|
|
1221
|
+
confirmText,
|
|
1222
|
+
cancelText = "Cancelar",
|
|
1223
|
+
loading = false,
|
|
1224
|
+
requireConfirmation = false,
|
|
1225
|
+
confirmationText = "CONFIRMAR",
|
|
1226
|
+
details = [],
|
|
1227
|
+
impact
|
|
1228
|
+
}) => {
|
|
1229
|
+
const [confirmationInput, setConfirmationInput] = useState("");
|
|
1230
|
+
const [showDetails, setShowDetails] = useState(false);
|
|
1231
|
+
const isConfirmationValid = !requireConfirmation || confirmationInput.toUpperCase() === confirmationText.toUpperCase();
|
|
1232
|
+
const handleClose = () => {
|
|
1233
|
+
setConfirmationInput("");
|
|
1234
|
+
setShowDetails(false);
|
|
1235
|
+
onClose();
|
|
1236
|
+
};
|
|
1237
|
+
const handleConfirm = () => {
|
|
1238
|
+
if (isConfirmationValid) {
|
|
1239
|
+
onConfirm();
|
|
1240
|
+
setConfirmationInput("");
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
const getConfig = () => {
|
|
1244
|
+
switch (type) {
|
|
1245
|
+
case "delete":
|
|
1246
|
+
return { icon: /* @__PURE__ */ jsx(Trash2, { className: "w-6 h-6 text-red-500" }), confirmText: confirmText || "Excluir", confirmVariant: "destructive", bgColor: "bg-gradient-to-br from-red-50 to-red-100 dark:from-red-950/30 dark:to-red-900/20", borderColor: "border-red-200 dark:border-red-800" };
|
|
1247
|
+
case "danger":
|
|
1248
|
+
return { icon: /* @__PURE__ */ jsx(Shield, { className: "w-6 h-6 text-red-600" }), confirmText: confirmText || "Executar", confirmVariant: "destructive", bgColor: "bg-gradient-to-br from-red-100 to-red-200 dark:from-red-950/50 dark:to-red-900/30", borderColor: "border-red-300 dark:border-red-700" };
|
|
1249
|
+
case "edit":
|
|
1250
|
+
return { icon: /* @__PURE__ */ jsx(Edit, { className: "w-6 h-6 text-blue-500" }), confirmText: confirmText || "Confirmar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-950/30 dark:to-blue-900/20", borderColor: "border-blue-200 dark:border-blue-800" };
|
|
1251
|
+
case "create":
|
|
1252
|
+
return { icon: /* @__PURE__ */ jsx(Plus, { className: "w-6 h-6 text-green-500" }), confirmText: confirmText || "Criar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-green-50 to-green-100 dark:from-green-950/30 dark:to-green-900/20", borderColor: "border-green-200 dark:border-green-800" };
|
|
1253
|
+
default:
|
|
1254
|
+
return { icon: /* @__PURE__ */ jsx(AlertTriangle, { className: "w-6 h-6 text-yellow-500" }), confirmText: confirmText || "Confirmar", confirmVariant: "default", bgColor: "bg-gradient-to-br from-yellow-50 to-yellow-100 dark:from-yellow-950/30 dark:to-yellow-900/20", borderColor: "border-yellow-200 dark:border-yellow-800" };
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
const config = getConfig();
|
|
1258
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: onClose, children: /* @__PURE__ */ jsx(DialogContent, { className: "max-w-md mx-auto p-0 overflow-hidden border-0 shadow-2xl", children: /* @__PURE__ */ jsxs(motion.div, { initial: { scale: 0.95, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.95, opacity: 0 }, transition: { duration: 0.2, ease: "easeOut" }, className: "relative", children: [
|
|
1259
|
+
/* @__PURE__ */ jsxs("div", { className: `${config.bgColor} ${config.borderColor} px-6 py-8 text-center relative overflow-hidden`, children: [
|
|
1260
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-white/20 to-transparent" }),
|
|
1261
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-10", children: [
|
|
1262
|
+
/* @__PURE__ */ jsx(motion.div, { initial: { scale: 0 }, animate: { scale: 1 }, transition: { delay: 0.1, type: "spring", stiffness: 200 }, className: "w-16 h-16 mx-auto mb-4 rounded-full bg-white/90 backdrop-blur-sm flex items-center justify-center shadow-lg", children: /* @__PURE__ */ jsx("div", { className: "scale-150", children: config.icon }) }),
|
|
1263
|
+
/* @__PURE__ */ jsx(motion.h2, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.2 }, className: "text-xl font-bold text-gray-900 dark:text-white mb-2 drop-shadow-sm", children: title })
|
|
1264
|
+
] })
|
|
1265
|
+
] }),
|
|
1266
|
+
/* @__PURE__ */ jsxs("div", { className: "px-6 py-6 bg-white dark:bg-gray-900 space-y-4", children: [
|
|
1267
|
+
/* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.3 }, className: "text-center text-gray-700 dark:text-gray-200 leading-relaxed font-medium", children: message.split("\n").map((line, index) => /* @__PURE__ */ jsx("p", { className: index > 0 ? "mt-2" : "", children: line }, index)) }),
|
|
1268
|
+
impact && /* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.4 }, className: "bg-orange-50 dark:bg-orange-950/30 border border-orange-200 dark:border-orange-800 rounded-lg p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1269
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "w-5 h-5 text-orange-500 mt-0.5 flex-shrink-0" }),
|
|
1270
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1271
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium text-orange-800 dark:text-orange-200 mb-1", children: "Impacto da Opera\xE7\xE3o:" }),
|
|
1272
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-orange-700 dark:text-orange-300", children: impact })
|
|
1273
|
+
] })
|
|
1274
|
+
] }) }),
|
|
1275
|
+
details.length > 0 && /* @__PURE__ */ jsxs(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.5 }, className: "space-y-2", children: [
|
|
1276
|
+
/* @__PURE__ */ jsxs("button", { onClick: () => setShowDetails(!showDetails), className: "text-sm text-blue-600 dark:text-blue-400 hover:underline flex items-center gap-1", children: [
|
|
1277
|
+
/* @__PURE__ */ jsx(Database, { className: "w-4 h-4" }),
|
|
1278
|
+
showDetails ? "Ocultar detalhes" : "Ver detalhes"
|
|
1279
|
+
] }),
|
|
1280
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showDetails && /* @__PURE__ */ jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-3 overflow-hidden", children: /* @__PURE__ */ jsx("ul", { className: "text-sm text-gray-600 dark:text-gray-300 space-y-1", children: details.map((detail, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2", children: [
|
|
1281
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400 mt-1", children: "\u2022" }),
|
|
1282
|
+
/* @__PURE__ */ jsx("span", { children: detail })
|
|
1283
|
+
] }, index)) }) }) })
|
|
1284
|
+
] }),
|
|
1285
|
+
requireConfirmation && /* @__PURE__ */ jsx(motion.div, { initial: { y: 10, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.6 }, className: "space-y-3", children: /* @__PURE__ */ jsxs("div", { className: "bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-800 rounded-lg p-4", children: [
|
|
1286
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 mb-2", children: [
|
|
1287
|
+
"Para confirmar, digite: ",
|
|
1288
|
+
/* @__PURE__ */ jsx("code", { className: "bg-red-100 dark:bg-red-900 px-2 py-1 rounded text-red-900 dark:text-red-100", children: confirmationText })
|
|
1289
|
+
] }),
|
|
1290
|
+
/* @__PURE__ */ jsx(Input, { value: confirmationInput, onChange: (e) => setConfirmationInput(e.target.value), placeholder: `Digite "${confirmationText}" para confirmar`, className: `${!isConfirmationValid && confirmationInput ? "border-red-300 focus:border-red-500" : ""}`, disabled: loading })
|
|
1291
|
+
] }) })
|
|
1292
|
+
] }),
|
|
1293
|
+
/* @__PURE__ */ jsxs(motion.div, { initial: { y: 20, opacity: 0 }, animate: { y: 0, opacity: 1 }, transition: { delay: 0.4 }, className: "px-6 py-4 bg-gray-50 dark:bg-gray-800 flex gap-3 justify-center", children: [
|
|
1294
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, disabled: loading, className: "min-w-24", children: cancelText }),
|
|
1295
|
+
/* @__PURE__ */ jsx(Button, { variant: config.confirmVariant, onClick: handleConfirm, disabled: loading || !isConfirmationValid, className: `min-w-24 shadow-lg ${!isConfirmationValid ? "opacity-50 cursor-not-allowed" : ""}`, children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1296
|
+
/* @__PURE__ */ jsx("div", { className: "w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin mr-2" }),
|
|
1297
|
+
"Processando..."
|
|
1298
|
+
] }) : config.confirmText })
|
|
1299
|
+
] }),
|
|
1300
|
+
/* @__PURE__ */ jsx("button", { onClick: handleClose, disabled: loading, className: "absolute top-4 right-4 w-8 h-8 rounded-full bg-white/90 backdrop-blur-sm hover:bg-white transition-colors flex items-center justify-center shadow-md z-20 disabled:opacity-50 disabled:cursor-not-allowed", children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-gray-800" }) })
|
|
1301
|
+
] }) }) }) });
|
|
1302
|
+
};
|
|
1303
|
+
var ConfirmDialog_default = ConfirmDialog;
|
|
1304
|
+
function CardView({
|
|
1305
|
+
queryKey,
|
|
1306
|
+
queryFn,
|
|
1307
|
+
title,
|
|
1308
|
+
subtitle,
|
|
1309
|
+
icon: Icon,
|
|
1310
|
+
hideHeader = false,
|
|
1311
|
+
emptyMessage = "Nenhum registro encontrado",
|
|
1312
|
+
emptyIcon: EmptyIcon,
|
|
1313
|
+
renderCard,
|
|
1314
|
+
onCardClick,
|
|
1315
|
+
selectedItem: externalSelectedItem,
|
|
1316
|
+
onSelectedItemChange,
|
|
1317
|
+
stats,
|
|
1318
|
+
filters,
|
|
1319
|
+
filterFn,
|
|
1320
|
+
activeFilters: externalActiveFilters,
|
|
1321
|
+
onActiveFiltersChange,
|
|
1322
|
+
searchPlaceholder = "Buscar...",
|
|
1323
|
+
searchColumns = [],
|
|
1324
|
+
persistKey,
|
|
1325
|
+
enablePresets,
|
|
1326
|
+
enableHistory,
|
|
1327
|
+
enableUrlSync,
|
|
1328
|
+
onNew,
|
|
1329
|
+
newButtonLabel = "Novo",
|
|
1330
|
+
onExport,
|
|
1331
|
+
renderDrawer,
|
|
1332
|
+
deleteFn,
|
|
1333
|
+
deleteTitle = "Confirmar exclus\xE3o",
|
|
1334
|
+
deleteMessage = () => "Tem certeza que deseja excluir este registro?",
|
|
1335
|
+
renderAdvancedFilters
|
|
1336
|
+
}) {
|
|
1337
|
+
const queryClient = useQueryClient();
|
|
1338
|
+
const [internalSelectedItem, setInternalSelectedItem] = useState(null);
|
|
1339
|
+
const selectedItem = externalSelectedItem !== void 0 ? externalSelectedItem : internalSelectedItem;
|
|
1340
|
+
const setSelectedItem = onSelectedItemChange || setInternalSelectedItem;
|
|
1341
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
1342
|
+
const [internalActiveFilters, setInternalActiveFilters] = useState([]);
|
|
1343
|
+
const activeFilters = externalActiveFilters !== void 0 ? externalActiveFilters : internalActiveFilters;
|
|
1344
|
+
const setActiveFilters = onActiveFiltersChange || setInternalActiveFilters;
|
|
1345
|
+
const [showFilters, setShowFilters] = useState(false);
|
|
1346
|
+
const [deleteItemId, setDeleteItemId] = useState(null);
|
|
1347
|
+
const [toastState, setToastState] = useState(null);
|
|
1348
|
+
const { data: response, isLoading } = useQuery({ queryKey, queryFn });
|
|
1349
|
+
const items = Array.isArray(response) ? response : response?.data || response?.assets || [];
|
|
1350
|
+
const computedStats = typeof stats === "function" ? stats(items) : stats;
|
|
1351
|
+
const computedFilters = typeof filters === "function" ? filters(items) : filters;
|
|
1352
|
+
const deleteMutation = useMutation({
|
|
1353
|
+
mutationFn: (id) => deleteFn(id),
|
|
1354
|
+
onSuccess: () => {
|
|
1355
|
+
queryClient.invalidateQueries({ queryKey });
|
|
1356
|
+
setToastState({ message: "Registro exclu\xEDdo com sucesso", type: "success" });
|
|
1357
|
+
setSelectedItem(null);
|
|
1358
|
+
setDeleteItemId(null);
|
|
1359
|
+
},
|
|
1360
|
+
onError: (error) => {
|
|
1361
|
+
setToastState({ message: error.response?.data?.message || "N\xE3o foi poss\xEDvel excluir o registro", type: "error" });
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
const handleDelete = (id) => setDeleteItemId(id);
|
|
1365
|
+
const confirmDelete = () => {
|
|
1366
|
+
if (deleteItemId && deleteFn) deleteMutation.mutate(deleteItemId);
|
|
1367
|
+
};
|
|
1368
|
+
const filteredItems = items.filter((item) => {
|
|
1369
|
+
const matchesSearch = searchColumns.length === 0 || searchColumns.some((col) => {
|
|
1370
|
+
const value = item[col.key];
|
|
1371
|
+
return value && String(value).toLowerCase().includes(searchTerm.toLowerCase());
|
|
1372
|
+
});
|
|
1373
|
+
const matchesFilter = !filterFn || activeFilters.length === 0 || activeFilters.some((filterValue) => filterFn(item, filterValue));
|
|
1374
|
+
return matchesSearch && matchesFilter;
|
|
1375
|
+
});
|
|
1376
|
+
const DisplayIcon = EmptyIcon || Icon;
|
|
1377
|
+
const colorMap = {
|
|
1378
|
+
green: { bg: "bg-green-100", text: "text-green-800", border: "border-green-300", darkBg: "dark:bg-green-900/30", darkText: "dark:text-green-300", darkBorder: "dark:border-green-800" },
|
|
1379
|
+
red: { bg: "bg-red-100", text: "text-red-800", border: "border-red-300", darkBg: "dark:bg-red-900/30", darkText: "dark:text-red-300", darkBorder: "dark:border-red-800" },
|
|
1380
|
+
blue: { bg: "bg-blue-100", text: "text-blue-800", border: "border-blue-300", darkBg: "dark:bg-blue-900/30", darkText: "dark:text-blue-300", darkBorder: "dark:border-blue-800" },
|
|
1381
|
+
cyan: { bg: "bg-cyan-100", text: "text-cyan-800", border: "border-cyan-300", darkBg: "dark:bg-cyan-900/30", darkText: "dark:text-cyan-300", darkBorder: "dark:border-cyan-800" },
|
|
1382
|
+
orange: { bg: "bg-orange-100", text: "text-orange-800", border: "border-orange-300", darkBg: "dark:bg-orange-900/30", darkText: "dark:text-orange-300", darkBorder: "dark:border-orange-800" },
|
|
1383
|
+
gray: { bg: "bg-slate-100", text: "text-slate-800", border: "border-slate-300", darkBg: "dark:bg-slate-900/30", darkText: "dark:text-slate-300", darkBorder: "dark:border-slate-800" },
|
|
1384
|
+
purple: { bg: "bg-purple-100", text: "text-purple-800", border: "border-purple-300", darkBg: "dark:bg-purple-900/30", darkText: "dark:text-purple-300", darkBorder: "dark:border-purple-800" }
|
|
1385
|
+
};
|
|
1386
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
1387
|
+
!hideHeader && title && Icon && /* @__PURE__ */ jsx(
|
|
1388
|
+
PageHeader,
|
|
1389
|
+
{
|
|
1390
|
+
title,
|
|
1391
|
+
subtitle,
|
|
1392
|
+
icon: Icon,
|
|
1393
|
+
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1394
|
+
onExport && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onExport, children: [
|
|
1395
|
+
/* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }),
|
|
1396
|
+
"Exportar"
|
|
1397
|
+
] }),
|
|
1398
|
+
onNew && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: onNew, children: [
|
|
1399
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
1400
|
+
newButtonLabel
|
|
1401
|
+
] })
|
|
1402
|
+
] })
|
|
1403
|
+
}
|
|
1404
|
+
),
|
|
1405
|
+
computedStats && computedStats.length > 0 && /* @__PURE__ */ jsx("div", { className: `grid grid-cols-2 md:grid-cols-3 lg:grid-cols-${Math.min(computedStats.length, 6)} gap-4`, children: computedStats.map((stat, idx) => /* @__PURE__ */ jsx(StatCard, { ...stat }, stat.label || idx)) }),
|
|
1406
|
+
computedFilters && computedFilters.length > 0 && /* @__PURE__ */ jsx(
|
|
1407
|
+
SmartFilterPanel_default,
|
|
1408
|
+
{
|
|
1409
|
+
filterGroups: [{
|
|
1410
|
+
key: "status",
|
|
1411
|
+
label: "Status",
|
|
1412
|
+
renderType: "badges",
|
|
1413
|
+
allLabel: "Todos",
|
|
1414
|
+
options: computedFilters.map((f) => ({
|
|
1415
|
+
value: f.value,
|
|
1416
|
+
label: f.label,
|
|
1417
|
+
emoji: f.emoji,
|
|
1418
|
+
color: colorMap[f.color || "gray"] || colorMap.gray
|
|
1419
|
+
})),
|
|
1420
|
+
selectedValues: activeFilters,
|
|
1421
|
+
onChange: setActiveFilters
|
|
1422
|
+
}],
|
|
1423
|
+
searchValue: searchTerm,
|
|
1424
|
+
onSearchChange: setSearchTerm,
|
|
1425
|
+
searchPlaceholder,
|
|
1426
|
+
resultsCount: filteredItems.length,
|
|
1427
|
+
persistKey,
|
|
1428
|
+
enablePresets,
|
|
1429
|
+
enableHistory,
|
|
1430
|
+
enableUrlSync,
|
|
1431
|
+
onClearAll: () => {
|
|
1432
|
+
setSearchTerm("");
|
|
1433
|
+
setActiveFilters([]);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
),
|
|
1437
|
+
/* @__PURE__ */ jsx("div", { children: isLoading ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12 text-muted-foreground", children: [
|
|
1438
|
+
DisplayIcon && /* @__PURE__ */ jsx(DisplayIcon, { className: "w-16 h-16 mx-auto mb-4 opacity-30 animate-pulse" }),
|
|
1439
|
+
/* @__PURE__ */ jsx("p", { children: "Carregando..." })
|
|
1440
|
+
] }) : filteredItems.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12 text-muted-foreground", children: [
|
|
1441
|
+
DisplayIcon && /* @__PURE__ */ jsx(DisplayIcon, { className: "w-16 h-16 mx-auto mb-4 opacity-30" }),
|
|
1442
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium", children: emptyMessage }),
|
|
1443
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", children: "Tente ajustar os filtros ou adicione um novo registro" })
|
|
1444
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-4", children: filteredItems.map((item, index) => /* @__PURE__ */ jsx(
|
|
1445
|
+
motion.div,
|
|
1446
|
+
{
|
|
1447
|
+
initial: { opacity: 0, y: 20 },
|
|
1448
|
+
animate: { opacity: 1, y: 0 },
|
|
1449
|
+
transition: { delay: index * 0.05, duration: 0.3 },
|
|
1450
|
+
onClick: () => {
|
|
1451
|
+
onCardClick(item);
|
|
1452
|
+
setSelectedItem(item);
|
|
1453
|
+
},
|
|
1454
|
+
className: "cursor-pointer",
|
|
1455
|
+
children: renderCard(item, selectedItem?.id === item.id, deleteFn ? handleDelete : void 0)
|
|
1456
|
+
},
|
|
1457
|
+
`${item.id}-${index}`
|
|
1458
|
+
)) }) }),
|
|
1459
|
+
selectedItem && renderDrawer && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1460
|
+
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/20 dark:bg-black/40 z-40", onClick: () => setSelectedItem(null) }),
|
|
1461
|
+
renderDrawer(selectedItem, () => setSelectedItem(null), () => {
|
|
1462
|
+
}, handleDelete)
|
|
1463
|
+
] }),
|
|
1464
|
+
renderAdvancedFilters && renderAdvancedFilters(showFilters, setShowFilters),
|
|
1465
|
+
deleteFn && /* @__PURE__ */ jsx(
|
|
1466
|
+
ConfirmDialog_default,
|
|
1467
|
+
{
|
|
1468
|
+
isOpen: deleteItemId !== null,
|
|
1469
|
+
onClose: () => setDeleteItemId(null),
|
|
1470
|
+
onConfirm: confirmDelete,
|
|
1471
|
+
type: "delete",
|
|
1472
|
+
title: deleteTitle,
|
|
1473
|
+
message: deleteItemId ? deleteMessage(items.find((i) => i.id === deleteItemId)) : "",
|
|
1474
|
+
loading: deleteMutation.isPending
|
|
1475
|
+
}
|
|
1476
|
+
),
|
|
1477
|
+
toastState && /* @__PURE__ */ jsx(Toast_default, { message: toastState.message, type: toastState.type, onClose: () => setToastState(null) })
|
|
1478
|
+
] });
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// src/theme/tokens.ts
|
|
1482
|
+
var defaultTheme = {
|
|
1483
|
+
background: "210 20% 96%",
|
|
1484
|
+
foreground: "240 10% 4%",
|
|
1485
|
+
card: "0 0% 100%",
|
|
1486
|
+
cardForeground: "240 10% 4%",
|
|
1487
|
+
primary: "142 76% 36%",
|
|
1488
|
+
primaryForeground: "0 0% 100%",
|
|
1489
|
+
secondary: "240 5% 96%",
|
|
1490
|
+
secondaryForeground: "240 10% 4%",
|
|
1491
|
+
muted: "240 5% 96%",
|
|
1492
|
+
mutedForeground: "240 4% 46%",
|
|
1493
|
+
accent: "217 91% 60%",
|
|
1494
|
+
accentForeground: "0 0% 100%",
|
|
1495
|
+
destructive: "0 72% 51%",
|
|
1496
|
+
destructiveForeground: "0 0% 100%",
|
|
1497
|
+
border: "240 6% 90%",
|
|
1498
|
+
input: "240 6% 90%",
|
|
1499
|
+
inputBg: "0 0% 100%",
|
|
1500
|
+
ring: "142 76% 36%",
|
|
1501
|
+
radius: "0.75rem"
|
|
1502
|
+
};
|
|
1503
|
+
var defaultDarkTheme = {
|
|
1504
|
+
background: "222 47% 8%",
|
|
1505
|
+
foreground: "210 40% 98%",
|
|
1506
|
+
card: "222 47% 15%",
|
|
1507
|
+
cardForeground: "210 40% 98%",
|
|
1508
|
+
primary: "161 94% 43%",
|
|
1509
|
+
primaryForeground: "255 100% 100%",
|
|
1510
|
+
secondary: "215 28% 21%",
|
|
1511
|
+
secondaryForeground: "210 40% 98%",
|
|
1512
|
+
muted: "215 28% 21%",
|
|
1513
|
+
mutedForeground: "215 20% 65%",
|
|
1514
|
+
accent: "161 94% 43%",
|
|
1515
|
+
accentForeground: "255 100% 100%",
|
|
1516
|
+
destructive: "0 84% 60%",
|
|
1517
|
+
destructiveForeground: "210 40% 98%",
|
|
1518
|
+
border: "215 28% 21%",
|
|
1519
|
+
input: "215 28% 21%",
|
|
1520
|
+
inputBg: "215 28% 17%",
|
|
1521
|
+
ring: "161 94% 43%"
|
|
1522
|
+
};
|
|
1523
|
+
function applyTheme(tokens, selector) {
|
|
1524
|
+
const map = {
|
|
1525
|
+
background: "--background",
|
|
1526
|
+
foreground: "--foreground",
|
|
1527
|
+
card: "--card",
|
|
1528
|
+
cardForeground: "--card-foreground",
|
|
1529
|
+
primary: "--primary",
|
|
1530
|
+
primaryForeground: "--primary-foreground",
|
|
1531
|
+
secondary: "--secondary",
|
|
1532
|
+
secondaryForeground: "--secondary-foreground",
|
|
1533
|
+
muted: "--muted",
|
|
1534
|
+
mutedForeground: "--muted-foreground",
|
|
1535
|
+
accent: "--accent",
|
|
1536
|
+
accentForeground: "--accent-foreground",
|
|
1537
|
+
destructive: "--destructive",
|
|
1538
|
+
destructiveForeground: "--destructive-foreground",
|
|
1539
|
+
border: "--border",
|
|
1540
|
+
input: "--input",
|
|
1541
|
+
inputBg: "--input-bg",
|
|
1542
|
+
ring: "--ring",
|
|
1543
|
+
radius: "--radius"
|
|
1544
|
+
};
|
|
1545
|
+
const el = document.documentElement ;
|
|
1546
|
+
if (!el) return;
|
|
1547
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
1548
|
+
if (value !== void 0) el.style.setProperty(map[key], value);
|
|
1549
|
+
});
|
|
1550
|
+
}
|
|
1551
|
+
function ThemeProvider({ children, theme, darkTheme }) {
|
|
1552
|
+
useEffect(() => {
|
|
1553
|
+
const light = { ...defaultTheme, ...theme };
|
|
1554
|
+
applyTheme(light);
|
|
1555
|
+
}, [theme]);
|
|
1556
|
+
useEffect(() => {
|
|
1557
|
+
const dark = { ...defaultDarkTheme, ...darkTheme };
|
|
1558
|
+
const applyDark = () => {
|
|
1559
|
+
if (document.documentElement.classList.contains("dark")) {
|
|
1560
|
+
applyTheme(dark);
|
|
1561
|
+
} else {
|
|
1562
|
+
const light = { ...defaultTheme, ...theme };
|
|
1563
|
+
applyTheme(light);
|
|
1564
|
+
}
|
|
1565
|
+
};
|
|
1566
|
+
applyDark();
|
|
1567
|
+
const observer = new MutationObserver(applyDark);
|
|
1568
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
|
|
1569
|
+
return () => observer.disconnect();
|
|
1570
|
+
}, [theme, darkTheme]);
|
|
1571
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
export { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Checkbox, ConfirmDialog_default as ConfirmDialog, DataTable_default as DataTable, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Input, PageHeader, PageLayout, STAT_ACCENT_SEQUENCE, SmartFilterPanel_default as SmartFilterPanel, StatCard, Table2 as Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, ThemeProvider, Toast_default as Toast, badgeVariants, buttonVariants, cn, defaultDarkTheme, defaultTheme };
|
|
1575
|
+
//# sourceMappingURL=index.js.map
|
|
1576
|
+
//# sourceMappingURL=index.js.map
|