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