@motor-hero/ui-kit 0.34.1 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/date-picker.d.ts.map +1 -1
- package/dist/components/filter-toolbar.d.ts +67 -0
- package/dist/components/filter-toolbar.d.ts.map +1 -0
- package/dist/index.cjs +1574 -1402
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +46 -44
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1628 -1459
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/date-picker.tsx +27 -9
- package/src/components/filter-toolbar.tsx +239 -0
- package/src/index.ts +83 -61
package/dist/index.js
CHANGED
|
@@ -1,419 +1,372 @@
|
|
|
1
|
-
// src/components/
|
|
2
|
-
import {
|
|
1
|
+
// src/components/app-shell.tsx
|
|
2
|
+
import { ChevronLeft, ChevronRight, Menu } from "lucide-react";
|
|
3
|
+
import { useState as useState3 } from "react";
|
|
3
4
|
|
|
4
|
-
// src/lib/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
secondaryForeground: "--color-secondary-foreground",
|
|
10
|
-
accent: "--color-accent",
|
|
11
|
-
accentForeground: "--color-accent-foreground",
|
|
12
|
-
ring: "--color-ring"
|
|
13
|
-
};
|
|
14
|
-
function definedTokens(tokens) {
|
|
15
|
-
if (!tokens) return {};
|
|
16
|
-
return Object.fromEntries(
|
|
17
|
-
Object.entries(tokens).filter(([, value]) => value != null)
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
function applyCompanyTheme(root, companyTheme, mode) {
|
|
21
|
-
const tokens = companyTheme ? mode === "dark" ? { ...companyTheme.light, ...definedTokens(companyTheme.dark) } : companyTheme.light : {};
|
|
22
|
-
for (const key of Object.keys(VAR_MAP)) {
|
|
23
|
-
const value = tokens[key];
|
|
24
|
-
if (value) root.style.setProperty(VAR_MAP[key], value);
|
|
25
|
-
else root.style.removeProperty(VAR_MAP[key]);
|
|
26
|
-
}
|
|
5
|
+
// src/lib/utils.ts
|
|
6
|
+
import { clsx } from "clsx";
|
|
7
|
+
import { twMerge } from "tailwind-merge";
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
27
10
|
}
|
|
28
11
|
|
|
29
|
-
// src/components/
|
|
12
|
+
// src/components/sidebar-nav.tsx
|
|
13
|
+
import { Fragment } from "react";
|
|
14
|
+
|
|
15
|
+
// src/components/types.tsx
|
|
30
16
|
import { jsx } from "react/jsx-runtime";
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
defaultTheme = "system",
|
|
39
|
-
storageKey = "ui-theme",
|
|
40
|
-
companyTheme,
|
|
41
|
-
...props
|
|
42
|
-
}) {
|
|
43
|
-
const [theme, setTheme] = useState(
|
|
44
|
-
() => localStorage.getItem(storageKey) || defaultTheme
|
|
45
|
-
);
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
const root = window.document.documentElement;
|
|
48
|
-
const applyResolved = (resolved) => {
|
|
49
|
-
root.classList.remove("light", "dark");
|
|
50
|
-
root.classList.add(resolved);
|
|
51
|
-
applyCompanyTheme(root, companyTheme, resolved);
|
|
52
|
-
};
|
|
53
|
-
if (theme === "system") {
|
|
54
|
-
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
55
|
-
applyResolved(mql.matches ? "dark" : "light");
|
|
56
|
-
const onChange = (e) => applyResolved(e.matches ? "dark" : "light");
|
|
57
|
-
mql.addEventListener("change", onChange);
|
|
58
|
-
return () => mql.removeEventListener("change", onChange);
|
|
59
|
-
}
|
|
60
|
-
applyResolved(theme);
|
|
61
|
-
}, [theme, companyTheme]);
|
|
62
|
-
const value = {
|
|
63
|
-
theme,
|
|
64
|
-
setTheme: (theme2) => {
|
|
65
|
-
localStorage.setItem(storageKey, theme2);
|
|
66
|
-
setTheme(theme2);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
return /* @__PURE__ */ jsx(ThemeProviderContext.Provider, { ...props, value, children });
|
|
17
|
+
var defaultRenderLink = ({ children, ...props }) => /* @__PURE__ */ jsx("a", { ...props, children });
|
|
18
|
+
|
|
19
|
+
// src/components/sidebar-nav.tsx
|
|
20
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
21
|
+
function defaultIsActive(item, activePath) {
|
|
22
|
+
if (item.href === "/") return activePath === "/";
|
|
23
|
+
return activePath === item.href || activePath.startsWith(item.href + "/");
|
|
70
24
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
25
|
+
function SidebarNav({
|
|
26
|
+
items,
|
|
27
|
+
activePath,
|
|
28
|
+
isActive = defaultIsActive,
|
|
29
|
+
isAdmin = false,
|
|
30
|
+
isCollapsed = false,
|
|
31
|
+
renderLink = defaultRenderLink,
|
|
32
|
+
onNavigate
|
|
33
|
+
}) {
|
|
34
|
+
const visible = items.filter((item) => !item.adminOnly || isAdmin);
|
|
35
|
+
return /* @__PURE__ */ jsx2("nav", { className: "flex flex-col gap-1", children: visible.map((item) => {
|
|
36
|
+
const active = isActive(item, activePath);
|
|
37
|
+
const link = renderLink({
|
|
38
|
+
href: item.href,
|
|
39
|
+
onClick: onNavigate,
|
|
40
|
+
title: isCollapsed ? item.label : void 0,
|
|
41
|
+
"aria-current": active ? "page" : void 0,
|
|
42
|
+
className: cn(
|
|
43
|
+
"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
44
|
+
active ? "bg-accent text-accent-foreground font-semibold" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
45
|
+
isCollapsed && "justify-center px-2"
|
|
46
|
+
),
|
|
47
|
+
children: /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
48
|
+
item.icon && /* @__PURE__ */ jsx2("span", { className: "shrink-0", children: item.icon }),
|
|
49
|
+
!isCollapsed && /* @__PURE__ */ jsx2("span", { className: "truncate", children: item.label })
|
|
50
|
+
] })
|
|
51
|
+
});
|
|
52
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: link }, item.href);
|
|
53
|
+
}) });
|
|
77
54
|
}
|
|
78
55
|
|
|
79
|
-
// src/
|
|
56
|
+
// src/components/user-menu.tsx
|
|
57
|
+
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
58
|
+
import { LogOut, User } from "lucide-react";
|
|
80
59
|
import { useState as useState2 } from "react";
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
60
|
+
import { Drawer as DrawerPrimitive } from "vaul";
|
|
61
|
+
|
|
62
|
+
// src/hooks/use-is-desktop.ts
|
|
63
|
+
import * as React from "react";
|
|
64
|
+
var DESKTOP_QUERY = "(min-width: 640px)";
|
|
65
|
+
function useIsDesktop() {
|
|
66
|
+
const [isDesktop, setIsDesktop] = React.useState(
|
|
67
|
+
() => typeof window !== "undefined" ? window.matchMedia(DESKTOP_QUERY).matches : true
|
|
68
|
+
);
|
|
69
|
+
React.useEffect(() => {
|
|
70
|
+
const mql = window.matchMedia(DESKTOP_QUERY);
|
|
71
|
+
const onChange = () => setIsDesktop(mql.matches);
|
|
72
|
+
onChange();
|
|
73
|
+
mql.addEventListener("change", onChange);
|
|
74
|
+
return () => mql.removeEventListener("change", onChange);
|
|
75
|
+
}, []);
|
|
76
|
+
return isDesktop;
|
|
87
77
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
window.localStorage.removeItem(storageKey);
|
|
98
|
-
return void 0;
|
|
99
|
-
}
|
|
100
|
-
return window.localStorage.getItem(storageKey) ?? void 0;
|
|
78
|
+
|
|
79
|
+
// src/components/user-menu.tsx
|
|
80
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
81
|
+
function initials(user) {
|
|
82
|
+
const source = user?.name?.trim() || user?.email?.trim();
|
|
83
|
+
if (!source) return "";
|
|
84
|
+
const parts = source.split(/\s+/);
|
|
85
|
+
if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
|
|
86
|
+
return source.slice(0, 2).toUpperCase();
|
|
101
87
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
88
|
+
var itemClass = "flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent";
|
|
89
|
+
var sheetItemClass = "flex w-full cursor-pointer select-none items-center gap-3 rounded-md px-3 py-3 text-base outline-none transition-colors hover:bg-accent active:bg-accent";
|
|
90
|
+
function UserMenu({
|
|
91
|
+
user,
|
|
92
|
+
items = [],
|
|
93
|
+
onLogout,
|
|
94
|
+
logoutLabel = "Sair",
|
|
95
|
+
renderLink = defaultRenderLink,
|
|
96
|
+
align = "end"
|
|
97
|
+
}) {
|
|
98
|
+
const isDesktop = useIsDesktop();
|
|
99
|
+
const [open, setOpen] = useState2(false);
|
|
100
|
+
const label = initials(user);
|
|
101
|
+
const trigger = /* @__PURE__ */ jsx3(
|
|
102
|
+
"button",
|
|
103
|
+
{
|
|
104
|
+
type: "button",
|
|
105
|
+
className: "inline-flex h-9 w-9 items-center justify-center overflow-hidden rounded-full border border-input bg-background text-xs font-semibold shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
106
|
+
"aria-label": "Menu do usu\xE1rio",
|
|
107
|
+
"data-testid": "user-menu",
|
|
108
|
+
children: user?.avatarUrl ? /* @__PURE__ */ jsx3(
|
|
109
|
+
"img",
|
|
110
|
+
{
|
|
111
|
+
src: user.avatarUrl,
|
|
112
|
+
alt: user.name ?? user.email ?? "Avatar",
|
|
113
|
+
className: "h-full w-full object-cover"
|
|
114
|
+
}
|
|
115
|
+
) : label ? /* @__PURE__ */ jsx3("span", { children: label }) : /* @__PURE__ */ jsx3(User, { className: "h-4 w-4" })
|
|
108
116
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
117
|
+
);
|
|
118
|
+
const userInfo = (user?.name || user?.email) && /* @__PURE__ */ jsxs2("div", { className: "px-2 py-1.5", children: [
|
|
119
|
+
user.name && /* @__PURE__ */ jsx3("p", { className: "truncate text-sm font-medium", children: user.name }),
|
|
120
|
+
user.email && /* @__PURE__ */ jsx3("p", { className: "truncate text-xs text-muted-foreground", children: user.email })
|
|
121
|
+
] });
|
|
122
|
+
if (isDesktop) {
|
|
123
|
+
return /* @__PURE__ */ jsxs2(DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
|
|
124
|
+
/* @__PURE__ */ jsx3(DropdownMenu.Trigger, { asChild: true, children: trigger }),
|
|
125
|
+
/* @__PURE__ */ jsx3(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs2(
|
|
126
|
+
DropdownMenu.Content,
|
|
127
|
+
{
|
|
128
|
+
align,
|
|
129
|
+
sideOffset: 6,
|
|
130
|
+
className: "z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
|
|
131
|
+
children: [
|
|
132
|
+
userInfo && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
133
|
+
userInfo,
|
|
134
|
+
/* @__PURE__ */ jsx3(DropdownMenu.Separator, { className: "-mx-1 my-1 h-px bg-border" })
|
|
135
|
+
] }),
|
|
136
|
+
items.map(
|
|
137
|
+
(item) => item.href ? /* @__PURE__ */ jsx3(DropdownMenu.Item, { asChild: true, children: renderLink({
|
|
138
|
+
href: item.href,
|
|
139
|
+
className: itemClass,
|
|
140
|
+
children: /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
141
|
+
item.icon,
|
|
142
|
+
item.label
|
|
143
|
+
] })
|
|
144
|
+
}) }, item.label) : /* @__PURE__ */ jsxs2(
|
|
145
|
+
DropdownMenu.Item,
|
|
146
|
+
{
|
|
147
|
+
className: itemClass,
|
|
148
|
+
onClick: item.onClick,
|
|
149
|
+
children: [
|
|
150
|
+
item.icon,
|
|
151
|
+
item.label
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
item.label
|
|
155
|
+
)
|
|
156
|
+
),
|
|
157
|
+
onLogout && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
158
|
+
items.length > 0 && /* @__PURE__ */ jsx3(DropdownMenu.Separator, { className: "-mx-1 my-1 h-px bg-border" }),
|
|
159
|
+
/* @__PURE__ */ jsxs2(
|
|
160
|
+
DropdownMenu.Item,
|
|
161
|
+
{
|
|
162
|
+
className: cn(
|
|
163
|
+
itemClass,
|
|
164
|
+
"text-destructive focus:bg-destructive/10"
|
|
165
|
+
),
|
|
166
|
+
onClick: onLogout,
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ jsx3(LogOut, { className: "h-4 w-4" }),
|
|
169
|
+
logoutLabel
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
] })
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
) })
|
|
177
|
+
] });
|
|
178
|
+
}
|
|
179
|
+
return /* @__PURE__ */ jsxs2(DrawerPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
180
|
+
/* @__PURE__ */ jsx3(DrawerPrimitive.Trigger, { asChild: true, children: trigger }),
|
|
181
|
+
/* @__PURE__ */ jsxs2(DrawerPrimitive.Portal, { children: [
|
|
182
|
+
/* @__PURE__ */ jsx3(DrawerPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
183
|
+
/* @__PURE__ */ jsxs2(DrawerPrimitive.Content, { className: "fixed inset-x-0 bottom-0 z-50 flex flex-col rounded-t-2xl border bg-popover p-2 pb-[max(0.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-none", children: [
|
|
184
|
+
/* @__PURE__ */ jsx3(DrawerPrimitive.Title, { className: "sr-only", children: "Menu do usu\xE1rio" }),
|
|
185
|
+
/* @__PURE__ */ jsx3("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
186
|
+
userInfo && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
187
|
+
userInfo,
|
|
188
|
+
/* @__PURE__ */ jsx3("div", { className: "-mx-1 my-1 h-px bg-border" })
|
|
189
|
+
] }),
|
|
190
|
+
items.map(
|
|
191
|
+
(item) => item.href ? /* @__PURE__ */ jsx3(
|
|
192
|
+
"span",
|
|
142
193
|
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
children:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
194
|
+
onClick: () => setOpen(false),
|
|
195
|
+
onKeyDown: () => setOpen(false),
|
|
196
|
+
children: renderLink({
|
|
197
|
+
href: item.href,
|
|
198
|
+
className: sheetItemClass,
|
|
199
|
+
children: /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
200
|
+
item.icon,
|
|
201
|
+
item.label
|
|
202
|
+
] })
|
|
203
|
+
})
|
|
204
|
+
},
|
|
205
|
+
item.label
|
|
206
|
+
) : /* @__PURE__ */ jsxs2(
|
|
207
|
+
"button",
|
|
153
208
|
{
|
|
154
|
-
|
|
155
|
-
|
|
209
|
+
type: "button",
|
|
210
|
+
className: sheetItemClass,
|
|
211
|
+
onClick: () => {
|
|
212
|
+
item.onClick?.();
|
|
213
|
+
setOpen(false);
|
|
214
|
+
},
|
|
156
215
|
children: [
|
|
157
|
-
|
|
158
|
-
|
|
216
|
+
item.icon,
|
|
217
|
+
item.label
|
|
159
218
|
]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
219
|
+
},
|
|
220
|
+
item.label
|
|
221
|
+
)
|
|
222
|
+
),
|
|
223
|
+
onLogout && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
224
|
+
items.length > 0 && /* @__PURE__ */ jsx3("div", { className: "-mx-1 my-1 h-px bg-border" }),
|
|
225
|
+
/* @__PURE__ */ jsxs2(
|
|
226
|
+
"button",
|
|
164
227
|
{
|
|
165
|
-
|
|
166
|
-
|
|
228
|
+
type: "button",
|
|
229
|
+
className: cn(sheetItemClass, "text-destructive"),
|
|
230
|
+
onClick: () => {
|
|
231
|
+
onLogout();
|
|
232
|
+
setOpen(false);
|
|
233
|
+
},
|
|
167
234
|
children: [
|
|
168
|
-
/* @__PURE__ */
|
|
169
|
-
|
|
235
|
+
/* @__PURE__ */ jsx3(LogOut, { className: "h-4 w-4" }),
|
|
236
|
+
logoutLabel
|
|
170
237
|
]
|
|
171
238
|
}
|
|
172
239
|
)
|
|
173
|
-
]
|
|
174
|
-
}
|
|
175
|
-
) })
|
|
176
|
-
] });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// src/components/empty-state.tsx
|
|
180
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
181
|
-
function EmptyState({ icon, title, description, action, className }) {
|
|
182
|
-
return /* @__PURE__ */ jsxs2("div", { className: `flex flex-col items-center justify-center py-16 text-center ${className ?? ""}`, children: [
|
|
183
|
-
icon && /* @__PURE__ */ jsx3("div", { className: "mb-4 text-muted-foreground", children: icon }),
|
|
184
|
-
/* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold tracking-tight", children: title }),
|
|
185
|
-
description && /* @__PURE__ */ jsx3("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: description }),
|
|
186
|
-
action && /* @__PURE__ */ jsx3("div", { className: "mt-4", children: action })
|
|
187
|
-
] });
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// src/components/confirm-dialog.tsx
|
|
191
|
-
import * as AlertDialog from "@radix-ui/react-alert-dialog";
|
|
192
|
-
|
|
193
|
-
// src/lib/utils.ts
|
|
194
|
-
import { clsx } from "clsx";
|
|
195
|
-
import { twMerge } from "tailwind-merge";
|
|
196
|
-
function cn(...inputs) {
|
|
197
|
-
return twMerge(clsx(inputs));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// src/components/confirm-dialog.tsx
|
|
201
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
202
|
-
function ConfirmDialog({
|
|
203
|
-
open,
|
|
204
|
-
onOpenChange,
|
|
205
|
-
onConfirm,
|
|
206
|
-
title,
|
|
207
|
-
description,
|
|
208
|
-
confirmLabel = "Confirmar",
|
|
209
|
-
cancelLabel = "Cancelar",
|
|
210
|
-
loading = false,
|
|
211
|
-
variant = "default",
|
|
212
|
-
blurBackdrop = true,
|
|
213
|
-
backdropClassName
|
|
214
|
-
}) {
|
|
215
|
-
return /* @__PURE__ */ jsx4(AlertDialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs3(AlertDialog.Portal, { children: [
|
|
216
|
-
/* @__PURE__ */ jsx4(
|
|
217
|
-
AlertDialog.Overlay,
|
|
218
|
-
{
|
|
219
|
-
className: cn(
|
|
220
|
-
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
221
|
-
blurBackdrop && "backdrop-blur-sm",
|
|
222
|
-
backdropClassName
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
),
|
|
226
|
-
/* @__PURE__ */ jsxs3(AlertDialog.Content, { className: "fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", children: [
|
|
227
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col space-y-2 text-center sm:text-left", children: [
|
|
228
|
-
/* @__PURE__ */ jsx4(AlertDialog.Title, { className: "text-lg font-semibold", children: title }),
|
|
229
|
-
/* @__PURE__ */ jsx4(AlertDialog.Description, { className: "text-sm text-muted-foreground", children: description })
|
|
230
|
-
] }),
|
|
231
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
|
|
232
|
-
/* @__PURE__ */ jsx4(AlertDialog.Cancel, { className: "inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer", children: cancelLabel }),
|
|
233
|
-
/* @__PURE__ */ jsx4(
|
|
234
|
-
AlertDialog.Action,
|
|
235
|
-
{
|
|
236
|
-
onClick: onConfirm,
|
|
237
|
-
disabled: loading,
|
|
238
|
-
className: `inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer ${variant === "destructive" ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : "bg-primary text-primary-foreground hover:bg-primary/90"}`,
|
|
239
|
-
children: loading ? "Aguarde..." : confirmLabel
|
|
240
|
-
}
|
|
241
|
-
)
|
|
240
|
+
] })
|
|
242
241
|
] })
|
|
243
242
|
] })
|
|
244
|
-
] }) });
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// src/components/page-header.tsx
|
|
248
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
249
|
-
function PageHeader({ title, description, action, className }) {
|
|
250
|
-
return /* @__PURE__ */ jsxs4(
|
|
251
|
-
"div",
|
|
252
|
-
{
|
|
253
|
-
className: `flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? ""}`,
|
|
254
|
-
children: [
|
|
255
|
-
/* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
|
|
256
|
-
/* @__PURE__ */ jsx5("h1", { className: "truncate text-2xl font-semibold tracking-tight", children: title }),
|
|
257
|
-
description && /* @__PURE__ */ jsx5("p", { className: "text-sm text-muted-foreground", children: description })
|
|
258
|
-
] }),
|
|
259
|
-
action && /* @__PURE__ */ jsx5("div", { className: "shrink-0", children: action })
|
|
260
|
-
]
|
|
261
|
-
}
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// src/components/status-dot.tsx
|
|
266
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
267
|
-
function StatusDot({ active, label, className }) {
|
|
268
|
-
return /* @__PURE__ */ jsxs5("span", { className: `inline-flex items-center gap-2 ${className ?? ""}`, children: [
|
|
269
|
-
/* @__PURE__ */ jsx6(
|
|
270
|
-
"span",
|
|
271
|
-
{
|
|
272
|
-
className: `h-2 w-2 rounded-full ${active ? "bg-green-500" : "bg-red-500"}`
|
|
273
|
-
}
|
|
274
|
-
),
|
|
275
|
-
label && /* @__PURE__ */ jsx6("span", { children: label })
|
|
276
243
|
] });
|
|
277
244
|
}
|
|
278
245
|
|
|
279
|
-
// src/components/
|
|
280
|
-
import { jsx as
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
badge: "bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400",
|
|
296
|
-
dot: "bg-red-500"
|
|
297
|
-
},
|
|
298
|
-
warning: {
|
|
299
|
-
badge: "bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400",
|
|
300
|
-
dot: "bg-amber-500"
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
function StatusBadge({
|
|
304
|
-
variant = "neutral",
|
|
305
|
-
dot = true,
|
|
306
|
-
className,
|
|
246
|
+
// src/components/app-shell.tsx
|
|
247
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
248
|
+
function AppShell({
|
|
249
|
+
brand,
|
|
250
|
+
brandCollapsed,
|
|
251
|
+
navItems,
|
|
252
|
+
activePath,
|
|
253
|
+
isActive,
|
|
254
|
+
isAdmin = false,
|
|
255
|
+
user,
|
|
256
|
+
userMenuItems,
|
|
257
|
+
onLogout,
|
|
258
|
+
renderLink = defaultRenderLink,
|
|
259
|
+
headerActions,
|
|
260
|
+
collapsible = true,
|
|
261
|
+
defaultCollapsed = false,
|
|
307
262
|
children
|
|
308
263
|
}) {
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
264
|
+
const [collapsed, setCollapsed] = useState3(defaultCollapsed);
|
|
265
|
+
const [mobileOpen, setMobileOpen] = useState3(false);
|
|
266
|
+
const nav = (isCollapsed, onNavigate) => /* @__PURE__ */ jsx4(
|
|
267
|
+
SidebarNav,
|
|
312
268
|
{
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
),
|
|
321
|
-
children
|
|
322
|
-
]
|
|
269
|
+
items: navItems,
|
|
270
|
+
activePath,
|
|
271
|
+
isActive,
|
|
272
|
+
isAdmin,
|
|
273
|
+
isCollapsed,
|
|
274
|
+
renderLink,
|
|
275
|
+
onNavigate
|
|
323
276
|
}
|
|
324
277
|
);
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
/* @__PURE__ */ jsx8(
|
|
348
|
-
"div",
|
|
349
|
-
{
|
|
350
|
-
className: `w-full overflow-hidden rounded-full bg-muted ${sizeClasses[size]}`,
|
|
351
|
-
children: /* @__PURE__ */ jsx8(
|
|
352
|
-
"div",
|
|
353
|
-
{
|
|
354
|
-
className: `h-full rounded-full transition-all duration-300 ${indicatorClassName ?? "bg-primary"}`,
|
|
355
|
-
style: { width: `${clamped}%` }
|
|
356
|
-
}
|
|
357
|
-
)
|
|
278
|
+
return /* @__PURE__ */ jsxs3("div", { className: "flex h-screen overflow-hidden bg-background", children: [
|
|
279
|
+
/* @__PURE__ */ jsxs3(
|
|
280
|
+
"aside",
|
|
281
|
+
{
|
|
282
|
+
className: cn(
|
|
283
|
+
"hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex",
|
|
284
|
+
collapsed ? "w-16" : "w-60"
|
|
285
|
+
),
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ jsx4("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: collapsed ? brandCollapsed ?? brand : brand }),
|
|
288
|
+
/* @__PURE__ */ jsx4("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(collapsed) }),
|
|
289
|
+
collapsible && /* @__PURE__ */ jsx4("div", { className: "border-t p-2", children: /* @__PURE__ */ jsx4(
|
|
290
|
+
"button",
|
|
291
|
+
{
|
|
292
|
+
type: "button",
|
|
293
|
+
onClick: () => setCollapsed((v) => !v),
|
|
294
|
+
className: "flex w-full items-center justify-center rounded-md px-2 py-2 text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
295
|
+
"aria-label": collapsed ? "Expandir menu" : "Recolher menu",
|
|
296
|
+
children: collapsed ? /* @__PURE__ */ jsx4(ChevronRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx4(ChevronLeft, { className: "h-4 w-4" })
|
|
297
|
+
}
|
|
298
|
+
) })
|
|
299
|
+
]
|
|
358
300
|
}
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
// src/components/form-field.tsx
|
|
364
|
-
import { cloneElement, isValidElement, useId } from "react";
|
|
365
|
-
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
366
|
-
function FormField({ label, htmlFor, error, required, children, className }) {
|
|
367
|
-
const errorId = useId();
|
|
368
|
-
const field = error && isValidElement(children) ? cloneElement(children, {
|
|
369
|
-
"aria-invalid": true,
|
|
370
|
-
"aria-describedby": [
|
|
371
|
-
children.props["aria-describedby"],
|
|
372
|
-
errorId
|
|
373
|
-
].filter(Boolean).join(" ")
|
|
374
|
-
}) : children;
|
|
375
|
-
return /* @__PURE__ */ jsxs8("div", { className: `space-y-2 ${className ?? ""}`, children: [
|
|
376
|
-
/* @__PURE__ */ jsxs8(
|
|
377
|
-
"label",
|
|
301
|
+
),
|
|
302
|
+
/* @__PURE__ */ jsxs3(
|
|
303
|
+
"div",
|
|
378
304
|
{
|
|
379
|
-
|
|
380
|
-
|
|
305
|
+
className: cn(
|
|
306
|
+
"fixed inset-0 z-50 transition-opacity duration-300 md:hidden",
|
|
307
|
+
mobileOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
|
308
|
+
),
|
|
309
|
+
onClick: () => setMobileOpen(false),
|
|
381
310
|
children: [
|
|
382
|
-
|
|
383
|
-
|
|
311
|
+
/* @__PURE__ */ jsx4("div", { className: "absolute inset-0 bg-black/50" }),
|
|
312
|
+
/* @__PURE__ */ jsxs3(
|
|
313
|
+
"div",
|
|
314
|
+
{
|
|
315
|
+
className: cn(
|
|
316
|
+
"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300",
|
|
317
|
+
mobileOpen ? "translate-x-0" : "-translate-x-full"
|
|
318
|
+
),
|
|
319
|
+
onClick: (e) => e.stopPropagation(),
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ jsx4("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: brand }),
|
|
322
|
+
/* @__PURE__ */ jsx4("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(false, () => setMobileOpen(false)) })
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
)
|
|
384
326
|
]
|
|
385
327
|
}
|
|
386
328
|
),
|
|
387
|
-
|
|
388
|
-
|
|
329
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
330
|
+
/* @__PURE__ */ jsxs3("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4", children: [
|
|
331
|
+
/* @__PURE__ */ jsx4(
|
|
332
|
+
"button",
|
|
333
|
+
{
|
|
334
|
+
type: "button",
|
|
335
|
+
onClick: () => setMobileOpen(true),
|
|
336
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded-md border border-input bg-background shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground md:hidden",
|
|
337
|
+
"aria-label": "Abrir menu",
|
|
338
|
+
children: /* @__PURE__ */ jsx4(Menu, { className: "h-4 w-4" })
|
|
339
|
+
}
|
|
340
|
+
),
|
|
341
|
+
/* @__PURE__ */ jsxs3("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
342
|
+
headerActions,
|
|
343
|
+
(user || onLogout) && /* @__PURE__ */ jsx4(UserMenu, { user, items: userMenuItems, onLogout, renderLink })
|
|
344
|
+
] })
|
|
345
|
+
] }),
|
|
346
|
+
/* @__PURE__ */ jsx4("main", { className: "flex-1 overflow-y-auto", children })
|
|
347
|
+
] })
|
|
389
348
|
] });
|
|
390
349
|
}
|
|
391
350
|
|
|
351
|
+
// src/components/auth-card.tsx
|
|
352
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
353
|
+
function AuthCard({ title, description, children, footer }) {
|
|
354
|
+
return /* @__PURE__ */ jsx5("div", { className: "flex min-h-screen items-center justify-center px-4", children: /* @__PURE__ */ jsxs4("div", { className: "w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm", children: [
|
|
355
|
+
/* @__PURE__ */ jsxs4("div", { className: "mb-6 text-center", children: [
|
|
356
|
+
/* @__PURE__ */ jsx5("h1", { className: "text-2xl font-semibold tracking-tight", children: title }),
|
|
357
|
+
description && /* @__PURE__ */ jsx5("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
|
|
358
|
+
] }),
|
|
359
|
+
/* @__PURE__ */ jsx5("div", { className: "space-y-4", children }),
|
|
360
|
+
footer && /* @__PURE__ */ jsx5("div", { className: "mt-4", children: footer })
|
|
361
|
+
] }) });
|
|
362
|
+
}
|
|
363
|
+
|
|
392
364
|
// src/components/base-dialog.tsx
|
|
393
365
|
import * as Dialog from "@radix-ui/react-dialog";
|
|
394
366
|
import { X } from "lucide-react";
|
|
395
367
|
import * as React2 from "react";
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
import * as React from "react";
|
|
399
|
-
var DESKTOP_QUERY = "(min-width: 640px)";
|
|
400
|
-
function useIsDesktop() {
|
|
401
|
-
const [isDesktop, setIsDesktop] = React.useState(
|
|
402
|
-
() => typeof window !== "undefined" ? window.matchMedia(DESKTOP_QUERY).matches : true
|
|
403
|
-
);
|
|
404
|
-
React.useEffect(() => {
|
|
405
|
-
const mql = window.matchMedia(DESKTOP_QUERY);
|
|
406
|
-
const onChange = () => setIsDesktop(mql.matches);
|
|
407
|
-
onChange();
|
|
408
|
-
mql.addEventListener("change", onChange);
|
|
409
|
-
return () => mql.removeEventListener("change", onChange);
|
|
410
|
-
}, []);
|
|
411
|
-
return isDesktop;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// src/components/base-dialog.tsx
|
|
415
|
-
import { Fragment, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
416
|
-
var sizeClasses2 = {
|
|
368
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
369
|
+
var sizeClasses = {
|
|
417
370
|
sm: "sm:max-w-sm",
|
|
418
371
|
md: "sm:max-w-md",
|
|
419
372
|
lg: "sm:max-w-lg",
|
|
@@ -449,27 +402,27 @@ function BaseDialog({
|
|
|
449
402
|
}, 0);
|
|
450
403
|
return () => window.clearTimeout(id);
|
|
451
404
|
}, [open]);
|
|
452
|
-
const body = /* @__PURE__ */
|
|
453
|
-
/* @__PURE__ */
|
|
454
|
-
/* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
456
|
-
description && /* @__PURE__ */
|
|
405
|
+
const body = /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
406
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-start justify-between gap-4 border-b px-6 py-3", children: [
|
|
407
|
+
/* @__PURE__ */ jsxs5("div", { className: "min-w-0 space-y-1", children: [
|
|
408
|
+
/* @__PURE__ */ jsx6(Dialog.Title, { className: "text-lg font-semibold leading-none tracking-tight", children: title }),
|
|
409
|
+
description && /* @__PURE__ */ jsx6(Dialog.Description, { className: "text-sm text-muted-foreground", children: description })
|
|
457
410
|
] }),
|
|
458
|
-
/* @__PURE__ */
|
|
411
|
+
/* @__PURE__ */ jsx6(
|
|
459
412
|
Dialog.Close,
|
|
460
413
|
{
|
|
461
414
|
className: "-mr-1 shrink-0 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
462
415
|
"aria-label": "Fechar",
|
|
463
|
-
children: /* @__PURE__ */
|
|
416
|
+
children: /* @__PURE__ */ jsx6(X, { className: "h-5 w-5" })
|
|
464
417
|
}
|
|
465
418
|
)
|
|
466
419
|
] }),
|
|
467
|
-
/* @__PURE__ */
|
|
468
|
-
footer && /* @__PURE__ */
|
|
420
|
+
/* @__PURE__ */ jsx6("div", { className: "min-h-0 flex-1 overflow-y-auto px-6 py-4", children }),
|
|
421
|
+
footer && /* @__PURE__ */ jsx6("div", { className: "flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-3 sm:flex-row sm:justify-end", children: footer })
|
|
469
422
|
] });
|
|
470
423
|
const isModal = modal ?? !isDesktop;
|
|
471
|
-
return /* @__PURE__ */
|
|
472
|
-
isModal ? /* @__PURE__ */
|
|
424
|
+
return /* @__PURE__ */ jsx6(Dialog.Root, { open, onOpenChange, modal: isModal, children: /* @__PURE__ */ jsxs5(Dialog.Portal, { children: [
|
|
425
|
+
isModal ? /* @__PURE__ */ jsx6(
|
|
473
426
|
Dialog.Overlay,
|
|
474
427
|
{
|
|
475
428
|
className: cn(
|
|
@@ -482,7 +435,7 @@ function BaseDialog({
|
|
|
482
435
|
// Radix skips Dialog.Overlay when non-modal, so the backdrop is
|
|
483
436
|
// rendered by hand; pointer-events-none keeps outside interactions
|
|
484
437
|
// working (the reason the dialog is non-modal on desktop).
|
|
485
|
-
(blurBackdrop || backdropClassName) && /* @__PURE__ */
|
|
438
|
+
(blurBackdrop || backdropClassName) && /* @__PURE__ */ jsx6(
|
|
486
439
|
"div",
|
|
487
440
|
{
|
|
488
441
|
"aria-hidden": true,
|
|
@@ -494,441 +447,178 @@ function BaseDialog({
|
|
|
494
447
|
}
|
|
495
448
|
)
|
|
496
449
|
),
|
|
497
|
-
/* @__PURE__ */
|
|
498
|
-
Dialog.Content,
|
|
499
|
-
{
|
|
500
|
-
onCloseAutoFocus: () => {
|
|
501
|
-
document.body.style.pointerEvents = "";
|
|
502
|
-
},
|
|
503
|
-
className: cn(
|
|
504
|
-
"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none",
|
|
505
|
-
"inset-x-0 bottom-0 rounded-t-2xl",
|
|
506
|
-
"sm:inset-x-auto sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:max-h-[92vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg",
|
|
507
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
508
|
-
sizeClasses2[size],
|
|
509
|
-
className
|
|
510
|
-
),
|
|
511
|
-
children: contentWrapper(body)
|
|
512
|
-
}
|
|
513
|
-
)
|
|
514
|
-
] }) });
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// src/components/form-dialog.tsx
|
|
518
|
-
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
519
|
-
function FormDialogLayout({
|
|
520
|
-
title,
|
|
521
|
-
children,
|
|
522
|
-
onSubmit,
|
|
523
|
-
submitLabel = "Salvar",
|
|
524
|
-
cancelLabel = "Cancelar",
|
|
525
|
-
onCancel,
|
|
526
|
-
isSubmitting = false,
|
|
527
|
-
isDisabled = false
|
|
528
|
-
}) {
|
|
529
|
-
return /* @__PURE__ */ jsxs10("form", { onSubmit, children: [
|
|
530
|
-
/* @__PURE__ */ jsx11("div", { className: "flex flex-col space-y-1.5 text-center sm:text-left", children: /* @__PURE__ */ jsx11("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: title }) }),
|
|
531
|
-
/* @__PURE__ */ jsx11("div", { className: "space-y-4 py-4", children }),
|
|
532
|
-
/* @__PURE__ */ jsxs10("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
|
|
533
|
-
/* @__PURE__ */ jsx11(
|
|
534
|
-
"button",
|
|
535
|
-
{
|
|
536
|
-
type: "button",
|
|
537
|
-
onClick: onCancel,
|
|
538
|
-
className: "inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
539
|
-
children: cancelLabel
|
|
540
|
-
}
|
|
541
|
-
),
|
|
542
|
-
/* @__PURE__ */ jsx11(
|
|
543
|
-
"button",
|
|
544
|
-
{
|
|
545
|
-
type: "submit",
|
|
546
|
-
disabled: isSubmitting || isDisabled,
|
|
547
|
-
className: "inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
548
|
-
children: isSubmitting ? "Salvando..." : submitLabel
|
|
549
|
-
}
|
|
550
|
-
)
|
|
551
|
-
] })
|
|
552
|
-
] });
|
|
553
|
-
}
|
|
554
|
-
function FormDialog({ onSubmit, ...rest }) {
|
|
555
|
-
return /* @__PURE__ */ jsx11(
|
|
556
|
-
BaseDialog,
|
|
557
|
-
{
|
|
558
|
-
...rest,
|
|
559
|
-
contentWrapper: onSubmit ? (content) => /* @__PURE__ */ jsx11("form", { onSubmit, className: "flex min-h-0 flex-1 flex-col", children: content }) : void 0
|
|
560
|
-
}
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// src/components/auth-card.tsx
|
|
565
|
-
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
566
|
-
function AuthCard({ title, description, children, footer }) {
|
|
567
|
-
return /* @__PURE__ */ jsx12("div", { className: "flex min-h-screen items-center justify-center px-4", children: /* @__PURE__ */ jsxs11("div", { className: "w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm", children: [
|
|
568
|
-
/* @__PURE__ */ jsxs11("div", { className: "mb-6 text-center", children: [
|
|
569
|
-
/* @__PURE__ */ jsx12("h1", { className: "text-2xl font-semibold tracking-tight", children: title }),
|
|
570
|
-
description && /* @__PURE__ */ jsx12("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
|
|
571
|
-
] }),
|
|
572
|
-
/* @__PURE__ */ jsx12("div", { className: "space-y-4", children }),
|
|
573
|
-
footer && /* @__PURE__ */ jsx12("div", { className: "mt-4", children: footer })
|
|
574
|
-
] }) });
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
// src/components/pagination.tsx
|
|
578
|
-
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
579
|
-
var navButtonClass = "inline-flex h-8 items-center justify-center rounded-md border border-input bg-background px-3 text-xs font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50";
|
|
580
|
-
function Pagination({
|
|
581
|
-
page,
|
|
582
|
-
onPageChange,
|
|
583
|
-
hasNextPage,
|
|
584
|
-
hasPreviousPage,
|
|
585
|
-
totalPages,
|
|
586
|
-
showPageSizeSelector = false,
|
|
587
|
-
pageSize,
|
|
588
|
-
onPageSizeChange,
|
|
589
|
-
pageSizeOptions,
|
|
590
|
-
className
|
|
591
|
-
}) {
|
|
592
|
-
return /* @__PURE__ */ jsxs12(
|
|
593
|
-
"div",
|
|
594
|
-
{
|
|
595
|
-
className: `flex items-center ${showPageSizeSelector ? "justify-between" : "justify-end"} gap-4 ${className ?? ""}`,
|
|
596
|
-
children: [
|
|
597
|
-
showPageSizeSelector && /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
598
|
-
/* @__PURE__ */ jsx13("label", { htmlFor: "pagination-page-size", className: "text-sm text-muted-foreground", children: "Itens por p\xE1gina" }),
|
|
599
|
-
/* @__PURE__ */ jsx13(
|
|
600
|
-
"select",
|
|
601
|
-
{
|
|
602
|
-
id: "pagination-page-size",
|
|
603
|
-
value: pageSize,
|
|
604
|
-
onChange: (e) => onPageSizeChange?.(Number(e.target.value)),
|
|
605
|
-
className: "h-8 rounded-md border border-input bg-background px-2 text-xs font-medium shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring cursor-pointer",
|
|
606
|
-
children: (pageSizeOptions ?? []).map((size) => /* @__PURE__ */ jsx13("option", { value: size, children: size }, size))
|
|
607
|
-
}
|
|
608
|
-
)
|
|
609
|
-
] }),
|
|
610
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-4", children: [
|
|
611
|
-
/* @__PURE__ */ jsx13(
|
|
612
|
-
"button",
|
|
613
|
-
{
|
|
614
|
-
type: "button",
|
|
615
|
-
onClick: () => onPageChange(page - 1),
|
|
616
|
-
disabled: !hasPreviousPage,
|
|
617
|
-
className: navButtonClass,
|
|
618
|
-
children: "Anterior"
|
|
619
|
-
}
|
|
620
|
-
),
|
|
621
|
-
/* @__PURE__ */ jsxs12("span", { className: "text-sm text-muted-foreground", children: [
|
|
622
|
-
"P\xE1gina ",
|
|
623
|
-
page,
|
|
624
|
-
totalPages ? ` de ${totalPages}` : ""
|
|
625
|
-
] }),
|
|
626
|
-
/* @__PURE__ */ jsx13(
|
|
627
|
-
"button",
|
|
628
|
-
{
|
|
629
|
-
type: "button",
|
|
630
|
-
onClick: () => onPageChange(page + 1),
|
|
631
|
-
disabled: !hasNextPage,
|
|
632
|
-
className: navButtonClass,
|
|
633
|
-
children: "Pr\xF3ximo"
|
|
634
|
-
}
|
|
635
|
-
)
|
|
636
|
-
] })
|
|
637
|
-
]
|
|
638
|
-
}
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// src/components/table-skeleton.tsx
|
|
643
|
-
import { Fragment as Fragment2, jsx as jsx14 } from "react/jsx-runtime";
|
|
644
|
-
function TableSkeleton({ rows = 5, columns = 4 }) {
|
|
645
|
-
return /* @__PURE__ */ jsx14(Fragment2, { children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx14("tr", { className: "border-b transition-colors", children: Array.from({ length: columns }).map((_2, j) => /* @__PURE__ */ jsx14("td", { className: "p-4 align-middle", children: /* @__PURE__ */ jsx14("div", { className: "h-5 w-full animate-pulse rounded bg-muted" }) }, j)) }, i)) });
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// src/components/search-input.tsx
|
|
649
|
-
import * as React3 from "react";
|
|
650
|
-
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
651
|
-
var SearchInput = React3.forwardRef(
|
|
652
|
-
({ containerClassName, className, ...props }, ref) => {
|
|
653
|
-
return /* @__PURE__ */ jsxs13("div", { className: `relative flex-1 ${containerClassName ?? ""}`, children: [
|
|
654
|
-
/* @__PURE__ */ jsxs13(
|
|
655
|
-
"svg",
|
|
656
|
-
{
|
|
657
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
658
|
-
width: "16",
|
|
659
|
-
height: "16",
|
|
660
|
-
viewBox: "0 0 24 24",
|
|
661
|
-
fill: "none",
|
|
662
|
-
stroke: "currentColor",
|
|
663
|
-
strokeWidth: "2",
|
|
664
|
-
strokeLinecap: "round",
|
|
665
|
-
strokeLinejoin: "round",
|
|
666
|
-
className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground",
|
|
667
|
-
children: [
|
|
668
|
-
/* @__PURE__ */ jsx15("circle", { cx: "11", cy: "11", r: "8" }),
|
|
669
|
-
/* @__PURE__ */ jsx15("path", { d: "m21 21-4.3-4.3" })
|
|
670
|
-
]
|
|
671
|
-
}
|
|
672
|
-
),
|
|
673
|
-
/* @__PURE__ */ jsx15(
|
|
674
|
-
"input",
|
|
675
|
-
{
|
|
676
|
-
ref,
|
|
677
|
-
type: "text",
|
|
678
|
-
className: `flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 pl-10 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 ${className ?? ""}`,
|
|
679
|
-
...props
|
|
680
|
-
}
|
|
681
|
-
)
|
|
682
|
-
] });
|
|
683
|
-
}
|
|
684
|
-
);
|
|
685
|
-
SearchInput.displayName = "SearchInput";
|
|
686
|
-
|
|
687
|
-
// src/components/password-input.tsx
|
|
688
|
-
import { Eye, EyeOff } from "lucide-react";
|
|
689
|
-
import * as React4 from "react";
|
|
690
|
-
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
691
|
-
var PasswordInput = React4.forwardRef(({ containerClassName, className, ...props }, ref) => {
|
|
692
|
-
const [visible, setVisible] = React4.useState(false);
|
|
693
|
-
return /* @__PURE__ */ jsxs14("div", { className: `relative ${containerClassName ?? ""}`, children: [
|
|
694
|
-
/* @__PURE__ */ jsx16(
|
|
695
|
-
"input",
|
|
450
|
+
/* @__PURE__ */ jsx6(
|
|
451
|
+
Dialog.Content,
|
|
696
452
|
{
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
453
|
+
onCloseAutoFocus: () => {
|
|
454
|
+
document.body.style.pointerEvents = "";
|
|
455
|
+
},
|
|
456
|
+
className: cn(
|
|
457
|
+
"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none",
|
|
458
|
+
"inset-x-0 bottom-0 rounded-t-2xl",
|
|
459
|
+
"sm:inset-x-auto sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:max-h-[92vh] sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-lg",
|
|
460
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
461
|
+
sizeClasses[size],
|
|
462
|
+
className
|
|
463
|
+
),
|
|
464
|
+
children: contentWrapper(body)
|
|
701
465
|
}
|
|
702
|
-
)
|
|
703
|
-
|
|
466
|
+
)
|
|
467
|
+
] }) });
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/components/color-picker.tsx
|
|
471
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
472
|
+
import { ChevronsUpDown, X as X2 } from "lucide-react";
|
|
473
|
+
import * as React3 from "react";
|
|
474
|
+
import {
|
|
475
|
+
HexAlphaColorPicker,
|
|
476
|
+
HexColorInput,
|
|
477
|
+
HexColorPicker
|
|
478
|
+
} from "react-colorful";
|
|
479
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
480
|
+
function ColorPicker({
|
|
481
|
+
value,
|
|
482
|
+
onChange,
|
|
483
|
+
placeholder = "Selecionar cor",
|
|
484
|
+
clearable = true,
|
|
485
|
+
alpha = false,
|
|
486
|
+
disabled,
|
|
487
|
+
id,
|
|
488
|
+
className,
|
|
489
|
+
"aria-invalid": ariaInvalid,
|
|
490
|
+
"aria-describedby": ariaDescribedby
|
|
491
|
+
}) {
|
|
492
|
+
const [open, setOpen] = React3.useState(false);
|
|
493
|
+
const color = value || "";
|
|
494
|
+
const showClear = clearable && !!color && !disabled;
|
|
495
|
+
const clear = (event) => {
|
|
496
|
+
event.stopPropagation();
|
|
497
|
+
event.preventDefault();
|
|
498
|
+
onChange("");
|
|
499
|
+
};
|
|
500
|
+
return /* @__PURE__ */ jsxs6(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
501
|
+
/* @__PURE__ */ jsx7(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
|
|
704
502
|
"button",
|
|
705
503
|
{
|
|
706
504
|
type: "button",
|
|
707
|
-
|
|
708
|
-
"aria-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
505
|
+
id,
|
|
506
|
+
"aria-invalid": ariaInvalid,
|
|
507
|
+
"aria-describedby": ariaDescribedby,
|
|
508
|
+
disabled,
|
|
509
|
+
className: cn(
|
|
510
|
+
"flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors hover:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive",
|
|
511
|
+
className
|
|
512
|
+
),
|
|
513
|
+
children: [
|
|
514
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-2 truncate", children: [
|
|
515
|
+
/* @__PURE__ */ jsx7(
|
|
516
|
+
"span",
|
|
517
|
+
{
|
|
518
|
+
"aria-hidden": true,
|
|
519
|
+
className: "h-5 w-5 shrink-0 rounded border border-border bg-[length:8px_8px] bg-[position:0_0,4px_4px]",
|
|
520
|
+
style: {
|
|
521
|
+
// The checkerboard stays under the color layer so a
|
|
522
|
+
// translucent value reads as translucent in the swatch.
|
|
523
|
+
backgroundImage: `${color ? `linear-gradient(${color},${color}),` : ""}linear-gradient(45deg,var(--color-muted) 25%,transparent 25%,transparent 75%,var(--color-muted) 75%),linear-gradient(45deg,var(--color-muted) 25%,transparent 25%,transparent 75%,var(--color-muted) 75%)`
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
),
|
|
527
|
+
/* @__PURE__ */ jsx7("span", { className: cn("truncate", !color && "text-muted-foreground"), children: color || placeholder })
|
|
528
|
+
] }),
|
|
529
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex shrink-0 items-center gap-1", children: [
|
|
530
|
+
showClear && // Not a <button> — nesting one inside the trigger button is
|
|
531
|
+
// invalid HTML.
|
|
532
|
+
/* @__PURE__ */ jsx7(
|
|
533
|
+
"span",
|
|
534
|
+
{
|
|
535
|
+
role: "button",
|
|
536
|
+
tabIndex: 0,
|
|
537
|
+
"aria-label": "Limpar cor",
|
|
538
|
+
onClick: clear,
|
|
539
|
+
onKeyDown: (event) => {
|
|
540
|
+
if (event.key === "Enter" || event.key === " ") clear(event);
|
|
541
|
+
},
|
|
542
|
+
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
543
|
+
children: /* @__PURE__ */ jsx7(X2, { className: "h-3.5 w-3.5" })
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ jsx7(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
547
|
+
] })
|
|
548
|
+
]
|
|
712
549
|
}
|
|
713
|
-
)
|
|
550
|
+
) }),
|
|
551
|
+
/* @__PURE__ */ jsx7(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
|
|
552
|
+
PopoverPrimitive.Content,
|
|
553
|
+
{
|
|
554
|
+
align: "start",
|
|
555
|
+
sideOffset: 4,
|
|
556
|
+
className: "z-50 w-56 rounded-md border bg-popover p-3 text-popover-foreground shadow-md",
|
|
557
|
+
children: /* @__PURE__ */ jsxs6("div", { className: "mh-color-picker flex flex-col gap-3", children: [
|
|
558
|
+
alpha ? /* @__PURE__ */ jsx7(HexAlphaColorPicker, { color, onChange }) : /* @__PURE__ */ jsx7(HexColorPicker, { color, onChange }),
|
|
559
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
560
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm text-muted-foreground", children: "#" }),
|
|
561
|
+
/* @__PURE__ */ jsx7(
|
|
562
|
+
HexColorInput,
|
|
563
|
+
{
|
|
564
|
+
color,
|
|
565
|
+
onChange,
|
|
566
|
+
prefixed: false,
|
|
567
|
+
alpha,
|
|
568
|
+
className: "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm uppercase shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
] })
|
|
572
|
+
] })
|
|
573
|
+
}
|
|
574
|
+
) })
|
|
714
575
|
] });
|
|
715
|
-
}
|
|
716
|
-
PasswordInput.displayName = "PasswordInput";
|
|
576
|
+
}
|
|
717
577
|
|
|
718
578
|
// src/components/combobox.tsx
|
|
719
|
-
import * as
|
|
579
|
+
import * as PopoverPrimitive2 from "@radix-ui/react-popover";
|
|
720
580
|
import { Command as CommandPrimitive } from "cmdk";
|
|
721
|
-
import { Check, ChevronsUpDown, Loader2, Plus, Search } from "lucide-react";
|
|
722
|
-
import * as
|
|
723
|
-
import { Drawer as
|
|
581
|
+
import { Check, ChevronsUpDown as ChevronsUpDown2, Loader2, Plus, Search } from "lucide-react";
|
|
582
|
+
import * as React5 from "react";
|
|
583
|
+
import { Drawer as DrawerPrimitive2 } from "vaul";
|
|
724
584
|
|
|
725
585
|
// src/hooks/use-infinite-scroll-sentinel.ts
|
|
726
|
-
import * as
|
|
586
|
+
import * as React4 from "react";
|
|
727
587
|
function useInfiniteScrollSentinel({
|
|
728
588
|
enabled,
|
|
729
589
|
loading,
|
|
730
590
|
onLoadMore
|
|
731
591
|
}) {
|
|
732
|
-
const listRef =
|
|
733
|
-
const sentinelRef =
|
|
734
|
-
const loadingRef =
|
|
735
|
-
const onLoadMoreRef =
|
|
736
|
-
|
|
592
|
+
const listRef = React4.useRef(null);
|
|
593
|
+
const sentinelRef = React4.useRef(null);
|
|
594
|
+
const loadingRef = React4.useRef(loading);
|
|
595
|
+
const onLoadMoreRef = React4.useRef(onLoadMore);
|
|
596
|
+
React4.useEffect(() => {
|
|
737
597
|
loadingRef.current = loading;
|
|
738
598
|
onLoadMoreRef.current = onLoadMore;
|
|
739
599
|
});
|
|
740
|
-
|
|
600
|
+
React4.useEffect(() => {
|
|
741
601
|
if (!enabled) return;
|
|
742
602
|
const root = listRef.current;
|
|
743
603
|
const sentinel = sentinelRef.current;
|
|
744
604
|
if (!root || !sentinel) return;
|
|
745
605
|
const observer = new IntersectionObserver(
|
|
746
|
-
(entries) => {
|
|
747
|
-
if (entries[0]?.isIntersecting && !loadingRef.current) {
|
|
748
|
-
onLoadMoreRef.current?.();
|
|
749
|
-
}
|
|
750
|
-
},
|
|
751
|
-
{ root, rootMargin: "0px 0px 100px 0px" }
|
|
752
|
-
);
|
|
753
|
-
observer.observe(sentinel);
|
|
754
|
-
return () => observer.disconnect();
|
|
755
|
-
}, [enabled]);
|
|
756
|
-
return { listRef, sentinelRef };
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// src/components/combobox.tsx
|
|
760
|
-
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
761
|
-
function Combobox({
|
|
762
|
-
options,
|
|
763
|
-
value,
|
|
764
|
-
onChange,
|
|
765
|
-
placeholder = "Selecione...",
|
|
766
|
-
searchPlaceholder = "Buscar...",
|
|
767
|
-
emptyMessage = "Nenhum resultado encontrado.",
|
|
768
|
-
disabled,
|
|
769
|
-
id,
|
|
770
|
-
className,
|
|
771
|
-
"aria-invalid": ariaInvalid,
|
|
772
|
-
"aria-describedby": ariaDescribedby,
|
|
773
|
-
onSearchChange,
|
|
774
|
-
onLoadMore,
|
|
775
|
-
loading,
|
|
776
|
-
hasMore,
|
|
777
|
-
selectedOption,
|
|
778
|
-
creatable,
|
|
779
|
-
formatCreateLabel
|
|
780
|
-
}) {
|
|
781
|
-
const [open, setOpen] = React6.useState(false);
|
|
782
|
-
const [search, setSearch] = React6.useState("");
|
|
783
|
-
const isDesktop = useIsDesktop();
|
|
784
|
-
const isServer = onSearchChange !== void 0;
|
|
785
|
-
const selected = selectedOption?.value === value ? selectedOption : options.find((option) => option.value === value) ?? (creatable && value ? { value, label: value } : void 0);
|
|
786
|
-
const handleOpenChange = (next) => {
|
|
787
|
-
setOpen(next);
|
|
788
|
-
if (!next) setSearch("");
|
|
789
|
-
};
|
|
790
|
-
const handleSelect = (next) => {
|
|
791
|
-
onChange(next);
|
|
792
|
-
handleOpenChange(false);
|
|
793
|
-
};
|
|
794
|
-
const handleSearchChange = (next) => {
|
|
795
|
-
setSearch(next);
|
|
796
|
-
onSearchChange?.(next);
|
|
797
|
-
};
|
|
798
|
-
const trimmedSearch = search.trim();
|
|
799
|
-
const showCreate = !!creatable && trimmedSearch.length > 0 && !options.some(
|
|
800
|
-
(option) => option.value.toLowerCase() === trimmedSearch.toLowerCase()
|
|
801
|
-
);
|
|
802
|
-
const { listRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
803
|
-
enabled: isServer && !!hasMore,
|
|
804
|
-
loading,
|
|
805
|
-
onLoadMore
|
|
806
|
-
});
|
|
807
|
-
const trigger = /* @__PURE__ */ jsxs15(
|
|
808
|
-
"button",
|
|
809
|
-
{
|
|
810
|
-
type: "button",
|
|
811
|
-
id,
|
|
812
|
-
role: "combobox",
|
|
813
|
-
"aria-expanded": open,
|
|
814
|
-
"aria-invalid": ariaInvalid,
|
|
815
|
-
"aria-describedby": ariaDescribedby,
|
|
816
|
-
disabled,
|
|
817
|
-
className: cn(
|
|
818
|
-
"flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors hover:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive",
|
|
819
|
-
className
|
|
820
|
-
),
|
|
821
|
-
children: [
|
|
822
|
-
/* @__PURE__ */ jsx17("span", { className: cn("truncate", !selected && "text-muted-foreground"), children: selected ? selected.label : placeholder }),
|
|
823
|
-
/* @__PURE__ */ jsx17(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
824
|
-
]
|
|
825
|
-
}
|
|
826
|
-
);
|
|
827
|
-
const command = /* @__PURE__ */ jsxs15(
|
|
828
|
-
CommandPrimitive,
|
|
829
|
-
{
|
|
830
|
-
shouldFilter: !isServer,
|
|
831
|
-
className: "flex h-full w-full flex-col overflow-hidden",
|
|
832
|
-
children: [
|
|
833
|
-
/* @__PURE__ */ jsxs15("div", { className: "flex items-center border-b px-3", children: [
|
|
834
|
-
/* @__PURE__ */ jsx17(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
835
|
-
/* @__PURE__ */ jsx17(
|
|
836
|
-
CommandPrimitive.Input,
|
|
837
|
-
{
|
|
838
|
-
placeholder: searchPlaceholder,
|
|
839
|
-
onValueChange: isServer || creatable ? handleSearchChange : void 0,
|
|
840
|
-
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
841
|
-
}
|
|
842
|
-
)
|
|
843
|
-
] }),
|
|
844
|
-
/* @__PURE__ */ jsxs15(
|
|
845
|
-
CommandPrimitive.List,
|
|
846
|
-
{
|
|
847
|
-
ref: listRef,
|
|
848
|
-
className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
|
|
849
|
-
children: [
|
|
850
|
-
!isServer && !showCreate && /* @__PURE__ */ jsx17(CommandPrimitive.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
851
|
-
showCreate && /* @__PURE__ */ jsxs15(
|
|
852
|
-
CommandPrimitive.Item,
|
|
853
|
-
{
|
|
854
|
-
value: trimmedSearch,
|
|
855
|
-
onSelect: () => handleSelect(trimmedSearch),
|
|
856
|
-
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground sm:py-1.5",
|
|
857
|
-
children: [
|
|
858
|
-
/* @__PURE__ */ jsx17(Plus, { className: "h-4 w-4 shrink-0" }),
|
|
859
|
-
/* @__PURE__ */ jsx17("span", { className: "truncate", children: (formatCreateLabel ?? ((text) => `Usar "${text}"`))(
|
|
860
|
-
trimmedSearch
|
|
861
|
-
) })
|
|
862
|
-
]
|
|
863
|
-
}
|
|
864
|
-
),
|
|
865
|
-
options.map((option) => /* @__PURE__ */ jsxs15(
|
|
866
|
-
CommandPrimitive.Item,
|
|
867
|
-
{
|
|
868
|
-
value: isServer ? option.value : option.label,
|
|
869
|
-
disabled: option.disabled,
|
|
870
|
-
onSelect: () => handleSelect(option.value),
|
|
871
|
-
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
872
|
-
children: [
|
|
873
|
-
/* @__PURE__ */ jsx17(
|
|
874
|
-
Check,
|
|
875
|
-
{
|
|
876
|
-
className: cn(
|
|
877
|
-
"h-4 w-4 shrink-0",
|
|
878
|
-
value === option.value ? "opacity-100" : "opacity-0"
|
|
879
|
-
)
|
|
880
|
-
}
|
|
881
|
-
),
|
|
882
|
-
/* @__PURE__ */ jsx17("span", { className: "truncate", children: option.label })
|
|
883
|
-
]
|
|
884
|
-
},
|
|
885
|
-
option.value
|
|
886
|
-
)),
|
|
887
|
-
isServer && !loading && options.length === 0 && /* @__PURE__ */ jsx17("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
888
|
-
isServer && loading && /* @__PURE__ */ jsx17("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx17(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
889
|
-
isServer && hasMore && /* @__PURE__ */ jsx17("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1" })
|
|
890
|
-
]
|
|
891
|
-
}
|
|
892
|
-
)
|
|
893
|
-
]
|
|
894
|
-
}
|
|
895
|
-
);
|
|
896
|
-
if (isDesktop) {
|
|
897
|
-
return /* @__PURE__ */ jsxs15(PopoverPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
|
|
898
|
-
/* @__PURE__ */ jsx17(PopoverPrimitive.Trigger, { asChild: true, children: trigger }),
|
|
899
|
-
/* @__PURE__ */ jsx17(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx17(
|
|
900
|
-
PopoverPrimitive.Content,
|
|
901
|
-
{
|
|
902
|
-
align: "start",
|
|
903
|
-
sideOffset: 4,
|
|
904
|
-
className: "pointer-events-auto z-50 overflow-hidden rounded-md border bg-popover p-0 text-popover-foreground shadow-md",
|
|
905
|
-
style: { width: "var(--radix-popover-trigger-width)" },
|
|
906
|
-
children: command
|
|
606
|
+
(entries) => {
|
|
607
|
+
if (entries[0]?.isIntersecting && !loadingRef.current) {
|
|
608
|
+
onLoadMoreRef.current?.();
|
|
907
609
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
/* @__PURE__ */ jsxs15(DrawerPrimitive.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
|
|
916
|
-
/* @__PURE__ */ jsx17(DrawerPrimitive.Title, { className: "sr-only", children: placeholder }),
|
|
917
|
-
/* @__PURE__ */ jsx17("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
918
|
-
command
|
|
919
|
-
] })
|
|
920
|
-
] })
|
|
921
|
-
] });
|
|
610
|
+
},
|
|
611
|
+
{ root, rootMargin: "0px 0px 100px 0px" }
|
|
612
|
+
);
|
|
613
|
+
observer.observe(sentinel);
|
|
614
|
+
return () => observer.disconnect();
|
|
615
|
+
}, [enabled]);
|
|
616
|
+
return { listRef, sentinelRef };
|
|
922
617
|
}
|
|
923
618
|
|
|
924
|
-
// src/components/
|
|
925
|
-
import
|
|
926
|
-
|
|
927
|
-
import { Check as Check2, ChevronsUpDown as ChevronsUpDown2, Loader2 as Loader22, Search as Search2, X as X2 } from "lucide-react";
|
|
928
|
-
import * as React7 from "react";
|
|
929
|
-
import { Drawer as DrawerPrimitive2 } from "vaul";
|
|
930
|
-
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
931
|
-
function MultiCombobox({
|
|
619
|
+
// src/components/combobox.tsx
|
|
620
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
621
|
+
function Combobox({
|
|
932
622
|
options,
|
|
933
623
|
value,
|
|
934
624
|
onChange,
|
|
@@ -944,130 +634,119 @@ function MultiCombobox({
|
|
|
944
634
|
onLoadMore,
|
|
945
635
|
loading,
|
|
946
636
|
hasMore,
|
|
947
|
-
|
|
637
|
+
selectedOption,
|
|
638
|
+
creatable,
|
|
639
|
+
formatCreateLabel
|
|
948
640
|
}) {
|
|
949
|
-
const [open, setOpen] =
|
|
641
|
+
const [open, setOpen] = React5.useState(false);
|
|
642
|
+
const [search, setSearch] = React5.useState("");
|
|
950
643
|
const isDesktop = useIsDesktop();
|
|
951
644
|
const isServer = onSearchChange !== void 0;
|
|
952
|
-
const
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
645
|
+
const selected = selectedOption?.value === value ? selectedOption : options.find((option) => option.value === value) ?? (creatable && value ? { value, label: value } : void 0);
|
|
646
|
+
const handleOpenChange = (next) => {
|
|
647
|
+
setOpen(next);
|
|
648
|
+
if (!next) setSearch("");
|
|
649
|
+
};
|
|
650
|
+
const handleSelect = (next) => {
|
|
651
|
+
onChange(next);
|
|
652
|
+
handleOpenChange(false);
|
|
653
|
+
};
|
|
654
|
+
const handleSearchChange = (next) => {
|
|
655
|
+
setSearch(next);
|
|
656
|
+
onSearchChange?.(next);
|
|
657
|
+
};
|
|
658
|
+
const trimmedSearch = search.trim();
|
|
659
|
+
const showCreate = !!creatable && trimmedSearch.length > 0 && !options.some(
|
|
660
|
+
(option) => option.value.toLowerCase() === trimmedSearch.toLowerCase()
|
|
661
|
+
);
|
|
958
662
|
const { listRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
959
663
|
enabled: isServer && !!hasMore,
|
|
960
664
|
loading,
|
|
961
665
|
onLoadMore
|
|
962
666
|
});
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
|
|
966
|
-
);
|
|
967
|
-
};
|
|
968
|
-
const removeValue = (optionValue) => {
|
|
969
|
-
onChange(value.filter((v) => v !== optionValue));
|
|
970
|
-
};
|
|
971
|
-
const trigger = /* @__PURE__ */ jsxs16(
|
|
972
|
-
"div",
|
|
667
|
+
const trigger = /* @__PURE__ */ jsxs7(
|
|
668
|
+
"button",
|
|
973
669
|
{
|
|
670
|
+
type: "button",
|
|
974
671
|
id,
|
|
975
672
|
role: "combobox",
|
|
976
|
-
tabIndex: disabled ? -1 : 0,
|
|
977
673
|
"aria-expanded": open,
|
|
978
674
|
"aria-invalid": ariaInvalid,
|
|
979
675
|
"aria-describedby": ariaDescribedby,
|
|
980
|
-
|
|
981
|
-
onKeyDown: (event) => {
|
|
982
|
-
if (disabled) return;
|
|
983
|
-
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
|
|
984
|
-
event.preventDefault();
|
|
985
|
-
setOpen(true);
|
|
986
|
-
}
|
|
987
|
-
},
|
|
676
|
+
disabled,
|
|
988
677
|
className: cn(
|
|
989
|
-
"flex
|
|
678
|
+
"flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors hover:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive",
|
|
990
679
|
className
|
|
991
680
|
),
|
|
992
681
|
children: [
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
{
|
|
996
|
-
className: "inline-flex items-center gap-1 rounded bg-secondary px-1.5 py-0.5 text-xs text-secondary-foreground",
|
|
997
|
-
children: [
|
|
998
|
-
option.label,
|
|
999
|
-
/* @__PURE__ */ jsx18(
|
|
1000
|
-
"button",
|
|
1001
|
-
{
|
|
1002
|
-
type: "button",
|
|
1003
|
-
tabIndex: -1,
|
|
1004
|
-
"aria-label": `Remover ${option.label}`,
|
|
1005
|
-
onClick: (event) => {
|
|
1006
|
-
event.stopPropagation();
|
|
1007
|
-
removeValue(option.value);
|
|
1008
|
-
},
|
|
1009
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1010
|
-
className: "rounded-sm opacity-60 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1011
|
-
children: /* @__PURE__ */ jsx18(X2, { className: "h-3 w-3" })
|
|
1012
|
-
}
|
|
1013
|
-
)
|
|
1014
|
-
]
|
|
1015
|
-
},
|
|
1016
|
-
option.value
|
|
1017
|
-
)),
|
|
1018
|
-
/* @__PURE__ */ jsx18(ChevronsUpDown2, { className: "ml-auto h-4 w-4 shrink-0 opacity-50" })
|
|
682
|
+
/* @__PURE__ */ jsx8("span", { className: cn("truncate", !selected && "text-muted-foreground"), children: selected ? selected.label : placeholder }),
|
|
683
|
+
/* @__PURE__ */ jsx8(ChevronsUpDown2, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
1019
684
|
]
|
|
1020
685
|
}
|
|
1021
686
|
);
|
|
1022
|
-
const command = /* @__PURE__ */
|
|
1023
|
-
|
|
687
|
+
const command = /* @__PURE__ */ jsxs7(
|
|
688
|
+
CommandPrimitive,
|
|
1024
689
|
{
|
|
1025
690
|
shouldFilter: !isServer,
|
|
1026
691
|
className: "flex h-full w-full flex-col overflow-hidden",
|
|
1027
692
|
children: [
|
|
1028
|
-
/* @__PURE__ */
|
|
1029
|
-
/* @__PURE__ */
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
|
|
693
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center border-b px-3", children: [
|
|
694
|
+
/* @__PURE__ */ jsx8(Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
695
|
+
/* @__PURE__ */ jsx8(
|
|
696
|
+
CommandPrimitive.Input,
|
|
1032
697
|
{
|
|
1033
698
|
placeholder: searchPlaceholder,
|
|
1034
|
-
onValueChange: isServer ?
|
|
699
|
+
onValueChange: isServer || creatable ? handleSearchChange : void 0,
|
|
1035
700
|
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
1036
701
|
}
|
|
1037
702
|
)
|
|
1038
703
|
] }),
|
|
1039
|
-
/* @__PURE__ */
|
|
1040
|
-
|
|
704
|
+
/* @__PURE__ */ jsxs7(
|
|
705
|
+
CommandPrimitive.List,
|
|
1041
706
|
{
|
|
1042
707
|
ref: listRef,
|
|
1043
708
|
className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
|
|
1044
709
|
children: [
|
|
1045
|
-
!isServer && /* @__PURE__ */
|
|
1046
|
-
|
|
1047
|
-
|
|
710
|
+
!isServer && !showCreate && /* @__PURE__ */ jsx8(CommandPrimitive.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
711
|
+
showCreate && /* @__PURE__ */ jsxs7(
|
|
712
|
+
CommandPrimitive.Item,
|
|
713
|
+
{
|
|
714
|
+
value: trimmedSearch,
|
|
715
|
+
onSelect: () => handleSelect(trimmedSearch),
|
|
716
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground sm:py-1.5",
|
|
717
|
+
children: [
|
|
718
|
+
/* @__PURE__ */ jsx8(Plus, { className: "h-4 w-4 shrink-0" }),
|
|
719
|
+
/* @__PURE__ */ jsx8("span", { className: "truncate", children: (formatCreateLabel ?? ((text) => `Usar "${text}"`))(
|
|
720
|
+
trimmedSearch
|
|
721
|
+
) })
|
|
722
|
+
]
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
options.map((option) => /* @__PURE__ */ jsxs7(
|
|
726
|
+
CommandPrimitive.Item,
|
|
1048
727
|
{
|
|
1049
728
|
value: isServer ? option.value : option.label,
|
|
1050
729
|
disabled: option.disabled,
|
|
1051
|
-
onSelect: () =>
|
|
730
|
+
onSelect: () => handleSelect(option.value),
|
|
1052
731
|
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
1053
732
|
children: [
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
|
|
733
|
+
/* @__PURE__ */ jsx8(
|
|
734
|
+
Check,
|
|
1056
735
|
{
|
|
1057
736
|
className: cn(
|
|
1058
737
|
"h-4 w-4 shrink-0",
|
|
1059
|
-
value
|
|
738
|
+
value === option.value ? "opacity-100" : "opacity-0"
|
|
1060
739
|
)
|
|
1061
740
|
}
|
|
1062
741
|
),
|
|
1063
|
-
/* @__PURE__ */
|
|
742
|
+
/* @__PURE__ */ jsx8("span", { className: "truncate", children: option.label })
|
|
1064
743
|
]
|
|
1065
744
|
},
|
|
1066
745
|
option.value
|
|
1067
746
|
)),
|
|
1068
|
-
isServer && !loading && options.length === 0 && /* @__PURE__ */
|
|
1069
|
-
isServer && loading && /* @__PURE__ */
|
|
1070
|
-
isServer && hasMore && /* @__PURE__ */
|
|
747
|
+
isServer && !loading && options.length === 0 && /* @__PURE__ */ jsx8("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
748
|
+
isServer && loading && /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx8(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
749
|
+
isServer && hasMore && /* @__PURE__ */ jsx8("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1" })
|
|
1071
750
|
]
|
|
1072
751
|
}
|
|
1073
752
|
)
|
|
@@ -1075,9 +754,9 @@ function MultiCombobox({
|
|
|
1075
754
|
}
|
|
1076
755
|
);
|
|
1077
756
|
if (isDesktop) {
|
|
1078
|
-
return /* @__PURE__ */
|
|
1079
|
-
/* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
757
|
+
return /* @__PURE__ */ jsxs7(PopoverPrimitive2.Root, { open, onOpenChange: handleOpenChange, children: [
|
|
758
|
+
/* @__PURE__ */ jsx8(PopoverPrimitive2.Trigger, { asChild: true, children: trigger }),
|
|
759
|
+
/* @__PURE__ */ jsx8(PopoverPrimitive2.Portal, { children: /* @__PURE__ */ jsx8(
|
|
1081
760
|
PopoverPrimitive2.Content,
|
|
1082
761
|
{
|
|
1083
762
|
align: "start",
|
|
@@ -1089,137 +768,127 @@ function MultiCombobox({
|
|
|
1089
768
|
) })
|
|
1090
769
|
] });
|
|
1091
770
|
}
|
|
1092
|
-
return /* @__PURE__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
1096
|
-
/* @__PURE__ */
|
|
1097
|
-
/* @__PURE__ */
|
|
1098
|
-
/* @__PURE__ */
|
|
771
|
+
return /* @__PURE__ */ jsxs7(DrawerPrimitive2.Root, { open, onOpenChange: handleOpenChange, children: [
|
|
772
|
+
/* @__PURE__ */ jsx8(DrawerPrimitive2.Trigger, { asChild: true, children: trigger }),
|
|
773
|
+
/* @__PURE__ */ jsxs7(DrawerPrimitive2.Portal, { children: [
|
|
774
|
+
/* @__PURE__ */ jsx8(DrawerPrimitive2.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
775
|
+
/* @__PURE__ */ jsxs7(DrawerPrimitive2.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
|
|
776
|
+
/* @__PURE__ */ jsx8(DrawerPrimitive2.Title, { className: "sr-only", children: placeholder }),
|
|
777
|
+
/* @__PURE__ */ jsx8("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
1099
778
|
command
|
|
1100
779
|
] })
|
|
1101
780
|
] })
|
|
1102
781
|
] });
|
|
1103
782
|
}
|
|
1104
783
|
|
|
1105
|
-
// src/components/
|
|
1106
|
-
import * as
|
|
1107
|
-
import {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
alpha = false,
|
|
1121
|
-
disabled,
|
|
1122
|
-
id,
|
|
1123
|
-
className,
|
|
1124
|
-
"aria-invalid": ariaInvalid,
|
|
1125
|
-
"aria-describedby": ariaDescribedby
|
|
784
|
+
// src/components/confirm-dialog.tsx
|
|
785
|
+
import * as AlertDialog from "@radix-ui/react-alert-dialog";
|
|
786
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
787
|
+
function ConfirmDialog({
|
|
788
|
+
open,
|
|
789
|
+
onOpenChange,
|
|
790
|
+
onConfirm,
|
|
791
|
+
title,
|
|
792
|
+
description,
|
|
793
|
+
confirmLabel = "Confirmar",
|
|
794
|
+
cancelLabel = "Cancelar",
|
|
795
|
+
loading = false,
|
|
796
|
+
variant = "default",
|
|
797
|
+
blurBackdrop = true,
|
|
798
|
+
backdropClassName
|
|
1126
799
|
}) {
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
const clear = (event) => {
|
|
1131
|
-
event.stopPropagation();
|
|
1132
|
-
event.preventDefault();
|
|
1133
|
-
onChange("");
|
|
1134
|
-
};
|
|
1135
|
-
return /* @__PURE__ */ jsxs17(PopoverPrimitive3.Root, { open, onOpenChange: setOpen, children: [
|
|
1136
|
-
/* @__PURE__ */ jsx19(PopoverPrimitive3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs17(
|
|
1137
|
-
"button",
|
|
800
|
+
return /* @__PURE__ */ jsx9(AlertDialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs8(AlertDialog.Portal, { children: [
|
|
801
|
+
/* @__PURE__ */ jsx9(
|
|
802
|
+
AlertDialog.Overlay,
|
|
1138
803
|
{
|
|
1139
|
-
type: "button",
|
|
1140
|
-
id,
|
|
1141
|
-
"aria-invalid": ariaInvalid,
|
|
1142
|
-
"aria-describedby": ariaDescribedby,
|
|
1143
|
-
disabled,
|
|
1144
804
|
className: cn(
|
|
1145
|
-
"
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
/* @__PURE__ */ jsxs17("span", { className: "flex items-center gap-2 truncate", children: [
|
|
1150
|
-
/* @__PURE__ */ jsx19(
|
|
1151
|
-
"span",
|
|
1152
|
-
{
|
|
1153
|
-
"aria-hidden": true,
|
|
1154
|
-
className: "h-5 w-5 shrink-0 rounded border border-border bg-[length:8px_8px] bg-[position:0_0,4px_4px]",
|
|
1155
|
-
style: {
|
|
1156
|
-
// The checkerboard stays under the color layer so a
|
|
1157
|
-
// translucent value reads as translucent in the swatch.
|
|
1158
|
-
backgroundImage: `${color ? `linear-gradient(${color},${color}),` : ""}linear-gradient(45deg,var(--color-muted) 25%,transparent 25%,transparent 75%,var(--color-muted) 75%),linear-gradient(45deg,var(--color-muted) 25%,transparent 25%,transparent 75%,var(--color-muted) 75%)`
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
),
|
|
1162
|
-
/* @__PURE__ */ jsx19("span", { className: cn("truncate", !color && "text-muted-foreground"), children: color || placeholder })
|
|
1163
|
-
] }),
|
|
1164
|
-
/* @__PURE__ */ jsxs17("span", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1165
|
-
showClear && // Not a <button> — nesting one inside the trigger button is
|
|
1166
|
-
// invalid HTML.
|
|
1167
|
-
/* @__PURE__ */ jsx19(
|
|
1168
|
-
"span",
|
|
1169
|
-
{
|
|
1170
|
-
role: "button",
|
|
1171
|
-
tabIndex: 0,
|
|
1172
|
-
"aria-label": "Limpar cor",
|
|
1173
|
-
onClick: clear,
|
|
1174
|
-
onKeyDown: (event) => {
|
|
1175
|
-
if (event.key === "Enter" || event.key === " ") clear(event);
|
|
1176
|
-
},
|
|
1177
|
-
className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1178
|
-
children: /* @__PURE__ */ jsx19(X3, { className: "h-3.5 w-3.5" })
|
|
1179
|
-
}
|
|
1180
|
-
),
|
|
1181
|
-
/* @__PURE__ */ jsx19(ChevronsUpDown3, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
1182
|
-
] })
|
|
1183
|
-
]
|
|
1184
|
-
}
|
|
1185
|
-
) }),
|
|
1186
|
-
/* @__PURE__ */ jsx19(PopoverPrimitive3.Portal, { children: /* @__PURE__ */ jsx19(
|
|
1187
|
-
PopoverPrimitive3.Content,
|
|
1188
|
-
{
|
|
1189
|
-
align: "start",
|
|
1190
|
-
sideOffset: 4,
|
|
1191
|
-
className: "z-50 w-56 rounded-md border bg-popover p-3 text-popover-foreground shadow-md",
|
|
1192
|
-
children: /* @__PURE__ */ jsxs17("div", { className: "mh-color-picker flex flex-col gap-3", children: [
|
|
1193
|
-
alpha ? /* @__PURE__ */ jsx19(HexAlphaColorPicker, { color, onChange }) : /* @__PURE__ */ jsx19(HexColorPicker, { color, onChange }),
|
|
1194
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
1195
|
-
/* @__PURE__ */ jsx19("span", { className: "text-sm text-muted-foreground", children: "#" }),
|
|
1196
|
-
/* @__PURE__ */ jsx19(
|
|
1197
|
-
HexColorInput,
|
|
1198
|
-
{
|
|
1199
|
-
color,
|
|
1200
|
-
onChange,
|
|
1201
|
-
prefixed: false,
|
|
1202
|
-
alpha,
|
|
1203
|
-
className: "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm uppercase shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1204
|
-
}
|
|
1205
|
-
)
|
|
1206
|
-
] })
|
|
1207
|
-
] })
|
|
805
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
806
|
+
blurBackdrop && "backdrop-blur-sm",
|
|
807
|
+
backdropClassName
|
|
808
|
+
)
|
|
1208
809
|
}
|
|
1209
|
-
)
|
|
810
|
+
),
|
|
811
|
+
/* @__PURE__ */ jsxs8(AlertDialog.Content, { className: "fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", children: [
|
|
812
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col space-y-2 text-center sm:text-left", children: [
|
|
813
|
+
/* @__PURE__ */ jsx9(AlertDialog.Title, { className: "text-lg font-semibold", children: title }),
|
|
814
|
+
/* @__PURE__ */ jsx9(AlertDialog.Description, { className: "text-sm text-muted-foreground", children: description })
|
|
815
|
+
] }),
|
|
816
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
|
|
817
|
+
/* @__PURE__ */ jsx9(AlertDialog.Cancel, { className: "inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer", children: cancelLabel }),
|
|
818
|
+
/* @__PURE__ */ jsx9(
|
|
819
|
+
AlertDialog.Action,
|
|
820
|
+
{
|
|
821
|
+
onClick: onConfirm,
|
|
822
|
+
disabled: loading,
|
|
823
|
+
className: `inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 cursor-pointer ${variant === "destructive" ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : "bg-primary text-primary-foreground hover:bg-primary/90"}`,
|
|
824
|
+
children: loading ? "Aguarde..." : confirmLabel
|
|
825
|
+
}
|
|
826
|
+
)
|
|
827
|
+
] })
|
|
828
|
+
] })
|
|
829
|
+
] }) });
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// src/components/data-table-wrapper.tsx
|
|
833
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
834
|
+
function DataTableWrapper({
|
|
835
|
+
children,
|
|
836
|
+
isEmpty,
|
|
837
|
+
isLoading,
|
|
838
|
+
emptyIcon,
|
|
839
|
+
emptyTitle = "Nenhum registro encontrado",
|
|
840
|
+
emptyDescription,
|
|
841
|
+
page,
|
|
842
|
+
onPageChange,
|
|
843
|
+
hasNextPage = false,
|
|
844
|
+
hasPreviousPage = false
|
|
845
|
+
}) {
|
|
846
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
|
|
847
|
+
/* @__PURE__ */ jsx10("div", { className: "overflow-x-auto rounded-md border", children }),
|
|
848
|
+
!isLoading && isEmpty && /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
849
|
+
emptyIcon && /* @__PURE__ */ jsx10("div", { className: "mb-4 text-muted-foreground", children: emptyIcon }),
|
|
850
|
+
/* @__PURE__ */ jsx10("h3", { className: "text-lg font-semibold tracking-tight", children: emptyTitle }),
|
|
851
|
+
emptyDescription && /* @__PURE__ */ jsx10("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: emptyDescription })
|
|
852
|
+
] }),
|
|
853
|
+
page !== void 0 && onPageChange && /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-end gap-4", children: [
|
|
854
|
+
/* @__PURE__ */ jsx10(
|
|
855
|
+
"button",
|
|
856
|
+
{
|
|
857
|
+
type: "button",
|
|
858
|
+
onClick: () => onPageChange(page - 1),
|
|
859
|
+
disabled: !hasPreviousPage,
|
|
860
|
+
className: "inline-flex h-8 items-center justify-center rounded-md border border-input bg-background px-3 text-xs font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
861
|
+
children: "Anterior"
|
|
862
|
+
}
|
|
863
|
+
),
|
|
864
|
+
/* @__PURE__ */ jsxs9("span", { className: "text-sm text-muted-foreground", children: [
|
|
865
|
+
"P\xE1gina ",
|
|
866
|
+
page
|
|
867
|
+
] }),
|
|
868
|
+
/* @__PURE__ */ jsx10(
|
|
869
|
+
"button",
|
|
870
|
+
{
|
|
871
|
+
type: "button",
|
|
872
|
+
onClick: () => onPageChange(page + 1),
|
|
873
|
+
disabled: !hasNextPage,
|
|
874
|
+
className: "inline-flex h-8 items-center justify-center rounded-md border border-input bg-background px-3 text-xs font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
875
|
+
children: "Pr\xF3ximo"
|
|
876
|
+
}
|
|
877
|
+
)
|
|
878
|
+
] })
|
|
1210
879
|
] });
|
|
1211
880
|
}
|
|
1212
881
|
|
|
1213
882
|
// src/components/date-picker.tsx
|
|
1214
|
-
import * as
|
|
883
|
+
import * as PopoverPrimitive3 from "@radix-ui/react-popover";
|
|
1215
884
|
import { InputMask } from "@react-input/mask";
|
|
1216
|
-
import { format, isValid, parse } from "date-fns";
|
|
885
|
+
import { endOfYear, format, isValid, parse, subYears } from "date-fns";
|
|
1217
886
|
import { ptBR } from "date-fns/locale";
|
|
1218
|
-
import { CalendarIcon, ChevronLeft, ChevronRight, Clock } from "lucide-react";
|
|
1219
|
-
import * as
|
|
887
|
+
import { CalendarIcon, ChevronDown, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight2, Clock } from "lucide-react";
|
|
888
|
+
import * as React6 from "react";
|
|
1220
889
|
import { DayPicker } from "react-day-picker";
|
|
1221
890
|
import { Drawer as DrawerPrimitive3 } from "vaul";
|
|
1222
|
-
import { Fragment as
|
|
891
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1223
892
|
var DATE_MASK = "__/__/____";
|
|
1224
893
|
var TIME_MASK = "__:__";
|
|
1225
894
|
var MASK_REPLACEMENT = { _: /\d/ };
|
|
@@ -1261,15 +930,18 @@ function toMatchers(minDate, maxDate, disabledDates) {
|
|
|
1261
930
|
}
|
|
1262
931
|
var triggerInputClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 pr-10 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive";
|
|
1263
932
|
var fieldInputClass = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
1264
|
-
var
|
|
933
|
+
var navButtonClass = "inline-flex size-(--cell-size) shrink-0 select-none items-center justify-center rounded-md p-0 transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:opacity-50";
|
|
1265
934
|
var calendarClassNames = {
|
|
1266
935
|
months: "relative flex flex-col gap-4",
|
|
1267
936
|
month: "flex w-full flex-col gap-4",
|
|
1268
937
|
month_caption: "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
|
|
1269
|
-
caption_label: "text-sm font-medium select-none",
|
|
938
|
+
caption_label: "flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm font-medium select-none [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
|
|
939
|
+
dropdowns: "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
|
|
940
|
+
dropdown_root: "relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
|
|
941
|
+
dropdown: "absolute inset-0 bg-popover opacity-0",
|
|
1270
942
|
nav: "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
1271
|
-
button_previous:
|
|
1272
|
-
button_next:
|
|
943
|
+
button_previous: navButtonClass,
|
|
944
|
+
button_next: navButtonClass,
|
|
1273
945
|
month_grid: "w-full border-collapse",
|
|
1274
946
|
weekdays: "flex",
|
|
1275
947
|
weekday: "flex-1 select-none rounded-md text-[0.8rem] font-normal text-muted-foreground",
|
|
@@ -1282,8 +954,13 @@ var calendarClassNames = {
|
|
|
1282
954
|
hidden: "invisible"
|
|
1283
955
|
};
|
|
1284
956
|
var calendarComponents = {
|
|
1285
|
-
Chevron: ({ orientation }) =>
|
|
957
|
+
Chevron: ({ orientation }) => {
|
|
958
|
+
if (orientation === "left") return /* @__PURE__ */ jsx11(ChevronLeft2, { className: "size-4" });
|
|
959
|
+
if (orientation === "right") return /* @__PURE__ */ jsx11(ChevronRight2, { className: "size-4" });
|
|
960
|
+
return /* @__PURE__ */ jsx11(ChevronDown, { className: "size-4" });
|
|
961
|
+
}
|
|
1286
962
|
};
|
|
963
|
+
var formatMonthDropdown = (date) => date.toLocaleString("pt-BR", { month: "short" });
|
|
1287
964
|
function DatePickerImpl({
|
|
1288
965
|
value,
|
|
1289
966
|
onChange,
|
|
@@ -1299,15 +976,17 @@ function DatePickerImpl({
|
|
|
1299
976
|
"aria-describedby": ariaDescribedby
|
|
1300
977
|
}) {
|
|
1301
978
|
const isDesktop = useIsDesktop();
|
|
1302
|
-
const triggerRef =
|
|
1303
|
-
const [open, setOpenRaw] =
|
|
1304
|
-
const [focused, setFocused] =
|
|
1305
|
-
const [editText, setEditText] =
|
|
1306
|
-
const [pendingDate, setPendingDate] =
|
|
1307
|
-
const [pendingTime, setPendingTime] =
|
|
979
|
+
const triggerRef = React6.useRef(null);
|
|
980
|
+
const [open, setOpenRaw] = React6.useState(false);
|
|
981
|
+
const [focused, setFocused] = React6.useState(false);
|
|
982
|
+
const [editText, setEditText] = React6.useState("");
|
|
983
|
+
const [pendingDate, setPendingDate] = React6.useState();
|
|
984
|
+
const [pendingTime, setPendingTime] = React6.useState("");
|
|
1308
985
|
const committedDate = withTime ? dateTimeToDate(value) : dateOnlyToDate(value);
|
|
1309
986
|
const displayValue = displayFor(value, withTime);
|
|
1310
987
|
const matchers = toMatchers(minDate, maxDate, disabledDates);
|
|
988
|
+
const startMonth = dateOnlyToDate(minDate) ?? subYears(/* @__PURE__ */ new Date(), 100);
|
|
989
|
+
const endMonth = dateOnlyToDate(maxDate) ?? endOfYear(/* @__PURE__ */ new Date());
|
|
1311
990
|
const setOpen = (next) => {
|
|
1312
991
|
setOpenRaw(next);
|
|
1313
992
|
if (next) {
|
|
@@ -1363,8 +1042,8 @@ function DatePickerImpl({
|
|
|
1363
1042
|
}
|
|
1364
1043
|
};
|
|
1365
1044
|
const canApply = withTime && !!pendingDate && !!parseStrict(pendingTime, TIME_FORMAT);
|
|
1366
|
-
const trigger = /* @__PURE__ */
|
|
1367
|
-
/* @__PURE__ */
|
|
1045
|
+
const trigger = /* @__PURE__ */ jsxs10("div", { ref: triggerRef, className: "relative", children: [
|
|
1046
|
+
/* @__PURE__ */ jsx11(
|
|
1368
1047
|
InputMask,
|
|
1369
1048
|
{
|
|
1370
1049
|
id,
|
|
@@ -1384,7 +1063,7 @@ function DatePickerImpl({
|
|
|
1384
1063
|
className: cn(triggerInputClass, className)
|
|
1385
1064
|
}
|
|
1386
1065
|
),
|
|
1387
|
-
/* @__PURE__ */
|
|
1066
|
+
/* @__PURE__ */ jsx11(
|
|
1388
1067
|
"button",
|
|
1389
1068
|
{
|
|
1390
1069
|
type: "button",
|
|
@@ -1394,16 +1073,20 @@ function DatePickerImpl({
|
|
|
1394
1073
|
"aria-expanded": open,
|
|
1395
1074
|
onClick: () => setOpen(!open),
|
|
1396
1075
|
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground transition-colors hover:text-foreground disabled:pointer-events-none disabled:opacity-50",
|
|
1397
|
-
children: withTime ? /* @__PURE__ */
|
|
1076
|
+
children: withTime ? /* @__PURE__ */ jsx11(Clock, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx11(CalendarIcon, { className: "h-4 w-4" })
|
|
1398
1077
|
}
|
|
1399
1078
|
)
|
|
1400
1079
|
] });
|
|
1401
|
-
const content = /* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1080
|
+
const content = /* @__PURE__ */ jsxs10("div", { className: withTime ? "p-3" : "", children: [
|
|
1081
|
+
/* @__PURE__ */ jsx11(
|
|
1403
1082
|
DayPicker,
|
|
1404
1083
|
{
|
|
1405
1084
|
mode: "single",
|
|
1406
1085
|
locale: ptBR,
|
|
1086
|
+
captionLayout: "dropdown",
|
|
1087
|
+
formatters: { formatMonthDropdown },
|
|
1088
|
+
startMonth,
|
|
1089
|
+
endMonth,
|
|
1407
1090
|
selected: withTime ? pendingDate : committedDate,
|
|
1408
1091
|
defaultMonth: (withTime ? pendingDate : committedDate) ?? /* @__PURE__ */ new Date(),
|
|
1409
1092
|
onSelect: (date) => date && handleCalendarSelect(date),
|
|
@@ -1413,10 +1096,10 @@ function DatePickerImpl({
|
|
|
1413
1096
|
components: calendarComponents
|
|
1414
1097
|
}
|
|
1415
1098
|
),
|
|
1416
|
-
withTime && /* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1419
|
-
/* @__PURE__ */
|
|
1099
|
+
withTime && /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
1100
|
+
/* @__PURE__ */ jsxs10("div", { className: "mt-2 flex items-center gap-2 border-t pt-3", children: [
|
|
1101
|
+
/* @__PURE__ */ jsx11("span", { className: "text-sm text-muted-foreground", children: "Hor\xE1rio" }),
|
|
1102
|
+
/* @__PURE__ */ jsx11(
|
|
1420
1103
|
InputMask,
|
|
1421
1104
|
{
|
|
1422
1105
|
mask: TIME_MASK,
|
|
@@ -1429,7 +1112,7 @@ function DatePickerImpl({
|
|
|
1429
1112
|
}
|
|
1430
1113
|
)
|
|
1431
1114
|
] }),
|
|
1432
|
-
/* @__PURE__ */
|
|
1115
|
+
/* @__PURE__ */ jsx11(
|
|
1433
1116
|
"button",
|
|
1434
1117
|
{
|
|
1435
1118
|
type: "button",
|
|
@@ -1442,10 +1125,10 @@ function DatePickerImpl({
|
|
|
1442
1125
|
] })
|
|
1443
1126
|
] });
|
|
1444
1127
|
if (isDesktop) {
|
|
1445
|
-
return /* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
|
|
1128
|
+
return /* @__PURE__ */ jsxs10(PopoverPrimitive3.Root, { open, onOpenChange: setOpen, children: [
|
|
1129
|
+
/* @__PURE__ */ jsx11(PopoverPrimitive3.Anchor, { asChild: true, children: trigger }),
|
|
1130
|
+
/* @__PURE__ */ jsx11(PopoverPrimitive3.Portal, { children: /* @__PURE__ */ jsx11(
|
|
1131
|
+
PopoverPrimitive3.Content,
|
|
1449
1132
|
{
|
|
1450
1133
|
align: "start",
|
|
1451
1134
|
sideOffset: 4,
|
|
@@ -1459,11 +1142,11 @@ function DatePickerImpl({
|
|
|
1459
1142
|
) })
|
|
1460
1143
|
] });
|
|
1461
1144
|
}
|
|
1462
|
-
return /* @__PURE__ */
|
|
1145
|
+
return /* @__PURE__ */ jsxs10(DrawerPrimitive3.Root, { open, onOpenChange: setOpen, children: [
|
|
1463
1146
|
trigger,
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1147
|
+
/* @__PURE__ */ jsxs10(DrawerPrimitive3.Portal, { children: [
|
|
1148
|
+
/* @__PURE__ */ jsx11(DrawerPrimitive3.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
1149
|
+
/* @__PURE__ */ jsxs10(
|
|
1467
1150
|
DrawerPrimitive3.Content,
|
|
1468
1151
|
{
|
|
1469
1152
|
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
@@ -1472,9 +1155,9 @@ function DatePickerImpl({
|
|
|
1472
1155
|
},
|
|
1473
1156
|
className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none",
|
|
1474
1157
|
children: [
|
|
1475
|
-
/* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1158
|
+
/* @__PURE__ */ jsx11(DrawerPrimitive3.Title, { className: "sr-only", children: withTime ? "Selecione a data e o hor\xE1rio" : "Selecione a data" }),
|
|
1159
|
+
/* @__PURE__ */ jsx11("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
1160
|
+
/* @__PURE__ */ jsx11("div", { className: "flex justify-center overflow-y-auto pb-4", children: content })
|
|
1478
1161
|
]
|
|
1479
1162
|
}
|
|
1480
1163
|
)
|
|
@@ -1482,88 +1165,254 @@ function DatePickerImpl({
|
|
|
1482
1165
|
] });
|
|
1483
1166
|
}
|
|
1484
1167
|
function DatePicker(props) {
|
|
1485
|
-
return /* @__PURE__ */
|
|
1168
|
+
return /* @__PURE__ */ jsx11(DatePickerImpl, { ...props });
|
|
1486
1169
|
}
|
|
1487
1170
|
function DateTimePicker(props) {
|
|
1488
|
-
return /* @__PURE__ */
|
|
1171
|
+
return /* @__PURE__ */ jsx11(DatePickerImpl, { ...props, withTime: true });
|
|
1489
1172
|
}
|
|
1490
1173
|
|
|
1491
|
-
// src/components/
|
|
1492
|
-
import { jsx as
|
|
1493
|
-
function
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1174
|
+
// src/components/empty-state.tsx
|
|
1175
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1176
|
+
function EmptyState({ icon, title, description, action, className }) {
|
|
1177
|
+
return /* @__PURE__ */ jsxs11("div", { className: `flex flex-col items-center justify-center py-16 text-center ${className ?? ""}`, children: [
|
|
1178
|
+
icon && /* @__PURE__ */ jsx12("div", { className: "mb-4 text-muted-foreground", children: icon }),
|
|
1179
|
+
/* @__PURE__ */ jsx12("h3", { className: "text-lg font-semibold tracking-tight", children: title }),
|
|
1180
|
+
description && /* @__PURE__ */ jsx12("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: description }),
|
|
1181
|
+
action && /* @__PURE__ */ jsx12("div", { className: "mt-4", children: action })
|
|
1182
|
+
] });
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/components/filter-toolbar.tsx
|
|
1186
|
+
import * as PopoverPrimitive4 from "@radix-ui/react-popover";
|
|
1187
|
+
import { ChevronDown as ChevronDown2, X as X3 } from "lucide-react";
|
|
1188
|
+
import * as React7 from "react";
|
|
1189
|
+
import { Drawer as DrawerPrimitive4 } from "vaul";
|
|
1190
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1191
|
+
function FilterToolbar({
|
|
1192
|
+
children,
|
|
1193
|
+
isFilterActive = false,
|
|
1194
|
+
onClear,
|
|
1195
|
+
clearLabel = "Limpar filtros",
|
|
1196
|
+
className
|
|
1197
|
+
}) {
|
|
1198
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("mb-6 flex flex-wrap items-center gap-2", className), children: [
|
|
1199
|
+
children,
|
|
1200
|
+
isFilterActive && onClear && /* @__PURE__ */ jsxs12(
|
|
1201
|
+
"button",
|
|
1202
|
+
{
|
|
1203
|
+
type: "button",
|
|
1204
|
+
onClick: onClear,
|
|
1205
|
+
className: "inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md px-2.5 text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
1206
|
+
children: [
|
|
1207
|
+
/* @__PURE__ */ jsx13(X3, { className: "h-4 w-4" }),
|
|
1208
|
+
clearLabel
|
|
1209
|
+
]
|
|
1210
|
+
}
|
|
1211
|
+
)
|
|
1212
|
+
] });
|
|
1213
|
+
}
|
|
1214
|
+
function FilterPopover({
|
|
1215
|
+
label,
|
|
1216
|
+
icon: Icon,
|
|
1217
|
+
active = false,
|
|
1218
|
+
badge,
|
|
1219
|
+
contentClassName,
|
|
1220
|
+
align = "start",
|
|
1221
|
+
title,
|
|
1222
|
+
children
|
|
1223
|
+
}) {
|
|
1224
|
+
const [open, setOpen] = React7.useState(false);
|
|
1225
|
+
const isDesktop = useIsDesktop();
|
|
1226
|
+
const close = React7.useCallback(() => setOpen(false), []);
|
|
1227
|
+
const content = typeof children === "function" ? children({ close }) : children;
|
|
1228
|
+
const trigger = /* @__PURE__ */ jsxs12(
|
|
1229
|
+
"button",
|
|
1230
|
+
{
|
|
1231
|
+
type: "button",
|
|
1232
|
+
"aria-expanded": open,
|
|
1233
|
+
className: cn(
|
|
1234
|
+
"inline-flex h-9 shrink-0 cursor-pointer items-center gap-1.5 rounded-md border border-input bg-transparent px-3 text-sm shadow-sm transition-colors hover:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1235
|
+
active ? "border-ring/60 text-foreground" : "text-muted-foreground"
|
|
1236
|
+
),
|
|
1237
|
+
children: [
|
|
1238
|
+
Icon && /* @__PURE__ */ jsx13(Icon, { className: "h-4 w-4 shrink-0 opacity-70" }),
|
|
1239
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate", children: label }),
|
|
1240
|
+
active && badge != null && /* @__PURE__ */ jsx13("span", { className: "inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-medium leading-none text-primary-foreground", children: badge }),
|
|
1241
|
+
/* @__PURE__ */ jsx13(ChevronDown2, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
1242
|
+
]
|
|
1243
|
+
}
|
|
1244
|
+
);
|
|
1245
|
+
if (isDesktop) {
|
|
1246
|
+
return /* @__PURE__ */ jsxs12(PopoverPrimitive4.Root, { open, onOpenChange: setOpen, children: [
|
|
1247
|
+
/* @__PURE__ */ jsx13(PopoverPrimitive4.Trigger, { asChild: true, children: trigger }),
|
|
1248
|
+
/* @__PURE__ */ jsx13(PopoverPrimitive4.Portal, { children: /* @__PURE__ */ jsx13(
|
|
1249
|
+
PopoverPrimitive4.Content,
|
|
1250
|
+
{
|
|
1251
|
+
align,
|
|
1252
|
+
sideOffset: 4,
|
|
1253
|
+
onInteractOutside: (event) => {
|
|
1254
|
+
const target = event.target;
|
|
1255
|
+
if (target?.closest("[data-radix-popper-content-wrapper]")) {
|
|
1256
|
+
event.preventDefault();
|
|
1257
|
+
}
|
|
1258
|
+
},
|
|
1259
|
+
className: cn(
|
|
1260
|
+
"pointer-events-auto z-50 w-60 overflow-hidden rounded-md border bg-popover p-0 text-popover-foreground shadow-md",
|
|
1261
|
+
contentClassName
|
|
1262
|
+
),
|
|
1263
|
+
children: content
|
|
1264
|
+
}
|
|
1265
|
+
) })
|
|
1502
1266
|
] });
|
|
1503
1267
|
}
|
|
1504
|
-
return /* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1268
|
+
return /* @__PURE__ */ jsxs12(DrawerPrimitive4.Root, { open, onOpenChange: setOpen, children: [
|
|
1269
|
+
/* @__PURE__ */ jsx13(DrawerPrimitive4.Trigger, { asChild: true, children: trigger }),
|
|
1270
|
+
/* @__PURE__ */ jsxs12(DrawerPrimitive4.Portal, { children: [
|
|
1271
|
+
/* @__PURE__ */ jsx13(DrawerPrimitive4.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
1272
|
+
/* @__PURE__ */ jsxs12(DrawerPrimitive4.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
|
|
1273
|
+
/* @__PURE__ */ jsx13(DrawerPrimitive4.Title, { className: "sr-only", children: title ?? label }),
|
|
1274
|
+
/* @__PURE__ */ jsx13("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
1275
|
+
/* @__PURE__ */ jsx13("div", { className: "overflow-y-auto p-2", children: content })
|
|
1276
|
+
] })
|
|
1277
|
+
] })
|
|
1278
|
+
] });
|
|
1279
|
+
}
|
|
1280
|
+
function FilterOptionList({
|
|
1281
|
+
options,
|
|
1282
|
+
value,
|
|
1283
|
+
onChange,
|
|
1284
|
+
multiple = false,
|
|
1285
|
+
clearable = false,
|
|
1286
|
+
clearLabel = "Limpar"
|
|
1287
|
+
}) {
|
|
1288
|
+
const selected = Array.isArray(value) ? value : value ? [value] : [];
|
|
1289
|
+
const hasSelection = selected.length > 0;
|
|
1290
|
+
const toggle = (optionValue) => {
|
|
1291
|
+
if (!multiple) {
|
|
1292
|
+
onChange(optionValue);
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
onChange(
|
|
1296
|
+
selected.includes(optionValue) ? selected.filter((v) => v !== optionValue) : [...selected, optionValue]
|
|
1297
|
+
);
|
|
1298
|
+
};
|
|
1299
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col p-1", children: [
|
|
1300
|
+
options.map((option) => {
|
|
1301
|
+
const isChecked = selected.includes(option.value);
|
|
1302
|
+
return /* @__PURE__ */ jsxs12(
|
|
1303
|
+
"button",
|
|
1304
|
+
{
|
|
1305
|
+
type: "button",
|
|
1306
|
+
onClick: () => toggle(option.value),
|
|
1307
|
+
className: "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
1308
|
+
children: [
|
|
1309
|
+
option.dotClassName && /* @__PURE__ */ jsx13(
|
|
1310
|
+
"span",
|
|
1311
|
+
{
|
|
1312
|
+
className: cn(
|
|
1313
|
+
"h-2 w-2 shrink-0 rounded-full",
|
|
1314
|
+
option.dotClassName
|
|
1315
|
+
)
|
|
1316
|
+
}
|
|
1317
|
+
),
|
|
1318
|
+
/* @__PURE__ */ jsx13("span", { className: "flex-1 truncate", children: option.label }),
|
|
1319
|
+
isChecked && /* @__PURE__ */ jsx13("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-primary" })
|
|
1320
|
+
]
|
|
1321
|
+
},
|
|
1322
|
+
option.value
|
|
1323
|
+
);
|
|
1324
|
+
}),
|
|
1325
|
+
clearable && hasSelection && /* @__PURE__ */ jsx13(
|
|
1326
|
+
"button",
|
|
1327
|
+
{
|
|
1328
|
+
type: "button",
|
|
1329
|
+
onClick: () => onChange(multiple ? [] : ""),
|
|
1330
|
+
className: "mt-1 border-t px-2 pt-1.5 pb-0.5 text-center text-xs text-muted-foreground transition-colors hover:text-foreground",
|
|
1331
|
+
children: clearLabel
|
|
1332
|
+
}
|
|
1333
|
+
)
|
|
1511
1334
|
] });
|
|
1512
1335
|
}
|
|
1513
1336
|
|
|
1514
|
-
// src/components/
|
|
1515
|
-
import { jsx as
|
|
1516
|
-
function
|
|
1337
|
+
// src/components/form-dialog.tsx
|
|
1338
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1339
|
+
function FormDialogLayout({
|
|
1340
|
+
title,
|
|
1517
1341
|
children,
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
onPageChange,
|
|
1525
|
-
hasNextPage = false,
|
|
1526
|
-
hasPreviousPage = false
|
|
1342
|
+
onSubmit,
|
|
1343
|
+
submitLabel = "Salvar",
|
|
1344
|
+
cancelLabel = "Cancelar",
|
|
1345
|
+
onCancel,
|
|
1346
|
+
isSubmitting = false,
|
|
1347
|
+
isDisabled = false
|
|
1527
1348
|
}) {
|
|
1528
|
-
return /* @__PURE__ */
|
|
1529
|
-
/* @__PURE__ */
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
emptyDescription && /* @__PURE__ */ jsx22("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: emptyDescription })
|
|
1534
|
-
] }),
|
|
1535
|
-
page !== void 0 && onPageChange && /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-end gap-4", children: [
|
|
1536
|
-
/* @__PURE__ */ jsx22(
|
|
1349
|
+
return /* @__PURE__ */ jsxs13("form", { onSubmit, children: [
|
|
1350
|
+
/* @__PURE__ */ jsx14("div", { className: "flex flex-col space-y-1.5 text-center sm:text-left", children: /* @__PURE__ */ jsx14("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: title }) }),
|
|
1351
|
+
/* @__PURE__ */ jsx14("div", { className: "space-y-4 py-4", children }),
|
|
1352
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", children: [
|
|
1353
|
+
/* @__PURE__ */ jsx14(
|
|
1537
1354
|
"button",
|
|
1538
1355
|
{
|
|
1539
1356
|
type: "button",
|
|
1540
|
-
onClick:
|
|
1541
|
-
disabled:
|
|
1542
|
-
|
|
1543
|
-
children: "Anterior"
|
|
1357
|
+
onClick: onCancel,
|
|
1358
|
+
className: "inline-flex h-9 items-center justify-center rounded-md border border-input bg-background px-4 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
1359
|
+
children: cancelLabel
|
|
1544
1360
|
}
|
|
1545
1361
|
),
|
|
1546
|
-
/* @__PURE__ */
|
|
1547
|
-
"P\xE1gina ",
|
|
1548
|
-
page
|
|
1549
|
-
] }),
|
|
1550
|
-
/* @__PURE__ */ jsx22(
|
|
1362
|
+
/* @__PURE__ */ jsx14(
|
|
1551
1363
|
"button",
|
|
1552
1364
|
{
|
|
1553
|
-
type: "
|
|
1554
|
-
|
|
1555
|
-
disabled:
|
|
1556
|
-
|
|
1557
|
-
children: "Pr\xF3ximo"
|
|
1365
|
+
type: "submit",
|
|
1366
|
+
disabled: isSubmitting || isDisabled,
|
|
1367
|
+
className: "inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90 cursor-pointer disabled:pointer-events-none disabled:opacity-50",
|
|
1368
|
+
children: isSubmitting ? "Salvando..." : submitLabel
|
|
1558
1369
|
}
|
|
1559
1370
|
)
|
|
1560
1371
|
] })
|
|
1561
1372
|
] });
|
|
1562
1373
|
}
|
|
1374
|
+
function FormDialog({ onSubmit, ...rest }) {
|
|
1375
|
+
return /* @__PURE__ */ jsx14(
|
|
1376
|
+
BaseDialog,
|
|
1377
|
+
{
|
|
1378
|
+
...rest,
|
|
1379
|
+
contentWrapper: onSubmit ? (content) => /* @__PURE__ */ jsx14("form", { onSubmit, className: "flex min-h-0 flex-1 flex-col", children: content }) : void 0
|
|
1380
|
+
}
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// src/components/form-field.tsx
|
|
1385
|
+
import { cloneElement, isValidElement, useId } from "react";
|
|
1386
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1387
|
+
function FormField({ label, htmlFor, error, required, children, className }) {
|
|
1388
|
+
const errorId = useId();
|
|
1389
|
+
const field = error && isValidElement(children) ? cloneElement(children, {
|
|
1390
|
+
"aria-invalid": true,
|
|
1391
|
+
"aria-describedby": [
|
|
1392
|
+
children.props["aria-describedby"],
|
|
1393
|
+
errorId
|
|
1394
|
+
].filter(Boolean).join(" ")
|
|
1395
|
+
}) : children;
|
|
1396
|
+
return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 ${className ?? ""}`, children: [
|
|
1397
|
+
/* @__PURE__ */ jsxs14(
|
|
1398
|
+
"label",
|
|
1399
|
+
{
|
|
1400
|
+
htmlFor,
|
|
1401
|
+
className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
1402
|
+
children: [
|
|
1403
|
+
label,
|
|
1404
|
+
required && /* @__PURE__ */ jsx15("span", { className: "ml-1 text-destructive", children: "*" })
|
|
1405
|
+
]
|
|
1406
|
+
}
|
|
1407
|
+
),
|
|
1408
|
+
field,
|
|
1409
|
+
error && /* @__PURE__ */ jsx15("p", { id: errorId, className: "text-sm text-destructive", children: error })
|
|
1410
|
+
] });
|
|
1411
|
+
}
|
|
1563
1412
|
|
|
1564
1413
|
// src/components/mobile-card-list.tsx
|
|
1565
1414
|
import { useRef as useRef3 } from "react";
|
|
1566
|
-
import { jsx as
|
|
1415
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1567
1416
|
var SCROLL_THRESHOLD = 8;
|
|
1568
1417
|
function MobileCardList({
|
|
1569
1418
|
data,
|
|
@@ -1594,407 +1443,533 @@ function MobileCardList({
|
|
|
1594
1443
|
}
|
|
1595
1444
|
};
|
|
1596
1445
|
if (isLoading) {
|
|
1597
|
-
return /* @__PURE__ */
|
|
1598
|
-
/* @__PURE__ */
|
|
1599
|
-
/* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1446
|
+
return /* @__PURE__ */ jsx16("div", { className: `space-y-3 ${className ?? ""}`, children: Array.from({ length: loadingCount }).map((_, i) => /* @__PURE__ */ jsx16("div", { className: "rounded-xl border p-4", children: /* @__PURE__ */ jsxs15("div", { className: "space-y-3", children: [
|
|
1447
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between", children: [
|
|
1448
|
+
/* @__PURE__ */ jsx16("div", { className: "h-5 w-32 animate-pulse rounded bg-muted" }),
|
|
1449
|
+
/* @__PURE__ */ jsx16("div", { className: "h-5 w-16 animate-pulse rounded bg-muted" })
|
|
1601
1450
|
] }),
|
|
1602
|
-
/* @__PURE__ */
|
|
1603
|
-
/* @__PURE__ */
|
|
1604
|
-
/* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
1451
|
+
/* @__PURE__ */ jsx16("div", { className: "h-4 w-48 animate-pulse rounded bg-muted" }),
|
|
1452
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between", children: [
|
|
1453
|
+
/* @__PURE__ */ jsx16("div", { className: "h-4 w-24 animate-pulse rounded bg-muted" }),
|
|
1454
|
+
/* @__PURE__ */ jsx16("div", { className: "h-4 w-20 animate-pulse rounded bg-muted" })
|
|
1606
1455
|
] })
|
|
1607
|
-
] }) }, i)) });
|
|
1608
|
-
}
|
|
1609
|
-
return /* @__PURE__ */
|
|
1610
|
-
"div",
|
|
1611
|
-
{
|
|
1612
|
-
className: `space-y-3 ${className ?? ""}`,
|
|
1613
|
-
onTouchStart,
|
|
1614
|
-
onTouchMove,
|
|
1615
|
-
onClickCapture,
|
|
1616
|
-
children: data.map((item, index) => /* @__PURE__ */
|
|
1617
|
-
"div",
|
|
1618
|
-
{
|
|
1619
|
-
className: "rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]",
|
|
1620
|
-
children: renderCard(item, index)
|
|
1621
|
-
},
|
|
1622
|
-
keyExtractor(item)
|
|
1623
|
-
))
|
|
1624
|
-
}
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
// src/components/responsive-data-view.tsx
|
|
1629
|
-
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1630
|
-
function ResponsiveDataView({
|
|
1631
|
-
table,
|
|
1632
|
-
cards,
|
|
1633
|
-
isEmpty,
|
|
1634
|
-
isLoading,
|
|
1635
|
-
emptyIcon,
|
|
1636
|
-
emptyTitle = "Nenhum registro encontrado",
|
|
1637
|
-
emptyDescription,
|
|
1638
|
-
pagination
|
|
1639
|
-
}) {
|
|
1640
|
-
return /* @__PURE__ */ jsxs22("div", { className: "space-y-4", children: [
|
|
1641
|
-
/* @__PURE__ */ jsx24("div", { className: "hidden overflow-x-auto rounded-md border md:block", children: table }),
|
|
1642
|
-
/* @__PURE__ */ jsx24("div", { className: "md:hidden", children: cards }),
|
|
1643
|
-
!isLoading && isEmpty && /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
1644
|
-
emptyIcon && /* @__PURE__ */ jsx24("div", { className: "mb-4 text-muted-foreground", children: emptyIcon }),
|
|
1645
|
-
/* @__PURE__ */ jsx24("h3", { className: "text-lg font-semibold tracking-tight", children: emptyTitle }),
|
|
1646
|
-
emptyDescription && /* @__PURE__ */ jsx24("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: emptyDescription })
|
|
1647
|
-
] }),
|
|
1648
|
-
pagination
|
|
1649
|
-
] });
|
|
1650
|
-
}
|
|
1651
|
-
|
|
1652
|
-
// src/components/toaster.tsx
|
|
1653
|
-
import { Toaster as Sonner } from "sonner";
|
|
1654
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1655
|
-
function Toaster(props) {
|
|
1656
|
-
const { theme = "system" } = useTheme();
|
|
1657
|
-
return /* @__PURE__ */ jsx25(
|
|
1658
|
-
Sonner,
|
|
1659
|
-
{
|
|
1660
|
-
theme,
|
|
1661
|
-
className: "toaster group",
|
|
1662
|
-
toastOptions: {
|
|
1663
|
-
classNames: {
|
|
1664
|
-
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md",
|
|
1665
|
-
description: "group-[.toast]:text-muted-foreground",
|
|
1666
|
-
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
1667
|
-
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
|
1668
|
-
success: "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40",
|
|
1669
|
-
error: "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40"
|
|
1670
|
-
}
|
|
1671
|
-
},
|
|
1672
|
-
...props
|
|
1456
|
+
] }) }, i)) });
|
|
1457
|
+
}
|
|
1458
|
+
return /* @__PURE__ */ jsx16(
|
|
1459
|
+
"div",
|
|
1460
|
+
{
|
|
1461
|
+
className: `space-y-3 ${className ?? ""}`,
|
|
1462
|
+
onTouchStart,
|
|
1463
|
+
onTouchMove,
|
|
1464
|
+
onClickCapture,
|
|
1465
|
+
children: data.map((item, index) => /* @__PURE__ */ jsx16(
|
|
1466
|
+
"div",
|
|
1467
|
+
{
|
|
1468
|
+
className: "rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]",
|
|
1469
|
+
children: renderCard(item, index)
|
|
1470
|
+
},
|
|
1471
|
+
keyExtractor(item)
|
|
1472
|
+
))
|
|
1673
1473
|
}
|
|
1674
1474
|
);
|
|
1675
1475
|
}
|
|
1676
1476
|
|
|
1677
|
-
// src/components/
|
|
1678
|
-
import
|
|
1679
|
-
import {
|
|
1680
|
-
|
|
1681
|
-
// src/components/sidebar-nav.tsx
|
|
1682
|
-
import { Fragment as Fragment4 } from "react";
|
|
1477
|
+
// src/components/mode-toggle.tsx
|
|
1478
|
+
import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
|
|
1479
|
+
import { Moon, Sun, Monitor } from "lucide-react";
|
|
1683
1480
|
|
|
1684
|
-
// src/components/
|
|
1685
|
-
import {
|
|
1686
|
-
var defaultRenderLink = ({ children, ...props }) => /* @__PURE__ */ jsx26("a", { ...props, children });
|
|
1481
|
+
// src/components/theme-provider.tsx
|
|
1482
|
+
import { createContext, useContext, useEffect as useEffect4, useState as useState8 } from "react";
|
|
1687
1483
|
|
|
1688
|
-
// src/
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1484
|
+
// src/lib/company-theme.ts
|
|
1485
|
+
var VAR_MAP = {
|
|
1486
|
+
primary: "--color-primary",
|
|
1487
|
+
primaryForeground: "--color-primary-foreground",
|
|
1488
|
+
secondary: "--color-secondary",
|
|
1489
|
+
secondaryForeground: "--color-secondary-foreground",
|
|
1490
|
+
accent: "--color-accent",
|
|
1491
|
+
accentForeground: "--color-accent-foreground",
|
|
1492
|
+
ring: "--color-ring"
|
|
1493
|
+
};
|
|
1494
|
+
function definedTokens(tokens) {
|
|
1495
|
+
if (!tokens) return {};
|
|
1496
|
+
return Object.fromEntries(
|
|
1497
|
+
Object.entries(tokens).filter(([, value]) => value != null)
|
|
1498
|
+
);
|
|
1693
1499
|
}
|
|
1694
|
-
function
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1500
|
+
function applyCompanyTheme(root, companyTheme, mode) {
|
|
1501
|
+
const tokens = companyTheme ? mode === "dark" ? { ...companyTheme.light, ...definedTokens(companyTheme.dark) } : companyTheme.light : {};
|
|
1502
|
+
for (const key of Object.keys(VAR_MAP)) {
|
|
1503
|
+
const value = tokens[key];
|
|
1504
|
+
if (value) root.style.setProperty(VAR_MAP[key], value);
|
|
1505
|
+
else root.style.removeProperty(VAR_MAP[key]);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// src/components/theme-provider.tsx
|
|
1510
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1511
|
+
var initialState = {
|
|
1512
|
+
theme: "system",
|
|
1513
|
+
setTheme: () => null
|
|
1514
|
+
};
|
|
1515
|
+
var ThemeProviderContext = createContext(initialState);
|
|
1516
|
+
function ThemeProvider({
|
|
1517
|
+
children,
|
|
1518
|
+
defaultTheme = "system",
|
|
1519
|
+
storageKey = "ui-theme",
|
|
1520
|
+
companyTheme,
|
|
1521
|
+
...props
|
|
1702
1522
|
}) {
|
|
1703
|
-
const
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
)
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1523
|
+
const [theme, setTheme] = useState8(
|
|
1524
|
+
() => localStorage.getItem(storageKey) || defaultTheme
|
|
1525
|
+
);
|
|
1526
|
+
useEffect4(() => {
|
|
1527
|
+
const root = window.document.documentElement;
|
|
1528
|
+
const applyResolved = (resolved) => {
|
|
1529
|
+
root.classList.remove("light", "dark");
|
|
1530
|
+
root.classList.add(resolved);
|
|
1531
|
+
applyCompanyTheme(root, companyTheme, resolved);
|
|
1532
|
+
};
|
|
1533
|
+
if (theme === "system") {
|
|
1534
|
+
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
1535
|
+
applyResolved(mql.matches ? "dark" : "light");
|
|
1536
|
+
const onChange = (e) => applyResolved(e.matches ? "dark" : "light");
|
|
1537
|
+
mql.addEventListener("change", onChange);
|
|
1538
|
+
return () => mql.removeEventListener("change", onChange);
|
|
1539
|
+
}
|
|
1540
|
+
applyResolved(theme);
|
|
1541
|
+
}, [theme, companyTheme]);
|
|
1542
|
+
const value = {
|
|
1543
|
+
theme,
|
|
1544
|
+
setTheme: (theme2) => {
|
|
1545
|
+
localStorage.setItem(storageKey, theme2);
|
|
1546
|
+
setTheme(theme2);
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
return /* @__PURE__ */ jsx17(ThemeProviderContext.Provider, { ...props, value, children });
|
|
1550
|
+
}
|
|
1551
|
+
function useTheme() {
|
|
1552
|
+
const context = useContext(ThemeProviderContext);
|
|
1553
|
+
if (context === void 0) {
|
|
1554
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
1555
|
+
}
|
|
1556
|
+
return context;
|
|
1723
1557
|
}
|
|
1724
1558
|
|
|
1725
|
-
// src/components/
|
|
1726
|
-
import
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1559
|
+
// src/components/mode-toggle.tsx
|
|
1560
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1561
|
+
function ModeToggle() {
|
|
1562
|
+
const { setTheme } = useTheme();
|
|
1563
|
+
return /* @__PURE__ */ jsxs16(DropdownMenu2.Root, { children: [
|
|
1564
|
+
/* @__PURE__ */ jsx18(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs16(
|
|
1565
|
+
"button",
|
|
1566
|
+
{
|
|
1567
|
+
type: "button",
|
|
1568
|
+
className: "relative inline-flex h-9 w-9 items-center justify-center rounded-md border border-input bg-background text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1569
|
+
"aria-label": "Alternar tema",
|
|
1570
|
+
children: [
|
|
1571
|
+
/* @__PURE__ */ jsx18(Sun, { className: "h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" }),
|
|
1572
|
+
/* @__PURE__ */ jsx18(Moon, { className: "absolute inset-0 m-auto h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" })
|
|
1573
|
+
]
|
|
1574
|
+
}
|
|
1575
|
+
) }),
|
|
1576
|
+
/* @__PURE__ */ jsx18(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs16(
|
|
1577
|
+
DropdownMenu2.Content,
|
|
1578
|
+
{
|
|
1579
|
+
align: "end",
|
|
1580
|
+
className: "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
|
|
1581
|
+
children: [
|
|
1582
|
+
/* @__PURE__ */ jsxs16(
|
|
1583
|
+
DropdownMenu2.Item,
|
|
1584
|
+
{
|
|
1585
|
+
className: "flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent",
|
|
1586
|
+
onClick: () => setTheme("light"),
|
|
1587
|
+
children: [
|
|
1588
|
+
/* @__PURE__ */ jsx18(Sun, { className: "h-4 w-4" }),
|
|
1589
|
+
" Claro"
|
|
1590
|
+
]
|
|
1591
|
+
}
|
|
1592
|
+
),
|
|
1593
|
+
/* @__PURE__ */ jsxs16(
|
|
1594
|
+
DropdownMenu2.Item,
|
|
1595
|
+
{
|
|
1596
|
+
className: "flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent",
|
|
1597
|
+
onClick: () => setTheme("dark"),
|
|
1598
|
+
children: [
|
|
1599
|
+
/* @__PURE__ */ jsx18(Moon, { className: "h-4 w-4" }),
|
|
1600
|
+
" Escuro"
|
|
1601
|
+
]
|
|
1602
|
+
}
|
|
1603
|
+
),
|
|
1604
|
+
/* @__PURE__ */ jsxs16(
|
|
1605
|
+
DropdownMenu2.Item,
|
|
1606
|
+
{
|
|
1607
|
+
className: "flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent",
|
|
1608
|
+
onClick: () => setTheme("system"),
|
|
1609
|
+
children: [
|
|
1610
|
+
/* @__PURE__ */ jsx18(Monitor, { className: "h-4 w-4" }),
|
|
1611
|
+
" Sistema"
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
)
|
|
1615
|
+
]
|
|
1616
|
+
}
|
|
1617
|
+
) })
|
|
1618
|
+
] });
|
|
1737
1619
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1620
|
+
|
|
1621
|
+
// src/components/multi-combobox.tsx
|
|
1622
|
+
import * as PopoverPrimitive5 from "@radix-ui/react-popover";
|
|
1623
|
+
import { Command as CommandPrimitive2 } from "cmdk";
|
|
1624
|
+
import { Check as Check2, ChevronsUpDown as ChevronsUpDown3, Loader2 as Loader22, Search as Search2, X as X4 } from "lucide-react";
|
|
1625
|
+
import * as React8 from "react";
|
|
1626
|
+
import { Drawer as DrawerPrimitive5 } from "vaul";
|
|
1627
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1628
|
+
function MultiCombobox({
|
|
1629
|
+
options,
|
|
1630
|
+
value,
|
|
1631
|
+
onChange,
|
|
1632
|
+
placeholder = "Selecione...",
|
|
1633
|
+
searchPlaceholder = "Buscar...",
|
|
1634
|
+
emptyMessage = "Nenhum resultado encontrado.",
|
|
1635
|
+
disabled,
|
|
1636
|
+
id,
|
|
1637
|
+
className,
|
|
1638
|
+
"aria-invalid": ariaInvalid,
|
|
1639
|
+
"aria-describedby": ariaDescribedby,
|
|
1640
|
+
onSearchChange,
|
|
1641
|
+
onLoadMore,
|
|
1642
|
+
loading,
|
|
1643
|
+
hasMore,
|
|
1644
|
+
selectedOptions
|
|
1747
1645
|
}) {
|
|
1646
|
+
const [open, setOpen] = React8.useState(false);
|
|
1748
1647
|
const isDesktop = useIsDesktop();
|
|
1749
|
-
const
|
|
1750
|
-
const
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1648
|
+
const isServer = onSearchChange !== void 0;
|
|
1649
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1650
|
+
const selected = [...selectedOptions ?? [], ...options].filter((option) => {
|
|
1651
|
+
if (!value.includes(option.value) || seen.has(option.value)) return false;
|
|
1652
|
+
seen.add(option.value);
|
|
1653
|
+
return true;
|
|
1654
|
+
});
|
|
1655
|
+
const { listRef, sentinelRef } = useInfiniteScrollSentinel({
|
|
1656
|
+
enabled: isServer && !!hasMore,
|
|
1657
|
+
loading,
|
|
1658
|
+
onLoadMore
|
|
1659
|
+
});
|
|
1660
|
+
const toggleValue = (optionValue) => {
|
|
1661
|
+
onChange(
|
|
1662
|
+
value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
|
|
1663
|
+
);
|
|
1664
|
+
};
|
|
1665
|
+
const removeValue = (optionValue) => {
|
|
1666
|
+
onChange(value.filter((v) => v !== optionValue));
|
|
1667
|
+
};
|
|
1668
|
+
const trigger = /* @__PURE__ */ jsxs17(
|
|
1669
|
+
"div",
|
|
1753
1670
|
{
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
"
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1671
|
+
id,
|
|
1672
|
+
role: "combobox",
|
|
1673
|
+
tabIndex: disabled ? -1 : 0,
|
|
1674
|
+
"aria-expanded": open,
|
|
1675
|
+
"aria-invalid": ariaInvalid,
|
|
1676
|
+
"aria-describedby": ariaDescribedby,
|
|
1677
|
+
"aria-disabled": disabled,
|
|
1678
|
+
onKeyDown: (event) => {
|
|
1679
|
+
if (disabled) return;
|
|
1680
|
+
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
|
|
1681
|
+
event.preventDefault();
|
|
1682
|
+
setOpen(true);
|
|
1764
1683
|
}
|
|
1765
|
-
|
|
1684
|
+
},
|
|
1685
|
+
className: cn(
|
|
1686
|
+
"flex min-h-9 w-full cursor-pointer flex-wrap items-center gap-1 rounded-md border border-input bg-transparent px-3 py-1.5 text-sm shadow-sm transition-colors hover:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive",
|
|
1687
|
+
className
|
|
1688
|
+
),
|
|
1689
|
+
children: [
|
|
1690
|
+
selected.length === 0 ? /* @__PURE__ */ jsx19("span", { className: "text-muted-foreground", children: placeholder }) : selected.map((option) => /* @__PURE__ */ jsxs17(
|
|
1691
|
+
"span",
|
|
1692
|
+
{
|
|
1693
|
+
className: "inline-flex items-center gap-1 rounded bg-secondary px-1.5 py-0.5 text-xs text-secondary-foreground",
|
|
1694
|
+
children: [
|
|
1695
|
+
option.label,
|
|
1696
|
+
/* @__PURE__ */ jsx19(
|
|
1697
|
+
"button",
|
|
1698
|
+
{
|
|
1699
|
+
type: "button",
|
|
1700
|
+
tabIndex: -1,
|
|
1701
|
+
"aria-label": `Remover ${option.label}`,
|
|
1702
|
+
onClick: (event) => {
|
|
1703
|
+
event.stopPropagation();
|
|
1704
|
+
removeValue(option.value);
|
|
1705
|
+
},
|
|
1706
|
+
onPointerDown: (event) => event.stopPropagation(),
|
|
1707
|
+
className: "rounded-sm opacity-60 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
1708
|
+
children: /* @__PURE__ */ jsx19(X4, { className: "h-3 w-3" })
|
|
1709
|
+
}
|
|
1710
|
+
)
|
|
1711
|
+
]
|
|
1712
|
+
},
|
|
1713
|
+
option.value
|
|
1714
|
+
)),
|
|
1715
|
+
/* @__PURE__ */ jsx19(ChevronsUpDown3, { className: "ml-auto h-4 w-4 shrink-0 opacity-50" })
|
|
1716
|
+
]
|
|
1766
1717
|
}
|
|
1767
1718
|
);
|
|
1768
|
-
const
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
}) }, item.label) : /* @__PURE__ */ jsxs24(
|
|
1795
|
-
DropdownMenu2.Item,
|
|
1719
|
+
const command = /* @__PURE__ */ jsxs17(
|
|
1720
|
+
CommandPrimitive2,
|
|
1721
|
+
{
|
|
1722
|
+
shouldFilter: !isServer,
|
|
1723
|
+
className: "flex h-full w-full flex-col overflow-hidden",
|
|
1724
|
+
children: [
|
|
1725
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center border-b px-3", children: [
|
|
1726
|
+
/* @__PURE__ */ jsx19(Search2, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
1727
|
+
/* @__PURE__ */ jsx19(
|
|
1728
|
+
CommandPrimitive2.Input,
|
|
1729
|
+
{
|
|
1730
|
+
placeholder: searchPlaceholder,
|
|
1731
|
+
onValueChange: isServer ? onSearchChange : void 0,
|
|
1732
|
+
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] }),
|
|
1736
|
+
/* @__PURE__ */ jsxs17(
|
|
1737
|
+
CommandPrimitive2.List,
|
|
1738
|
+
{
|
|
1739
|
+
ref: listRef,
|
|
1740
|
+
className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
|
|
1741
|
+
children: [
|
|
1742
|
+
!isServer && /* @__PURE__ */ jsx19(CommandPrimitive2.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
1743
|
+
options.map((option) => /* @__PURE__ */ jsxs17(
|
|
1744
|
+
CommandPrimitive2.Item,
|
|
1796
1745
|
{
|
|
1797
|
-
|
|
1798
|
-
|
|
1746
|
+
value: isServer ? option.value : option.label,
|
|
1747
|
+
disabled: option.disabled,
|
|
1748
|
+
onSelect: () => toggleValue(option.value),
|
|
1749
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
1799
1750
|
children: [
|
|
1800
|
-
|
|
1801
|
-
|
|
1751
|
+
/* @__PURE__ */ jsx19(
|
|
1752
|
+
Check2,
|
|
1753
|
+
{
|
|
1754
|
+
className: cn(
|
|
1755
|
+
"h-4 w-4 shrink-0",
|
|
1756
|
+
value.includes(option.value) ? "opacity-100" : "opacity-0"
|
|
1757
|
+
)
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1760
|
+
/* @__PURE__ */ jsx19("span", { className: "truncate", children: option.label })
|
|
1802
1761
|
]
|
|
1803
1762
|
},
|
|
1804
|
-
|
|
1805
|
-
)
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1763
|
+
option.value
|
|
1764
|
+
)),
|
|
1765
|
+
isServer && !loading && options.length === 0 && /* @__PURE__ */ jsx19("div", { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
1766
|
+
isServer && loading && /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx19(Loader22, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
|
|
1767
|
+
isServer && hasMore && /* @__PURE__ */ jsx19("div", { ref: sentinelRef, "aria-hidden": true, className: "h-1" })
|
|
1768
|
+
]
|
|
1769
|
+
}
|
|
1770
|
+
)
|
|
1771
|
+
]
|
|
1772
|
+
}
|
|
1773
|
+
);
|
|
1774
|
+
if (isDesktop) {
|
|
1775
|
+
return /* @__PURE__ */ jsxs17(PopoverPrimitive5.Root, { open, onOpenChange: setOpen, children: [
|
|
1776
|
+
/* @__PURE__ */ jsx19(PopoverPrimitive5.Trigger, { asChild: true, disabled, children: trigger }),
|
|
1777
|
+
/* @__PURE__ */ jsx19(PopoverPrimitive5.Portal, { children: /* @__PURE__ */ jsx19(
|
|
1778
|
+
PopoverPrimitive5.Content,
|
|
1779
|
+
{
|
|
1780
|
+
align: "start",
|
|
1781
|
+
sideOffset: 4,
|
|
1782
|
+
className: "pointer-events-auto z-50 overflow-hidden rounded-md border bg-popover p-0 text-popover-foreground shadow-md",
|
|
1783
|
+
style: { width: "var(--radix-popover-trigger-width)" },
|
|
1784
|
+
children: command
|
|
1825
1785
|
}
|
|
1826
1786
|
) })
|
|
1827
1787
|
] });
|
|
1828
1788
|
}
|
|
1829
|
-
return /* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
1831
|
-
/* @__PURE__ */
|
|
1832
|
-
/* @__PURE__ */
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
/* @__PURE__ */
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1789
|
+
return /* @__PURE__ */ jsxs17(DrawerPrimitive5.Root, { open, onOpenChange: setOpen, children: [
|
|
1790
|
+
/* @__PURE__ */ jsx19(DrawerPrimitive5.Trigger, { asChild: true, disabled, children: trigger }),
|
|
1791
|
+
/* @__PURE__ */ jsxs17(DrawerPrimitive5.Portal, { children: [
|
|
1792
|
+
/* @__PURE__ */ jsx19(DrawerPrimitive5.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
1793
|
+
/* @__PURE__ */ jsxs17(DrawerPrimitive5.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
|
|
1794
|
+
/* @__PURE__ */ jsx19(DrawerPrimitive5.Title, { className: "sr-only", children: placeholder }),
|
|
1795
|
+
/* @__PURE__ */ jsx19("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
1796
|
+
command
|
|
1797
|
+
] })
|
|
1798
|
+
] })
|
|
1799
|
+
] });
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
// src/components/page-header.tsx
|
|
1803
|
+
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1804
|
+
function PageHeader({ title, description, action, className }) {
|
|
1805
|
+
return /* @__PURE__ */ jsxs18(
|
|
1806
|
+
"div",
|
|
1807
|
+
{
|
|
1808
|
+
className: `flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? ""}`,
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
|
|
1811
|
+
/* @__PURE__ */ jsx20("h1", { className: "truncate text-2xl font-semibold tracking-tight", children: title }),
|
|
1812
|
+
description && /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: description })
|
|
1839
1813
|
] }),
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1814
|
+
action && /* @__PURE__ */ jsx20("div", { className: "shrink-0", children: action })
|
|
1815
|
+
]
|
|
1816
|
+
}
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/components/pagination.tsx
|
|
1821
|
+
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1822
|
+
var navButtonClass2 = "inline-flex h-8 items-center justify-center rounded-md border border-input bg-background px-3 text-xs font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground cursor-pointer disabled:pointer-events-none disabled:opacity-50";
|
|
1823
|
+
function Pagination({
|
|
1824
|
+
page,
|
|
1825
|
+
onPageChange,
|
|
1826
|
+
hasNextPage,
|
|
1827
|
+
hasPreviousPage,
|
|
1828
|
+
totalPages,
|
|
1829
|
+
showPageSizeSelector = false,
|
|
1830
|
+
pageSize,
|
|
1831
|
+
onPageSizeChange,
|
|
1832
|
+
pageSizeOptions,
|
|
1833
|
+
className
|
|
1834
|
+
}) {
|
|
1835
|
+
return /* @__PURE__ */ jsxs19(
|
|
1836
|
+
"div",
|
|
1837
|
+
{
|
|
1838
|
+
className: `flex items-center ${showPageSizeSelector ? "justify-between" : "justify-end"} gap-4 ${className ?? ""}`,
|
|
1839
|
+
children: [
|
|
1840
|
+
showPageSizeSelector && /* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-2", children: [
|
|
1841
|
+
/* @__PURE__ */ jsx21("label", { htmlFor: "pagination-page-size", className: "text-sm text-muted-foreground", children: "Itens por p\xE1gina" }),
|
|
1842
|
+
/* @__PURE__ */ jsx21(
|
|
1843
|
+
"select",
|
|
1843
1844
|
{
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
},
|
|
1855
|
-
item.label
|
|
1856
|
-
) : /* @__PURE__ */ jsxs24(
|
|
1845
|
+
id: "pagination-page-size",
|
|
1846
|
+
value: pageSize,
|
|
1847
|
+
onChange: (e) => onPageSizeChange?.(Number(e.target.value)),
|
|
1848
|
+
className: "h-8 rounded-md border border-input bg-background px-2 text-xs font-medium shadow-sm transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring cursor-pointer",
|
|
1849
|
+
children: (pageSizeOptions ?? []).map((size) => /* @__PURE__ */ jsx21("option", { value: size, children: size }, size))
|
|
1850
|
+
}
|
|
1851
|
+
)
|
|
1852
|
+
] }),
|
|
1853
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex items-center gap-4", children: [
|
|
1854
|
+
/* @__PURE__ */ jsx21(
|
|
1857
1855
|
"button",
|
|
1858
1856
|
{
|
|
1859
1857
|
type: "button",
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
),
|
|
1873
|
-
onLogout && /* @__PURE__ */ jsxs24(Fragment6, { children: [
|
|
1874
|
-
items.length > 0 && /* @__PURE__ */ jsx28("div", { className: "-mx-1 my-1 h-px bg-border" }),
|
|
1875
|
-
/* @__PURE__ */ jsxs24(
|
|
1858
|
+
onClick: () => onPageChange(page - 1),
|
|
1859
|
+
disabled: !hasPreviousPage,
|
|
1860
|
+
className: navButtonClass2,
|
|
1861
|
+
children: "Anterior"
|
|
1862
|
+
}
|
|
1863
|
+
),
|
|
1864
|
+
/* @__PURE__ */ jsxs19("span", { className: "text-sm text-muted-foreground", children: [
|
|
1865
|
+
"P\xE1gina ",
|
|
1866
|
+
page,
|
|
1867
|
+
totalPages ? ` de ${totalPages}` : ""
|
|
1868
|
+
] }),
|
|
1869
|
+
/* @__PURE__ */ jsx21(
|
|
1876
1870
|
"button",
|
|
1877
1871
|
{
|
|
1878
1872
|
type: "button",
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
},
|
|
1884
|
-
children: [
|
|
1885
|
-
/* @__PURE__ */ jsx28(LogOut, { className: "h-4 w-4" }),
|
|
1886
|
-
logoutLabel
|
|
1887
|
-
]
|
|
1873
|
+
onClick: () => onPageChange(page + 1),
|
|
1874
|
+
disabled: !hasNextPage,
|
|
1875
|
+
className: navButtonClass2,
|
|
1876
|
+
children: "Pr\xF3ximo"
|
|
1888
1877
|
}
|
|
1889
1878
|
)
|
|
1890
1879
|
] })
|
|
1891
|
-
]
|
|
1892
|
-
] })
|
|
1893
|
-
] });
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
// src/components/app-shell.tsx
|
|
1897
|
-
import { jsx as jsx29, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1898
|
-
function AppShell({
|
|
1899
|
-
brand,
|
|
1900
|
-
brandCollapsed,
|
|
1901
|
-
navItems,
|
|
1902
|
-
activePath,
|
|
1903
|
-
isActive,
|
|
1904
|
-
isAdmin = false,
|
|
1905
|
-
user,
|
|
1906
|
-
userMenuItems,
|
|
1907
|
-
onLogout,
|
|
1908
|
-
renderLink = defaultRenderLink,
|
|
1909
|
-
headerActions,
|
|
1910
|
-
collapsible = true,
|
|
1911
|
-
defaultCollapsed = false,
|
|
1912
|
-
children
|
|
1913
|
-
}) {
|
|
1914
|
-
const [collapsed, setCollapsed] = useState10(defaultCollapsed);
|
|
1915
|
-
const [mobileOpen, setMobileOpen] = useState10(false);
|
|
1916
|
-
const nav = (isCollapsed, onNavigate) => /* @__PURE__ */ jsx29(
|
|
1917
|
-
SidebarNav,
|
|
1918
|
-
{
|
|
1919
|
-
items: navItems,
|
|
1920
|
-
activePath,
|
|
1921
|
-
isActive,
|
|
1922
|
-
isAdmin,
|
|
1923
|
-
isCollapsed,
|
|
1924
|
-
renderLink,
|
|
1925
|
-
onNavigate
|
|
1880
|
+
]
|
|
1926
1881
|
}
|
|
1927
1882
|
);
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
// src/components/password-input.tsx
|
|
1886
|
+
import { Eye, EyeOff } from "lucide-react";
|
|
1887
|
+
import * as React9 from "react";
|
|
1888
|
+
import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1889
|
+
var PasswordInput = React9.forwardRef(({ containerClassName, className, ...props }, ref) => {
|
|
1890
|
+
const [visible, setVisible] = React9.useState(false);
|
|
1891
|
+
return /* @__PURE__ */ jsxs20("div", { className: `relative ${containerClassName ?? ""}`, children: [
|
|
1892
|
+
/* @__PURE__ */ jsx22(
|
|
1893
|
+
"input",
|
|
1931
1894
|
{
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
}
|
|
1948
|
-
) })
|
|
1949
|
-
]
|
|
1895
|
+
ref,
|
|
1896
|
+
type: visible ? "text" : "password",
|
|
1897
|
+
className: `flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 pr-10 text-base shadow-sm transition-all duration-200 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive md:text-sm ${className ?? ""}`,
|
|
1898
|
+
...props
|
|
1899
|
+
}
|
|
1900
|
+
),
|
|
1901
|
+
/* @__PURE__ */ jsx22(
|
|
1902
|
+
"button",
|
|
1903
|
+
{
|
|
1904
|
+
type: "button",
|
|
1905
|
+
onClick: () => setVisible((prev) => !prev),
|
|
1906
|
+
"aria-label": visible ? "Ocultar senha" : "Mostrar senha",
|
|
1907
|
+
tabIndex: -1,
|
|
1908
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground transition-colors hover:text-foreground",
|
|
1909
|
+
children: visible ? /* @__PURE__ */ jsx22(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx22(Eye, { className: "h-4 w-4" })
|
|
1950
1910
|
}
|
|
1951
|
-
)
|
|
1952
|
-
|
|
1911
|
+
)
|
|
1912
|
+
] });
|
|
1913
|
+
});
|
|
1914
|
+
PasswordInput.displayName = "PasswordInput";
|
|
1915
|
+
|
|
1916
|
+
// src/components/progress-bar.tsx
|
|
1917
|
+
import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1918
|
+
var sizeClasses2 = {
|
|
1919
|
+
sm: "h-1.5",
|
|
1920
|
+
md: "h-2"
|
|
1921
|
+
};
|
|
1922
|
+
function ProgressBar({
|
|
1923
|
+
value,
|
|
1924
|
+
size = "md",
|
|
1925
|
+
label,
|
|
1926
|
+
valueLabel,
|
|
1927
|
+
className,
|
|
1928
|
+
indicatorClassName
|
|
1929
|
+
}) {
|
|
1930
|
+
const clamped = Math.min(100, Math.max(0, value));
|
|
1931
|
+
return /* @__PURE__ */ jsxs21("div", { className: `space-y-1.5 ${className ?? ""}`, children: [
|
|
1932
|
+
(label || valueLabel) && /* @__PURE__ */ jsxs21("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
1933
|
+
label && /* @__PURE__ */ jsx23("span", { className: "text-sm text-muted-foreground", children: label }),
|
|
1934
|
+
valueLabel && /* @__PURE__ */ jsx23("span", { className: "text-sm font-semibold", children: valueLabel })
|
|
1935
|
+
] }),
|
|
1936
|
+
/* @__PURE__ */ jsx23(
|
|
1953
1937
|
"div",
|
|
1954
1938
|
{
|
|
1955
|
-
className:
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
),
|
|
1959
|
-
onClick: () => setMobileOpen(false),
|
|
1960
|
-
children: [
|
|
1961
|
-
/* @__PURE__ */ jsx29("div", { className: "absolute inset-0 bg-black/50" }),
|
|
1962
|
-
/* @__PURE__ */ jsxs25(
|
|
1963
|
-
"div",
|
|
1964
|
-
{
|
|
1965
|
-
className: cn(
|
|
1966
|
-
"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300",
|
|
1967
|
-
mobileOpen ? "translate-x-0" : "-translate-x-full"
|
|
1968
|
-
),
|
|
1969
|
-
onClick: (e) => e.stopPropagation(),
|
|
1970
|
-
children: [
|
|
1971
|
-
/* @__PURE__ */ jsx29("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: brand }),
|
|
1972
|
-
/* @__PURE__ */ jsx29("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(false, () => setMobileOpen(false)) })
|
|
1973
|
-
]
|
|
1974
|
-
}
|
|
1975
|
-
)
|
|
1976
|
-
]
|
|
1977
|
-
}
|
|
1978
|
-
),
|
|
1979
|
-
/* @__PURE__ */ jsxs25("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
1980
|
-
/* @__PURE__ */ jsxs25("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4", children: [
|
|
1981
|
-
/* @__PURE__ */ jsx29(
|
|
1982
|
-
"button",
|
|
1939
|
+
className: `w-full overflow-hidden rounded-full bg-muted ${sizeClasses2[size]}`,
|
|
1940
|
+
children: /* @__PURE__ */ jsx23(
|
|
1941
|
+
"div",
|
|
1983
1942
|
{
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
className: "inline-flex h-9 w-9 items-center justify-center rounded-md border border-input bg-background shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground md:hidden",
|
|
1987
|
-
"aria-label": "Abrir menu",
|
|
1988
|
-
children: /* @__PURE__ */ jsx29(Menu, { className: "h-4 w-4" })
|
|
1943
|
+
className: `h-full rounded-full transition-all duration-300 ${indicatorClassName ?? "bg-primary"}`,
|
|
1944
|
+
style: { width: `${clamped}%` }
|
|
1989
1945
|
}
|
|
1990
|
-
)
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1946
|
+
)
|
|
1947
|
+
}
|
|
1948
|
+
)
|
|
1949
|
+
] });
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// src/components/responsive-data-view.tsx
|
|
1953
|
+
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1954
|
+
function ResponsiveDataView({
|
|
1955
|
+
table,
|
|
1956
|
+
cards,
|
|
1957
|
+
isEmpty,
|
|
1958
|
+
isLoading,
|
|
1959
|
+
emptyIcon,
|
|
1960
|
+
emptyTitle = "Nenhum registro encontrado",
|
|
1961
|
+
emptyDescription,
|
|
1962
|
+
pagination
|
|
1963
|
+
}) {
|
|
1964
|
+
return /* @__PURE__ */ jsxs22("div", { className: "space-y-4", children: [
|
|
1965
|
+
/* @__PURE__ */ jsx24("div", { className: "hidden overflow-x-auto rounded-md border md:block", children: table }),
|
|
1966
|
+
/* @__PURE__ */ jsx24("div", { className: "md:hidden", children: cards }),
|
|
1967
|
+
!isLoading && isEmpty && /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
1968
|
+
emptyIcon && /* @__PURE__ */ jsx24("div", { className: "mb-4 text-muted-foreground", children: emptyIcon }),
|
|
1969
|
+
/* @__PURE__ */ jsx24("h3", { className: "text-lg font-semibold tracking-tight", children: emptyTitle }),
|
|
1970
|
+
emptyDescription && /* @__PURE__ */ jsx24("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: emptyDescription })
|
|
1971
|
+
] }),
|
|
1972
|
+
pagination
|
|
1998
1973
|
] });
|
|
1999
1974
|
}
|
|
2000
1975
|
|
|
@@ -2002,8 +1977,8 @@ function AppShell({
|
|
|
2002
1977
|
import * as DropdownMenu3 from "@radix-ui/react-dropdown-menu";
|
|
2003
1978
|
import { MoreVertical } from "lucide-react";
|
|
2004
1979
|
import { useState as useState11 } from "react";
|
|
2005
|
-
import { Drawer as
|
|
2006
|
-
import { Fragment as
|
|
1980
|
+
import { Drawer as DrawerPrimitive6 } from "vaul";
|
|
1981
|
+
import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2007
1982
|
var triggerClass = "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
|
|
2008
1983
|
var itemClass2 = "flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
|
|
2009
1984
|
var sheetItemClass2 = "flex w-full cursor-pointer select-none items-center gap-3 rounded-md px-3 py-3 text-base outline-none transition-colors hover:bg-accent active:bg-accent disabled:pointer-events-none disabled:opacity-50";
|
|
@@ -2017,20 +1992,20 @@ function RowActionsMenu({
|
|
|
2017
1992
|
const isDesktop = useIsDesktop();
|
|
2018
1993
|
const [open, setOpen] = useState11(false);
|
|
2019
1994
|
if (actions.length === 0) return null;
|
|
2020
|
-
const trigger = /* @__PURE__ */
|
|
1995
|
+
const trigger = /* @__PURE__ */ jsx25(
|
|
2021
1996
|
"button",
|
|
2022
1997
|
{
|
|
2023
1998
|
type: "button",
|
|
2024
1999
|
disabled,
|
|
2025
2000
|
"aria-label": label,
|
|
2026
2001
|
className: triggerClass,
|
|
2027
|
-
children: /* @__PURE__ */
|
|
2002
|
+
children: /* @__PURE__ */ jsx25(MoreVertical, { className: "h-4 w-4" })
|
|
2028
2003
|
}
|
|
2029
2004
|
);
|
|
2030
2005
|
if (isDesktop) {
|
|
2031
|
-
return /* @__PURE__ */
|
|
2032
|
-
/* @__PURE__ */
|
|
2033
|
-
/* @__PURE__ */
|
|
2006
|
+
return /* @__PURE__ */ jsxs23(DropdownMenu3.Root, { open, onOpenChange: setOpen, modal: false, children: [
|
|
2007
|
+
/* @__PURE__ */ jsx25(DropdownMenu3.Trigger, { asChild: true, children: trigger }),
|
|
2008
|
+
/* @__PURE__ */ jsx25(DropdownMenu3.Portal, { children: /* @__PURE__ */ jsx25(
|
|
2034
2009
|
DropdownMenu3.Content,
|
|
2035
2010
|
{
|
|
2036
2011
|
align,
|
|
@@ -2041,7 +2016,7 @@ function RowActionsMenu({
|
|
|
2041
2016
|
itemClass2,
|
|
2042
2017
|
action.destructive && "text-destructive focus:bg-destructive/10"
|
|
2043
2018
|
);
|
|
2044
|
-
return action.href ? /* @__PURE__ */
|
|
2019
|
+
return action.href ? /* @__PURE__ */ jsx25(
|
|
2045
2020
|
DropdownMenu3.Item,
|
|
2046
2021
|
{
|
|
2047
2022
|
asChild: true,
|
|
@@ -2049,14 +2024,14 @@ function RowActionsMenu({
|
|
|
2049
2024
|
children: renderLink({
|
|
2050
2025
|
href: action.href,
|
|
2051
2026
|
className: cls,
|
|
2052
|
-
children: /* @__PURE__ */
|
|
2027
|
+
children: /* @__PURE__ */ jsxs23(Fragment6, { children: [
|
|
2053
2028
|
action.icon,
|
|
2054
2029
|
action.label
|
|
2055
2030
|
] })
|
|
2056
2031
|
})
|
|
2057
2032
|
},
|
|
2058
2033
|
action.label
|
|
2059
|
-
) : /* @__PURE__ */
|
|
2034
|
+
) : /* @__PURE__ */ jsxs23(
|
|
2060
2035
|
DropdownMenu3.Item,
|
|
2061
2036
|
{
|
|
2062
2037
|
className: cls,
|
|
@@ -2074,23 +2049,23 @@ function RowActionsMenu({
|
|
|
2074
2049
|
) })
|
|
2075
2050
|
] });
|
|
2076
2051
|
}
|
|
2077
|
-
return /* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */
|
|
2081
|
-
/* @__PURE__ */
|
|
2082
|
-
/* @__PURE__ */
|
|
2083
|
-
/* @__PURE__ */
|
|
2052
|
+
return /* @__PURE__ */ jsxs23(DrawerPrimitive6.Root, { open, onOpenChange: setOpen, children: [
|
|
2053
|
+
/* @__PURE__ */ jsx25(DrawerPrimitive6.Trigger, { asChild: true, children: trigger }),
|
|
2054
|
+
/* @__PURE__ */ jsxs23(DrawerPrimitive6.Portal, { children: [
|
|
2055
|
+
/* @__PURE__ */ jsx25(DrawerPrimitive6.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
2056
|
+
/* @__PURE__ */ jsxs23(DrawerPrimitive6.Content, { className: "fixed inset-x-0 bottom-0 z-50 flex flex-col rounded-t-2xl border bg-popover p-2 pb-[max(0.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-none", children: [
|
|
2057
|
+
/* @__PURE__ */ jsx25(DrawerPrimitive6.Title, { className: "sr-only", children: label }),
|
|
2058
|
+
/* @__PURE__ */ jsx25("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
2084
2059
|
actions.map((action) => {
|
|
2085
2060
|
const cls = cn(
|
|
2086
2061
|
sheetItemClass2,
|
|
2087
2062
|
action.destructive && "text-destructive"
|
|
2088
2063
|
);
|
|
2089
|
-
const inner = /* @__PURE__ */
|
|
2064
|
+
const inner = /* @__PURE__ */ jsxs23(Fragment6, { children: [
|
|
2090
2065
|
action.icon,
|
|
2091
2066
|
action.label
|
|
2092
2067
|
] });
|
|
2093
|
-
return action.href ? /* @__PURE__ */
|
|
2068
|
+
return action.href ? /* @__PURE__ */ jsx25(
|
|
2094
2069
|
"span",
|
|
2095
2070
|
{
|
|
2096
2071
|
onClick: () => setOpen(false),
|
|
@@ -2102,7 +2077,7 @@ function RowActionsMenu({
|
|
|
2102
2077
|
})
|
|
2103
2078
|
},
|
|
2104
2079
|
action.label
|
|
2105
|
-
) : /* @__PURE__ */
|
|
2080
|
+
) : /* @__PURE__ */ jsx25(
|
|
2106
2081
|
"button",
|
|
2107
2082
|
{
|
|
2108
2083
|
type: "button",
|
|
@@ -2122,30 +2097,212 @@ function RowActionsMenu({
|
|
|
2122
2097
|
] });
|
|
2123
2098
|
}
|
|
2124
2099
|
|
|
2125
|
-
// src/
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2100
|
+
// src/components/search-input.tsx
|
|
2101
|
+
import * as React10 from "react";
|
|
2102
|
+
import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2103
|
+
var SearchInput = React10.forwardRef(
|
|
2104
|
+
({ containerClassName, className, ...props }, ref) => {
|
|
2105
|
+
return /* @__PURE__ */ jsxs24("div", { className: `relative flex-1 ${containerClassName ?? ""}`, children: [
|
|
2106
|
+
/* @__PURE__ */ jsxs24(
|
|
2107
|
+
"svg",
|
|
2108
|
+
{
|
|
2109
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2110
|
+
width: "16",
|
|
2111
|
+
height: "16",
|
|
2112
|
+
viewBox: "0 0 24 24",
|
|
2113
|
+
fill: "none",
|
|
2114
|
+
stroke: "currentColor",
|
|
2115
|
+
strokeWidth: "2",
|
|
2116
|
+
strokeLinecap: "round",
|
|
2117
|
+
strokeLinejoin: "round",
|
|
2118
|
+
className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground",
|
|
2119
|
+
children: [
|
|
2120
|
+
/* @__PURE__ */ jsx26("circle", { cx: "11", cy: "11", r: "8" }),
|
|
2121
|
+
/* @__PURE__ */ jsx26("path", { d: "m21 21-4.3-4.3" })
|
|
2122
|
+
]
|
|
2123
|
+
}
|
|
2124
|
+
),
|
|
2125
|
+
/* @__PURE__ */ jsx26(
|
|
2126
|
+
"input",
|
|
2127
|
+
{
|
|
2128
|
+
ref,
|
|
2129
|
+
type: "text",
|
|
2130
|
+
className: `flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 pl-10 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 ${className ?? ""}`,
|
|
2131
|
+
...props
|
|
2132
|
+
}
|
|
2133
|
+
)
|
|
2134
|
+
] });
|
|
2130
2135
|
}
|
|
2131
|
-
|
|
2136
|
+
);
|
|
2137
|
+
SearchInput.displayName = "SearchInput";
|
|
2138
|
+
|
|
2139
|
+
// src/components/stat-card.tsx
|
|
2140
|
+
import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2141
|
+
function StatCard({ label, value, detail, icon, isLoading }) {
|
|
2142
|
+
if (isLoading) {
|
|
2143
|
+
return /* @__PURE__ */ jsxs25("div", { className: "rounded-lg border bg-card p-6 shadow-sm", children: [
|
|
2144
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between pb-2", children: [
|
|
2145
|
+
/* @__PURE__ */ jsx27("div", { className: "h-4 w-24 animate-pulse rounded bg-muted" }),
|
|
2146
|
+
/* @__PURE__ */ jsx27("div", { className: "h-4 w-4 animate-pulse rounded bg-muted" })
|
|
2147
|
+
] }),
|
|
2148
|
+
/* @__PURE__ */ jsx27("div", { className: "mt-2 h-7 w-16 animate-pulse rounded bg-muted" }),
|
|
2149
|
+
/* @__PURE__ */ jsx27("div", { className: "mt-1 h-4 w-20 animate-pulse rounded bg-muted" })
|
|
2150
|
+
] });
|
|
2151
|
+
}
|
|
2152
|
+
return /* @__PURE__ */ jsxs25("div", { className: "rounded-lg border bg-card p-6 shadow-sm", children: [
|
|
2153
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between pb-2", children: [
|
|
2154
|
+
/* @__PURE__ */ jsx27("span", { className: "text-sm font-medium text-muted-foreground", children: label }),
|
|
2155
|
+
icon && /* @__PURE__ */ jsx27("span", { className: "text-muted-foreground", children: icon })
|
|
2156
|
+
] }),
|
|
2157
|
+
/* @__PURE__ */ jsx27("div", { className: "text-2xl font-bold", children: value }),
|
|
2158
|
+
detail && /* @__PURE__ */ jsx27("p", { className: "text-xs text-muted-foreground", children: detail })
|
|
2159
|
+
] });
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
// src/components/status-badge.tsx
|
|
2163
|
+
import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2164
|
+
var variantClasses = {
|
|
2165
|
+
neutral: {
|
|
2166
|
+
badge: "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300",
|
|
2167
|
+
dot: "bg-gray-400"
|
|
2168
|
+
},
|
|
2169
|
+
info: {
|
|
2170
|
+
badge: "bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400",
|
|
2171
|
+
dot: "bg-blue-500"
|
|
2172
|
+
},
|
|
2173
|
+
success: {
|
|
2174
|
+
badge: "bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-400",
|
|
2175
|
+
dot: "bg-green-500"
|
|
2176
|
+
},
|
|
2177
|
+
danger: {
|
|
2178
|
+
badge: "bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400",
|
|
2179
|
+
dot: "bg-red-500"
|
|
2180
|
+
},
|
|
2181
|
+
warning: {
|
|
2182
|
+
badge: "bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400",
|
|
2183
|
+
dot: "bg-amber-500"
|
|
2184
|
+
}
|
|
2185
|
+
};
|
|
2186
|
+
function StatusBadge({
|
|
2187
|
+
variant = "neutral",
|
|
2188
|
+
dot = true,
|
|
2189
|
+
className,
|
|
2190
|
+
children
|
|
2191
|
+
}) {
|
|
2192
|
+
const classes = variantClasses[variant];
|
|
2193
|
+
return /* @__PURE__ */ jsxs26(
|
|
2194
|
+
"span",
|
|
2195
|
+
{
|
|
2196
|
+
className: `inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium ${classes.badge} ${className ?? ""}`,
|
|
2197
|
+
children: [
|
|
2198
|
+
dot && /* @__PURE__ */ jsx28(
|
|
2199
|
+
"span",
|
|
2200
|
+
{
|
|
2201
|
+
className: `inline-block h-1.5 w-1.5 shrink-0 rounded-full ${classes.dot}`
|
|
2202
|
+
}
|
|
2203
|
+
),
|
|
2204
|
+
children
|
|
2205
|
+
]
|
|
2206
|
+
}
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
// src/components/status-dot.tsx
|
|
2211
|
+
import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2212
|
+
function StatusDot({ active, label, className }) {
|
|
2213
|
+
return /* @__PURE__ */ jsxs27("span", { className: `inline-flex items-center gap-2 ${className ?? ""}`, children: [
|
|
2214
|
+
/* @__PURE__ */ jsx29(
|
|
2215
|
+
"span",
|
|
2216
|
+
{
|
|
2217
|
+
className: `h-2 w-2 rounded-full ${active ? "bg-green-500" : "bg-red-500"}`
|
|
2218
|
+
}
|
|
2219
|
+
),
|
|
2220
|
+
label && /* @__PURE__ */ jsx29("span", { children: label })
|
|
2221
|
+
] });
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// src/components/table-skeleton.tsx
|
|
2225
|
+
import { Fragment as Fragment7, jsx as jsx30 } from "react/jsx-runtime";
|
|
2226
|
+
function TableSkeleton({ rows = 5, columns = 4 }) {
|
|
2227
|
+
return /* @__PURE__ */ jsx30(Fragment7, { children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx30("tr", { className: "border-b transition-colors", children: Array.from({ length: columns }).map((_2, j) => /* @__PURE__ */ jsx30("td", { className: "p-4 align-middle", children: /* @__PURE__ */ jsx30("div", { className: "h-5 w-full animate-pulse rounded bg-muted" }) }, j)) }, i)) });
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
// src/components/toaster.tsx
|
|
2231
|
+
import { Toaster as Sonner } from "sonner";
|
|
2232
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
2233
|
+
function Toaster(props) {
|
|
2234
|
+
const { theme = "system" } = useTheme();
|
|
2235
|
+
return /* @__PURE__ */ jsx31(
|
|
2236
|
+
Sonner,
|
|
2237
|
+
{
|
|
2238
|
+
theme,
|
|
2239
|
+
className: "toaster group",
|
|
2240
|
+
toastOptions: {
|
|
2241
|
+
classNames: {
|
|
2242
|
+
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md",
|
|
2243
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
2244
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
2245
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
|
2246
|
+
success: "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40",
|
|
2247
|
+
error: "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40"
|
|
2248
|
+
}
|
|
2249
|
+
},
|
|
2250
|
+
...props
|
|
2251
|
+
}
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
// src/hooks/use-company-subdomain.ts
|
|
2256
|
+
import { useState as useState12 } from "react";
|
|
2257
|
+
function getSubdomain(hostname) {
|
|
2258
|
+
const labels = hostname.split(".");
|
|
2259
|
+
if (labels.length < 2) return void 0;
|
|
2260
|
+
const first = labels[0];
|
|
2261
|
+
if (!first || first === "www" || first === "localhost") return void 0;
|
|
2262
|
+
return first;
|
|
2263
|
+
}
|
|
2264
|
+
function resolveOverride(storageKey) {
|
|
2265
|
+
if (typeof window === "undefined") return void 0;
|
|
2266
|
+
const params = new URLSearchParams(window.location.search);
|
|
2267
|
+
if (params.has("company")) {
|
|
2268
|
+
const value = params.get("company");
|
|
2269
|
+
if (value) {
|
|
2270
|
+
window.localStorage.setItem(storageKey, value);
|
|
2271
|
+
return value;
|
|
2272
|
+
}
|
|
2273
|
+
window.localStorage.removeItem(storageKey);
|
|
2274
|
+
return void 0;
|
|
2275
|
+
}
|
|
2276
|
+
return window.localStorage.getItem(storageKey) ?? void 0;
|
|
2277
|
+
}
|
|
2278
|
+
function useCompanySubdomain(opts = {}) {
|
|
2279
|
+
const { enableOverride = false, overrideStorageKey = "company-subdomain" } = opts;
|
|
2280
|
+
const [subdomain] = useState12(() => {
|
|
2281
|
+
if (enableOverride) {
|
|
2282
|
+
const override = resolveOverride(overrideStorageKey);
|
|
2283
|
+
if (override) return override;
|
|
2284
|
+
}
|
|
2285
|
+
if (typeof window === "undefined") return void 0;
|
|
2286
|
+
return getSubdomain(window.location.hostname);
|
|
2287
|
+
});
|
|
2288
|
+
return { subdomain };
|
|
2132
2289
|
}
|
|
2133
2290
|
|
|
2134
2291
|
// src/hooks/use-disclosure.ts
|
|
2135
|
-
import { useCallback, useState as
|
|
2292
|
+
import { useCallback as useCallback2, useState as useState13 } from "react";
|
|
2136
2293
|
function useDisclosure(initial = false) {
|
|
2137
|
-
const [open, setOpen] =
|
|
2138
|
-
const onOpen =
|
|
2139
|
-
const onClose =
|
|
2140
|
-
const onToggle =
|
|
2294
|
+
const [open, setOpen] = useState13(initial);
|
|
2295
|
+
const onOpen = useCallback2(() => setOpen(true), []);
|
|
2296
|
+
const onClose = useCallback2(() => setOpen(false), []);
|
|
2297
|
+
const onToggle = useCallback2(() => setOpen((v) => !v), []);
|
|
2141
2298
|
return { open, onOpen, onClose, onToggle, setOpen };
|
|
2142
2299
|
}
|
|
2143
2300
|
|
|
2144
2301
|
// src/hooks/use-toast.ts
|
|
2145
2302
|
import { toast } from "sonner";
|
|
2146
|
-
import { useCallback as
|
|
2303
|
+
import { useCallback as useCallback3 } from "react";
|
|
2147
2304
|
function useCustomToast() {
|
|
2148
|
-
const showToast =
|
|
2305
|
+
const showToast = useCallback3(
|
|
2149
2306
|
(title, description, status = "success") => {
|
|
2150
2307
|
switch (status) {
|
|
2151
2308
|
case "success":
|
|
@@ -2166,6 +2323,15 @@ function useCustomToast() {
|
|
|
2166
2323
|
);
|
|
2167
2324
|
return showToast;
|
|
2168
2325
|
}
|
|
2326
|
+
|
|
2327
|
+
// src/lib/api-error.ts
|
|
2328
|
+
function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
|
|
2329
|
+
const detail = err?.body?.detail || err?.message;
|
|
2330
|
+
if (Array.isArray(detail) && detail.length > 0) {
|
|
2331
|
+
return detail[0].msg;
|
|
2332
|
+
}
|
|
2333
|
+
return detail || fallbackMessage;
|
|
2334
|
+
}
|
|
2169
2335
|
export {
|
|
2170
2336
|
AppShell,
|
|
2171
2337
|
AuthCard,
|
|
@@ -2177,6 +2343,9 @@ export {
|
|
|
2177
2343
|
DatePicker,
|
|
2178
2344
|
DateTimePicker,
|
|
2179
2345
|
EmptyState,
|
|
2346
|
+
FilterOptionList,
|
|
2347
|
+
FilterPopover,
|
|
2348
|
+
FilterToolbar,
|
|
2180
2349
|
FormDialog,
|
|
2181
2350
|
FormDialogLayout,
|
|
2182
2351
|
FormField,
|