@motor-hero/ui-kit 0.14.1 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/mobile-card-list.d.ts +1 -1
- package/dist/components/mobile-card-list.d.ts.map +1 -1
- package/dist/index.cjs +49 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +37 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/mobile-card-list.tsx +40 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-card-list.d.ts","sourceRoot":"","sources":["../../src/components/mobile-card-list.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"mobile-card-list.d.ts","sourceRoot":"","sources":["../../src/components/mobile-card-list.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAA2B,MAAM,OAAO,CAAA;AAEhF,UAAU,mBAAmB,CAAC,CAAC;IAC7B,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAA;IACjD,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;IACjC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAKD,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAChC,IAAI,EACJ,UAAU,EACV,YAAY,EACZ,SAAiB,EACjB,YAAgB,EAChB,SAAS,GACV,EAAE,mBAAmB,CAAC,CAAC,CAAC,+BAsExB"}
|
package/dist/index.cjs
CHANGED
|
@@ -651,7 +651,9 @@ function DataTableWrapper({
|
|
|
651
651
|
}
|
|
652
652
|
|
|
653
653
|
// src/components/mobile-card-list.tsx
|
|
654
|
+
var import_react3 = require("react");
|
|
654
655
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
656
|
+
var SCROLL_THRESHOLD = 8;
|
|
655
657
|
function MobileCardList({
|
|
656
658
|
data,
|
|
657
659
|
renderCard,
|
|
@@ -660,6 +662,26 @@ function MobileCardList({
|
|
|
660
662
|
loadingCount = 5,
|
|
661
663
|
className
|
|
662
664
|
}) {
|
|
665
|
+
const start = (0, import_react3.useRef)(null);
|
|
666
|
+
const scrolled = (0, import_react3.useRef)(false);
|
|
667
|
+
const onTouchStart = (e) => {
|
|
668
|
+
const t = e.touches[0];
|
|
669
|
+
start.current = { x: t.clientX, y: t.clientY };
|
|
670
|
+
scrolled.current = false;
|
|
671
|
+
};
|
|
672
|
+
const onTouchMove = (e) => {
|
|
673
|
+
if (!start.current) return;
|
|
674
|
+
const t = e.touches[0];
|
|
675
|
+
if (Math.abs(t.clientX - start.current.x) > SCROLL_THRESHOLD || Math.abs(t.clientY - start.current.y) > SCROLL_THRESHOLD) {
|
|
676
|
+
scrolled.current = true;
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
const onClickCapture = (e) => {
|
|
680
|
+
if (scrolled.current) {
|
|
681
|
+
e.preventDefault();
|
|
682
|
+
e.stopPropagation();
|
|
683
|
+
}
|
|
684
|
+
};
|
|
663
685
|
if (isLoading) {
|
|
664
686
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: `space-y-3 ${className ?? ""}`, children: Array.from({ length: loadingCount }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "rounded-xl border p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "space-y-3", children: [
|
|
665
687
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex justify-between", children: [
|
|
@@ -673,14 +695,23 @@ function MobileCardList({
|
|
|
673
695
|
] })
|
|
674
696
|
] }) }, i)) });
|
|
675
697
|
}
|
|
676
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
698
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
677
699
|
"div",
|
|
678
700
|
{
|
|
679
|
-
className:
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
701
|
+
className: `space-y-3 ${className ?? ""}`,
|
|
702
|
+
onTouchStart,
|
|
703
|
+
onTouchMove,
|
|
704
|
+
onClickCapture,
|
|
705
|
+
children: data.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
706
|
+
"div",
|
|
707
|
+
{
|
|
708
|
+
className: "rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]",
|
|
709
|
+
children: renderCard(item, index)
|
|
710
|
+
},
|
|
711
|
+
keyExtractor(item)
|
|
712
|
+
))
|
|
713
|
+
}
|
|
714
|
+
);
|
|
684
715
|
}
|
|
685
716
|
|
|
686
717
|
// src/components/responsive-data-view.tsx
|
|
@@ -734,10 +765,10 @@ function Toaster(props) {
|
|
|
734
765
|
|
|
735
766
|
// src/components/app-shell.tsx
|
|
736
767
|
var import_lucide_react4 = require("lucide-react");
|
|
737
|
-
var
|
|
768
|
+
var import_react5 = require("react");
|
|
738
769
|
|
|
739
770
|
// src/components/sidebar-nav.tsx
|
|
740
|
-
var
|
|
771
|
+
var import_react4 = require("react");
|
|
741
772
|
|
|
742
773
|
// src/components/types.tsx
|
|
743
774
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
@@ -776,7 +807,7 @@ function SidebarNav({
|
|
|
776
807
|
!isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "truncate", children: item.label })
|
|
777
808
|
] })
|
|
778
809
|
});
|
|
779
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react4.Fragment, { children: link }, item.href);
|
|
780
811
|
}) });
|
|
781
812
|
}
|
|
782
813
|
|
|
@@ -866,8 +897,8 @@ function AppShell({
|
|
|
866
897
|
defaultCollapsed = false,
|
|
867
898
|
children
|
|
868
899
|
}) {
|
|
869
|
-
const [collapsed, setCollapsed] = (0,
|
|
870
|
-
const [mobileOpen, setMobileOpen] = (0,
|
|
900
|
+
const [collapsed, setCollapsed] = (0, import_react5.useState)(defaultCollapsed);
|
|
901
|
+
const [mobileOpen, setMobileOpen] = (0, import_react5.useState)(false);
|
|
871
902
|
const nav = (isCollapsed, onNavigate) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
872
903
|
SidebarNav,
|
|
873
904
|
{
|
|
@@ -1021,20 +1052,20 @@ function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
|
|
|
1021
1052
|
}
|
|
1022
1053
|
|
|
1023
1054
|
// src/hooks/use-disclosure.ts
|
|
1024
|
-
var
|
|
1055
|
+
var import_react6 = require("react");
|
|
1025
1056
|
function useDisclosure(initial = false) {
|
|
1026
|
-
const [open, setOpen] = (0,
|
|
1027
|
-
const onOpen = (0,
|
|
1028
|
-
const onClose = (0,
|
|
1029
|
-
const onToggle = (0,
|
|
1057
|
+
const [open, setOpen] = (0, import_react6.useState)(initial);
|
|
1058
|
+
const onOpen = (0, import_react6.useCallback)(() => setOpen(true), []);
|
|
1059
|
+
const onClose = (0, import_react6.useCallback)(() => setOpen(false), []);
|
|
1060
|
+
const onToggle = (0, import_react6.useCallback)(() => setOpen((v) => !v), []);
|
|
1030
1061
|
return { open, onOpen, onClose, onToggle, setOpen };
|
|
1031
1062
|
}
|
|
1032
1063
|
|
|
1033
1064
|
// src/hooks/use-toast.ts
|
|
1034
1065
|
var import_sonner2 = require("sonner");
|
|
1035
|
-
var
|
|
1066
|
+
var import_react7 = require("react");
|
|
1036
1067
|
function useCustomToast() {
|
|
1037
|
-
const showToast = (0,
|
|
1068
|
+
const showToast = (0, import_react7.useCallback)(
|
|
1038
1069
|
(title, description, status = "success") => {
|
|
1039
1070
|
switch (status) {
|
|
1040
1071
|
case "success":
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/theme-provider.tsx","../src/components/mode-toggle.tsx","../src/components/empty-state.tsx","../src/components/confirm-dialog.tsx","../src/components/page-header.tsx","../src/components/status-dot.tsx","../src/components/status-badge.tsx","../src/components/progress-bar.tsx","../src/components/form-field.tsx","../src/components/form-dialog.tsx","../src/lib/utils.ts","../src/components/auth-card.tsx","../src/components/pagination.tsx","../src/components/table-skeleton.tsx","../src/components/search-input.tsx","../src/components/stat-card.tsx","../src/components/data-table-wrapper.tsx","../src/components/mobile-card-list.tsx","../src/components/responsive-data-view.tsx","../src/components/toaster.tsx","../src/components/app-shell.tsx","../src/components/sidebar-nav.tsx","../src/components/types.tsx","../src/components/user-menu.tsx","../src/components/row-actions-menu.tsx","../src/lib/api-error.ts","../src/hooks/use-disclosure.ts","../src/hooks/use-toast.ts"],"sourcesContent":["// Theme\nexport { ThemeProvider, useTheme } from \"./components/theme-provider\"\nexport type { Theme, ThemeProviderProps, ThemeProviderState } from \"./components/theme-provider\"\n\n// Components\nexport { ModeToggle } from \"./components/mode-toggle\"\nexport { EmptyState } from \"./components/empty-state\"\nexport { ConfirmDialog } from \"./components/confirm-dialog\"\nexport { PageHeader } from \"./components/page-header\"\nexport { StatusDot } from \"./components/status-dot\"\nexport { StatusBadge } from \"./components/status-badge\"\nexport type { StatusBadgeVariant } from \"./components/status-badge\"\nexport { ProgressBar } from \"./components/progress-bar\"\nexport { FormField } from \"./components/form-field\"\nexport { FormDialogLayout, FormDialog } from \"./components/form-dialog\"\nexport type { FormDialogSize } from \"./components/form-dialog\"\nexport { AuthCard } from \"./components/auth-card\"\nexport { Pagination } from \"./components/pagination\"\nexport { TableSkeleton } from \"./components/table-skeleton\"\nexport { SearchInput } from \"./components/search-input\"\nexport { StatCard } from \"./components/stat-card\"\nexport { DataTableWrapper } from \"./components/data-table-wrapper\"\nexport { MobileCardList } from \"./components/mobile-card-list\"\nexport { ResponsiveDataView } from \"./components/responsive-data-view\"\nexport { Toaster } from \"./components/toaster\"\n\n// App shell\nexport { AppShell } from \"./components/app-shell\"\nexport type { AppShellProps } from \"./components/app-shell\"\nexport { SidebarNav } from \"./components/sidebar-nav\"\nexport type { NavItem, SidebarNavProps } from \"./components/sidebar-nav\"\nexport { UserMenu } from \"./components/user-menu\"\nexport type { AppUser, UserMenuItem, UserMenuProps } from \"./components/user-menu\"\nexport { RowActionsMenu } from \"./components/row-actions-menu\"\nexport type { RowAction, RowActionsMenuProps } from \"./components/row-actions-menu\"\nexport { defaultRenderLink } from \"./components/types\"\nexport type { RenderLink, RenderLinkProps } from \"./components/types\"\n\n// Utilities\nexport { cn } from \"./lib/utils\"\nexport { extractApiError } from \"./lib/api-error\"\n\n// Hooks\nexport { useDisclosure } from \"./hooks/use-disclosure\"\nexport { useCustomToast, toast } from \"./hooks/use-toast\"\n","import { createContext, useContext, useEffect, useState } from \"react\"\n\ntype Theme = \"dark\" | \"light\" | \"system\"\n\ntype ThemeProviderProps = {\n children: React.ReactNode\n defaultTheme?: Theme\n storageKey?: string\n}\n\ntype ThemeProviderState = {\n theme: Theme\n setTheme: (theme: Theme) => void\n}\n\nconst initialState: ThemeProviderState = {\n theme: \"system\",\n setTheme: () => null,\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState)\n\nexport function ThemeProvider({\n children,\n defaultTheme = \"system\",\n storageKey = \"ui-theme\",\n ...props\n}: ThemeProviderProps) {\n const [theme, setTheme] = useState<Theme>(\n () => (localStorage.getItem(storageKey) as Theme) || defaultTheme\n )\n\n useEffect(() => {\n const root = window.document.documentElement\n root.classList.remove(\"light\", \"dark\")\n if (theme === \"system\") {\n const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\"\n root.classList.add(systemTheme)\n return\n }\n root.classList.add(theme)\n }, [theme])\n\n const value = {\n theme,\n setTheme: (theme: Theme) => {\n localStorage.setItem(storageKey, theme)\n setTheme(theme)\n },\n }\n\n return (\n <ThemeProviderContext.Provider {...props} value={value}>\n {children}\n </ThemeProviderContext.Provider>\n )\n}\n\nexport function useTheme() {\n const context = useContext(ThemeProviderContext)\n if (context === undefined) {\n throw new Error(\"useTheme must be used within a ThemeProvider\")\n }\n return context\n}\n\nexport type { Theme, ThemeProviderProps, ThemeProviderState }\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { Moon, Sun, Monitor } from \"lucide-react\"\nimport { useTheme } from \"./theme-provider\"\n\nexport function ModeToggle() {\n const { setTheme } = useTheme()\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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\"\n aria-label=\"Alternar tema\"\n >\n <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute inset-0 m-auto h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align=\"end\"\n 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\"\n >\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"light\")}\n >\n <Sun className=\"h-4 w-4\" /> Claro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"dark\")}\n >\n <Moon className=\"h-4 w-4\" /> Escuro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"system\")}\n >\n <Monitor className=\"h-4 w-4\" /> Sistema\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface EmptyStateProps {\n icon?: ReactNode\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={`flex flex-col items-center justify-center py-16 text-center ${className ?? \"\"}`}>\n {icon && <div className=\"mb-4 text-muted-foreground\">{icon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{title}</h3>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n )\n}\n","import * as AlertDialog from \"@radix-ui/react-alert-dialog\"\nimport type { ReactNode } from \"react\"\n\ninterface ConfirmDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n title: string\n description: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n loading?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nexport function ConfirmDialog({\n open,\n onOpenChange,\n onConfirm,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n loading = false,\n variant = \"default\",\n}: ConfirmDialogProps) {\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Portal>\n <AlertDialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <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\">\n <div className=\"flex flex-col space-y-2 text-center sm:text-left\">\n <AlertDialog.Title className=\"text-lg font-semibold\">{title}</AlertDialog.Title>\n <AlertDialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </AlertDialog.Description>\n </div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <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\">\n {cancelLabel}\n </AlertDialog.Cancel>\n <AlertDialog.Action\n onClick={onConfirm}\n disabled={loading}\n 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 ${\n variant === \"destructive\"\n ? \"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n : \"bg-primary text-primary-foreground hover:bg-primary/90\"\n }`}\n >\n {loading ? \"Aguarde...\" : confirmLabel}\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface PageHeaderProps {\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function PageHeader({ title, description, action, className }: PageHeaderProps) {\n return (\n <div\n className={`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? \"\"}`}\n >\n <div className=\"min-w-0\">\n <h1 className=\"truncate text-2xl font-semibold tracking-tight\">\n {title}\n </h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n","interface StatusDotProps {\n active: boolean\n label?: string\n className?: string\n}\n\nexport function StatusDot({ active, label, className }: StatusDotProps) {\n return (\n <span className={`inline-flex items-center gap-2 ${className ?? \"\"}`}>\n <span\n className={`h-2 w-2 rounded-full ${active ? \"bg-green-500\" : \"bg-red-500\"}`}\n />\n {label && <span>{label}</span>}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport type StatusBadgeVariant =\n | \"neutral\"\n | \"info\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n\ninterface StatusBadgeProps {\n variant?: StatusBadgeVariant\n dot?: boolean\n className?: string\n children: ReactNode\n}\n\nconst variantClasses: Record<\n StatusBadgeVariant,\n { badge: string; dot: string }\n> = {\n neutral: {\n badge: \"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300\",\n dot: \"bg-gray-400\",\n },\n info: {\n badge: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400\",\n dot: \"bg-blue-500\",\n },\n success: {\n badge: \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-400\",\n dot: \"bg-green-500\",\n },\n danger: {\n badge: \"bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400\",\n dot: \"bg-red-500\",\n },\n warning: {\n badge: \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400\",\n dot: \"bg-amber-500\",\n },\n}\n\nexport function StatusBadge({\n variant = \"neutral\",\n dot = true,\n className,\n children,\n}: StatusBadgeProps) {\n const classes = variantClasses[variant]\n\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium ${classes.badge} ${className ?? \"\"}`}\n >\n {dot && (\n <span\n className={`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${classes.dot}`}\n />\n )}\n {children}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ProgressBarProps {\n value: number\n size?: \"sm\" | \"md\"\n label?: ReactNode\n valueLabel?: ReactNode\n className?: string\n indicatorClassName?: string\n}\n\nconst sizeClasses = {\n sm: \"h-1.5\",\n md: \"h-2\",\n} as const\n\nexport function ProgressBar({\n value,\n size = \"md\",\n label,\n valueLabel,\n className,\n indicatorClassName,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value))\n\n return (\n <div className={`space-y-1.5 ${className ?? \"\"}`}>\n {(label || valueLabel) && (\n <div className=\"flex items-baseline justify-between gap-2\">\n {label && (\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n )}\n {valueLabel && (\n <span className=\"text-sm font-semibold\">{valueLabel}</span>\n )}\n </div>\n )}\n <div\n className={`w-full overflow-hidden rounded-full bg-muted ${sizeClasses[size]}`}\n >\n <div\n className={`h-full rounded-full transition-all duration-300 ${indicatorClassName ?? \"bg-primary\"}`}\n style={{ width: `${clamped}%` }}\n />\n </div>\n </div>\n )\n}\n","import { type ReactElement, type ReactNode, cloneElement, isValidElement, useId } from \"react\"\n\ninterface FormFieldProps {\n label: string\n htmlFor?: string\n error?: string\n required?: boolean\n children: ReactNode\n className?: string\n}\n\nexport function FormField({ label, htmlFor, error, required, children, className }: FormFieldProps) {\n const errorId = useId()\n\n // Wire accessibility onto the control: mark it invalid and point it at the\n // error message so screen readers announce both.\n const field =\n error && isValidElement(children)\n ? cloneElement(children as ReactElement<Record<string, unknown>>, {\n \"aria-invalid\": true,\n \"aria-describedby\": [\n (children.props as Record<string, unknown>)[\"aria-describedby\"],\n errorId,\n ]\n .filter(Boolean)\n .join(\" \"),\n })\n : children\n\n return (\n <div className={`space-y-2 ${className ?? \"\"}`}>\n <label\n htmlFor={htmlFor}\n className=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n {required && <span className=\"ml-1 text-destructive\">*</span>}\n </label>\n {field}\n {error && (\n <p id={errorId} className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n </div>\n )\n}\n","import * as Dialog from \"@radix-ui/react-dialog\"\nimport { X } from \"lucide-react\"\nimport * as React from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\ninterface FormDialogLayoutProps {\n title: string\n children: ReactNode\n onSubmit: (e: React.FormEvent) => void\n submitLabel?: string\n cancelLabel?: string\n onCancel: () => void\n isSubmitting?: boolean\n isDisabled?: boolean\n}\n\nexport function FormDialogLayout({\n title,\n children,\n onSubmit,\n submitLabel = \"Salvar\",\n cancelLabel = \"Cancelar\",\n onCancel,\n isSubmitting = false,\n isDisabled = false,\n}: FormDialogLayoutProps) {\n return (\n <form onSubmit={onSubmit}>\n <div className=\"flex flex-col space-y-1.5 text-center sm:text-left\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">{title}</h2>\n </div>\n <div className=\"space-y-4 py-4\">{children}</div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <button\n type=\"button\"\n onClick={onCancel}\n 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\"\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || isDisabled}\n 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\"\n >\n {isSubmitting ? \"Salvando...\" : submitLabel}\n </button>\n </div>\n </form>\n )\n}\n\nconst sizeClasses = {\n sm: \"sm:max-w-sm\",\n md: \"sm:max-w-md\",\n lg: \"sm:max-w-lg\",\n xl: \"sm:max-w-xl\",\n \"2xl\": \"sm:max-w-2xl\",\n} as const\n\nexport type FormDialogSize = keyof typeof sizeClasses\n\ninterface FormDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n description?: ReactNode\n children: ReactNode\n footer?: ReactNode\n /** When provided, the dialog renders a <form> wrapping body + footer. */\n onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void\n size?: FormDialogSize\n className?: string\n}\n\n/**\n * Standardized, responsive modal:\n * - mobile: bottom sheet (full width, up to 92vh tall)\n * - desktop: centered dialog (up to 90vh tall)\n * Header and footer stay fixed; only the body scrolls.\n *\n * Also fixes the known Radix bug where `body { pointer-events: none }`\n * can persist after closing a dialog that contained a Select/Popover,\n * which would otherwise make the rest of the page unclickable.\n */\nexport function FormDialog({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n onSubmit,\n size = \"lg\",\n className,\n}: FormDialogProps) {\n React.useEffect(() => {\n if (open) return\n const id = window.setTimeout(() => {\n if (document.body.style.pointerEvents === \"none\") {\n document.body.style.pointerEvents = \"\"\n }\n }, 0)\n return () => window.clearTimeout(id)\n }, [open])\n\n const body = (\n <>\n <div className=\"flex shrink-0 items-start justify-between gap-4 border-b px-6 py-3\">\n <div className=\"min-w-0 space-y-1\">\n <Dialog.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </Dialog.Title>\n {description && (\n <Dialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </Dialog.Description>\n )}\n </div>\n <Dialog.Close\n 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\"\n aria-label=\"Fechar\"\n >\n <X className=\"h-5 w-5\" />\n </Dialog.Close>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-6 py-4\">{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-3 sm:flex-row sm:justify-end\">\n {footer}\n </div>\n )}\n </>\n )\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <Dialog.Content\n onCloseAutoFocus={() => {\n document.body.style.pointerEvents = \"\"\n }}\n className={cn(\n \"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none\",\n \"inset-x-0 bottom-0 rounded-t-2xl\",\n \"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\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n sizeClasses[size],\n className,\n )}\n >\n {onSubmit ? (\n <form\n onSubmit={onSubmit}\n className=\"flex min-h-0 flex-1 flex-col\"\n >\n {body}\n </form>\n ) : (\n body\n )}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthCardProps {\n title: string\n description?: string\n children: ReactNode\n footer?: ReactNode\n}\n\nexport function AuthCard({ title, description, children, footer }: AuthCardProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"mb-6 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n <div className=\"space-y-4\">{children}</div>\n {footer && <div className=\"mt-4\">{footer}</div>}\n </div>\n </div>\n )\n}\n","interface PaginationProps {\n page: number\n onPageChange: (page: number) => void\n hasNextPage: boolean\n hasPreviousPage: boolean\n className?: string\n}\n\nexport function Pagination({ page, onPageChange, hasNextPage, hasPreviousPage, className }: PaginationProps) {\n return (\n <div className={`flex items-center justify-end gap-4 ${className ?? \"\"}`}>\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )\n}\n","interface TableSkeletonProps {\n rows?: number\n columns?: number\n}\n\nexport function TableSkeleton({ rows = 5, columns = 4 }: TableSkeletonProps) {\n return (\n <>\n {Array.from({ length: rows }).map((_, i) => (\n <tr key={i} className=\"border-b transition-colors\">\n {Array.from({ length: columns }).map((_, j) => (\n <td key={j} className=\"p-4 align-middle\">\n <div className=\"h-5 w-full animate-pulse rounded bg-muted\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n )\n}\n","import * as React from \"react\"\n\ninterface SearchInputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n containerClassName?: string\n}\n\nexport const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ containerClassName, className, ...props }, ref) => {\n return (\n <div className={`relative flex-1 ${containerClassName ?? \"\"}`}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n <input\n ref={ref}\n type=\"text\"\n 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 ?? \"\"}`}\n {...props}\n />\n </div>\n )\n }\n)\nSearchInput.displayName = \"SearchInput\"\n","import type { ReactNode } from \"react\"\n\ninterface StatCardProps {\n label: string\n value: ReactNode\n detail?: string\n icon?: ReactNode\n isLoading?: boolean\n}\n\nexport function StatCard({ label, value, detail, icon, isLoading }: StatCardProps) {\n if (isLoading) {\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-4 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"mt-2 h-7 w-16 animate-pulse rounded bg-muted\" />\n <div className=\"mt-1 h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n )\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <span className=\"text-sm font-medium text-muted-foreground\">{label}</span>\n {icon && <span className=\"text-muted-foreground\">{icon}</span>}\n </div>\n <div className=\"text-2xl font-bold\">{value}</div>\n {detail && <p className=\"text-xs text-muted-foreground\">{detail}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface DataTableWrapperProps {\n children: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n page?: number\n onPageChange?: (page: number) => void\n hasNextPage?: boolean\n hasPreviousPage?: boolean\n}\n\nexport function DataTableWrapper({\n children,\n isEmpty,\n isLoading,\n emptyIcon,\n emptyTitle = \"Nenhum registro encontrado\",\n emptyDescription,\n page,\n onPageChange,\n hasNextPage = false,\n hasPreviousPage = false,\n}: DataTableWrapperProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-md border\">{children}</div>\n\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>\n )}\n </div>\n )}\n\n {page !== undefined && onPageChange && (\n <div className=\"flex items-center justify-end gap-4\">\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface MobileCardListProps<T> {\n data: T[]\n renderCard: (item: T, index: number) => ReactNode\n keyExtractor: (item: T) => string\n isLoading?: boolean\n loadingCount?: number\n className?: string\n}\n\nexport function MobileCardList<T>({\n data,\n renderCard,\n keyExtractor,\n isLoading = false,\n loadingCount = 5,\n className,\n}: MobileCardListProps<T>) {\n if (isLoading) {\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {Array.from({ length: loadingCount }).map((_, i) => (\n <div key={i} className=\"rounded-xl border p-4\">\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <div className=\"h-5 w-32 animate-pulse rounded bg-muted\" />\n <div className=\"h-5 w-16 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"h-4 w-48 animate-pulse rounded bg-muted\" />\n <div className=\"flex justify-between\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {data.map((item, index) => (\n <div\n key={keyExtractor(item)}\n className=\"rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]\"\n >\n {renderCard(item, index)}\n </div>\n ))}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ResponsiveDataViewProps {\n table: ReactNode\n cards: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n pagination?: ReactNode\n}\n\nexport function ResponsiveDataView({\n table, cards, isEmpty, isLoading, emptyIcon, emptyTitle = \"Nenhum registro encontrado\", emptyDescription, pagination,\n}: ResponsiveDataViewProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"hidden overflow-x-auto rounded-md border md:block\">{table}</div>\n <div className=\"md:hidden\">{cards}</div>\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>}\n </div>\n )}\n {pagination}\n </div>\n )\n}\n","import { useTheme } from \"./theme-provider\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps<typeof Sonner>\n\nexport function Toaster(props: ToasterProps) {\n const { theme = \"system\" } = useTheme()\n\n return (\n <Sonner\n theme={theme as ToasterProps[\"theme\"]}\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n success:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40\",\n error:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40\",\n },\n }}\n {...props}\n />\n )\n}\n","import { ChevronLeft, ChevronRight, Menu } from \"lucide-react\"\nimport { type ReactNode, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { SidebarNav, type NavItem } from \"./sidebar-nav\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\nimport { UserMenu, type AppUser, type UserMenuItem } from \"./user-menu\"\n\nexport interface AppShellProps {\n brand: ReactNode\n brandCollapsed?: ReactNode\n navItems: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n user?: AppUser\n userMenuItems?: UserMenuItem[]\n onLogout?: () => void\n renderLink?: RenderLink\n headerActions?: ReactNode\n collapsible?: boolean\n defaultCollapsed?: boolean\n children: ReactNode\n}\n\nexport function AppShell({\n brand,\n brandCollapsed,\n navItems,\n activePath,\n isActive,\n isAdmin = false,\n user,\n userMenuItems,\n onLogout,\n renderLink = defaultRenderLink,\n headerActions,\n collapsible = true,\n defaultCollapsed = false,\n children,\n}: AppShellProps) {\n const [collapsed, setCollapsed] = useState(defaultCollapsed)\n const [mobileOpen, setMobileOpen] = useState(false)\n\n const nav = (isCollapsed: boolean, onNavigate?: () => void) => (\n <SidebarNav\n items={navItems}\n activePath={activePath}\n isActive={isActive}\n isAdmin={isAdmin}\n isCollapsed={isCollapsed}\n renderLink={renderLink}\n onNavigate={onNavigate}\n />\n )\n\n return (\n <div className=\"flex h-screen overflow-hidden bg-background\">\n {/* Desktop sidebar */}\n <aside\n className={cn(\n \"hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex\",\n collapsed ? \"w-16\" : \"w-60\",\n )}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(collapsed)}</div>\n {collapsible && (\n <div className=\"border-t p-2\">\n <button\n type=\"button\"\n onClick={() => setCollapsed((v) => !v)}\n 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\"\n aria-label={collapsed ? \"Expandir menu\" : \"Recolher menu\"}\n >\n {collapsed ? <ChevronRight className=\"h-4 w-4\" /> : <ChevronLeft className=\"h-4 w-4\" />}\n </button>\n </div>\n )}\n </aside>\n\n {/* Mobile drawer */}\n <div\n className={cn(\n \"fixed inset-0 z-50 transition-opacity duration-300 md:hidden\",\n mobileOpen ? \"pointer-events-auto opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n onClick={() => setMobileOpen(false)}\n >\n <div className=\"absolute inset-0 bg-black/50\" />\n <div\n className={cn(\n \"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">{brand}</div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(false, () => setMobileOpen(false))}</div>\n </div>\n </div>\n\n {/* Main column */}\n <div className=\"flex flex-1 flex-col overflow-hidden\">\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4\">\n <button\n type=\"button\"\n onClick={() => setMobileOpen(true)}\n 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\"\n aria-label=\"Abrir menu\"\n >\n <Menu className=\"h-4 w-4\" />\n </button>\n <div className=\"ml-auto flex items-center gap-2\">\n {headerActions}\n {(user || onLogout) && (\n <UserMenu user={user} items={userMenuItems} onLogout={onLogout} renderLink={renderLink} />\n )}\n </div>\n </header>\n <main className=\"flex-1 overflow-y-auto\">{children}</main>\n </div>\n </div>\n )\n}\n","import { Fragment, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface NavItem {\n label: string\n href: string\n icon?: ReactNode\n adminOnly?: boolean\n}\n\nexport interface SidebarNavProps {\n items: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n isCollapsed?: boolean\n renderLink?: RenderLink\n onNavigate?: () => void\n}\n\nfunction defaultIsActive(item: NavItem, activePath: string): boolean {\n if (item.href === \"/\") return activePath === \"/\"\n return activePath === item.href || activePath.startsWith(item.href + \"/\")\n}\n\nexport function SidebarNav({\n items,\n activePath,\n isActive = defaultIsActive,\n isAdmin = false,\n isCollapsed = false,\n renderLink = defaultRenderLink,\n onNavigate,\n}: SidebarNavProps) {\n const visible = items.filter((item) => !item.adminOnly || isAdmin)\n\n return (\n <nav className=\"flex flex-col gap-1\">\n {visible.map((item) => {\n const active = isActive(item, activePath)\n const link = renderLink({\n href: item.href,\n onClick: onNavigate,\n title: isCollapsed ? item.label : undefined,\n \"aria-current\": active ? \"page\" : undefined,\n className: cn(\n \"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\n active\n ? \"bg-accent text-accent-foreground font-semibold\"\n : \"text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n isCollapsed && \"justify-center px-2\",\n ),\n children: (\n <>\n {item.icon && <span className=\"shrink-0\">{item.icon}</span>}\n {!isCollapsed && <span className=\"truncate\">{item.label}</span>}\n </>\n ),\n })\n return <Fragment key={item.href}>{link}</Fragment>\n })}\n </nav>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport interface RenderLinkProps {\n href: string\n className?: string\n children: ReactNode\n onClick?: () => void\n title?: string\n \"aria-current\"?: \"page\"\n}\n\nexport type RenderLink = (props: RenderLinkProps) => ReactNode\n\nexport const defaultRenderLink: RenderLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n)\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { LogOut, User } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface AppUser {\n name?: string\n email?: string\n avatarUrl?: string\n}\n\nexport interface UserMenuItem {\n label: string\n icon?: ReactNode\n href?: string\n onClick?: () => void\n}\n\nexport interface UserMenuProps {\n user?: AppUser\n items?: UserMenuItem[]\n onLogout?: () => void\n logoutLabel?: string\n renderLink?: RenderLink\n align?: \"start\" | \"center\" | \"end\"\n}\n\nfunction initials(user?: AppUser): string {\n const source = user?.name?.trim() || user?.email?.trim()\n if (!source) return \"\"\n const parts = source.split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n return source.slice(0, 2).toUpperCase()\n}\n\nconst itemClass =\n \"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\"\n\nexport function UserMenu({\n user,\n items = [],\n onLogout,\n logoutLabel = \"Sair\",\n renderLink = defaultRenderLink,\n align = \"end\",\n}: UserMenuProps) {\n const label = initials(user)\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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-1 focus-visible:ring-ring\"\n aria-label=\"Menu do usuário\"\n data-testid=\"user-menu\"\n >\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt={user.name ?? user.email ?? \"Avatar\"} className=\"h-full w-full object-cover\" />\n ) : label ? (\n <span>{label}</span>\n ) : (\n <User className=\"h-4 w-4\" />\n )}\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {(user?.name || user?.email) && (\n <>\n <div className=\"px-2 py-1.5\">\n {user.name && <p className=\"truncate text-sm font-medium\">{user.name}</p>}\n {user.email && <p className=\"truncate text-xs text-muted-foreground\">{user.email}</p>}\n </div>\n <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />\n </>\n )}\n\n {items.map((item) =>\n item.href ? (\n <DropdownMenu.Item key={item.label} asChild>\n {renderLink({ href: item.href, className: itemClass, children: (\n <>\n {item.icon}\n {item.label}\n </>\n ) })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item key={item.label} className={itemClass} onClick={item.onClick}>\n {item.icon}\n {item.label}\n </DropdownMenu.Item>\n ),\n )}\n\n {onLogout && (\n <>\n {items.length > 0 && <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />}\n <DropdownMenu.Item className={cn(itemClass, \"text-destructive focus:bg-destructive/10\")} onClick={onLogout}>\n <LogOut className=\"h-4 w-4\" />\n {logoutLabel}\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { MoreVertical } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface RowAction {\n label: string\n icon?: ReactNode\n onClick?: () => void\n href?: string\n destructive?: boolean\n disabled?: boolean\n}\n\nexport interface RowActionsMenuProps {\n actions: RowAction[]\n disabled?: boolean\n align?: \"start\" | \"center\" | \"end\"\n label?: string\n renderLink?: RenderLink\n}\n\nconst itemClass =\n \"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\"\n\nexport function RowActionsMenu({\n actions,\n disabled = false,\n align = \"end\",\n label = \"Ações\",\n renderLink = defaultRenderLink,\n}: RowActionsMenuProps) {\n if (actions.length === 0) return null\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={label}\n className=\"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-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {actions.map((action) => {\n const cls = cn(itemClass, action.destructive && \"text-destructive focus:bg-destructive/10\")\n return action.href ? (\n <DropdownMenu.Item key={action.label} asChild disabled={action.disabled}>\n {renderLink({\n href: action.href,\n className: cls,\n children: (\n <>\n {action.icon}\n {action.label}\n </>\n ),\n })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item\n key={action.label}\n className={cls}\n disabled={action.disabled}\n onClick={action.onClick}\n >\n {action.icon}\n {action.label}\n </DropdownMenu.Item>\n )\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","export function extractApiError(err: any, fallbackMessage = \"Ocorreu um erro inesperado.\"): string {\n const detail = err?.body?.detail || err?.message\n if (Array.isArray(detail) && detail.length > 0) {\n return detail[0].msg\n }\n return detail || fallbackMessage\n}\n","import { useCallback, useState } from \"react\"\n\nexport function useDisclosure(initial = false) {\n const [open, setOpen] = useState(initial)\n const onOpen = useCallback(() => setOpen(true), [])\n const onClose = useCallback(() => setOpen(false), [])\n const onToggle = useCallback(() => setOpen((v) => !v), [])\n return { open, onOpen, onClose, onToggle, setOpen }\n}\n","import { toast } from \"sonner\"\nimport { useCallback } from \"react\"\n\ntype ToastStatus = \"success\" | \"error\" | \"info\" | \"warning\"\n\nexport function useCustomToast() {\n const showToast = useCallback(\n (title: string, description?: string, status: ToastStatus = \"success\") => {\n switch (status) {\n case \"success\":\n toast.success(title, { description })\n break\n case \"error\":\n toast.error(title, { description })\n break\n case \"info\":\n toast.info(title, { description })\n break\n case \"warning\":\n toast.warning(title, { description })\n break\n }\n },\n [],\n )\n\n return showToast\n}\n\nexport { toast }\n"],"mappings":"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","names":["theme","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","sizeClasses","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","_","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","Sonner","import_lucide_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","DropdownMenu","import_lucide_react","import_jsx_runtime","import_jsx_runtime","DropdownMenu","import_lucide_react","import_jsx_runtime","itemClass","import_react","import_sonner","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/theme-provider.tsx","../src/components/mode-toggle.tsx","../src/components/empty-state.tsx","../src/components/confirm-dialog.tsx","../src/components/page-header.tsx","../src/components/status-dot.tsx","../src/components/status-badge.tsx","../src/components/progress-bar.tsx","../src/components/form-field.tsx","../src/components/form-dialog.tsx","../src/lib/utils.ts","../src/components/auth-card.tsx","../src/components/pagination.tsx","../src/components/table-skeleton.tsx","../src/components/search-input.tsx","../src/components/stat-card.tsx","../src/components/data-table-wrapper.tsx","../src/components/mobile-card-list.tsx","../src/components/responsive-data-view.tsx","../src/components/toaster.tsx","../src/components/app-shell.tsx","../src/components/sidebar-nav.tsx","../src/components/types.tsx","../src/components/user-menu.tsx","../src/components/row-actions-menu.tsx","../src/lib/api-error.ts","../src/hooks/use-disclosure.ts","../src/hooks/use-toast.ts"],"sourcesContent":["// Theme\nexport { ThemeProvider, useTheme } from \"./components/theme-provider\"\nexport type { Theme, ThemeProviderProps, ThemeProviderState } from \"./components/theme-provider\"\n\n// Components\nexport { ModeToggle } from \"./components/mode-toggle\"\nexport { EmptyState } from \"./components/empty-state\"\nexport { ConfirmDialog } from \"./components/confirm-dialog\"\nexport { PageHeader } from \"./components/page-header\"\nexport { StatusDot } from \"./components/status-dot\"\nexport { StatusBadge } from \"./components/status-badge\"\nexport type { StatusBadgeVariant } from \"./components/status-badge\"\nexport { ProgressBar } from \"./components/progress-bar\"\nexport { FormField } from \"./components/form-field\"\nexport { FormDialogLayout, FormDialog } from \"./components/form-dialog\"\nexport type { FormDialogSize } from \"./components/form-dialog\"\nexport { AuthCard } from \"./components/auth-card\"\nexport { Pagination } from \"./components/pagination\"\nexport { TableSkeleton } from \"./components/table-skeleton\"\nexport { SearchInput } from \"./components/search-input\"\nexport { StatCard } from \"./components/stat-card\"\nexport { DataTableWrapper } from \"./components/data-table-wrapper\"\nexport { MobileCardList } from \"./components/mobile-card-list\"\nexport { ResponsiveDataView } from \"./components/responsive-data-view\"\nexport { Toaster } from \"./components/toaster\"\n\n// App shell\nexport { AppShell } from \"./components/app-shell\"\nexport type { AppShellProps } from \"./components/app-shell\"\nexport { SidebarNav } from \"./components/sidebar-nav\"\nexport type { NavItem, SidebarNavProps } from \"./components/sidebar-nav\"\nexport { UserMenu } from \"./components/user-menu\"\nexport type { AppUser, UserMenuItem, UserMenuProps } from \"./components/user-menu\"\nexport { RowActionsMenu } from \"./components/row-actions-menu\"\nexport type { RowAction, RowActionsMenuProps } from \"./components/row-actions-menu\"\nexport { defaultRenderLink } from \"./components/types\"\nexport type { RenderLink, RenderLinkProps } from \"./components/types\"\n\n// Utilities\nexport { cn } from \"./lib/utils\"\nexport { extractApiError } from \"./lib/api-error\"\n\n// Hooks\nexport { useDisclosure } from \"./hooks/use-disclosure\"\nexport { useCustomToast, toast } from \"./hooks/use-toast\"\n","import { createContext, useContext, useEffect, useState } from \"react\"\n\ntype Theme = \"dark\" | \"light\" | \"system\"\n\ntype ThemeProviderProps = {\n children: React.ReactNode\n defaultTheme?: Theme\n storageKey?: string\n}\n\ntype ThemeProviderState = {\n theme: Theme\n setTheme: (theme: Theme) => void\n}\n\nconst initialState: ThemeProviderState = {\n theme: \"system\",\n setTheme: () => null,\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState)\n\nexport function ThemeProvider({\n children,\n defaultTheme = \"system\",\n storageKey = \"ui-theme\",\n ...props\n}: ThemeProviderProps) {\n const [theme, setTheme] = useState<Theme>(\n () => (localStorage.getItem(storageKey) as Theme) || defaultTheme\n )\n\n useEffect(() => {\n const root = window.document.documentElement\n root.classList.remove(\"light\", \"dark\")\n if (theme === \"system\") {\n const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\"\n root.classList.add(systemTheme)\n return\n }\n root.classList.add(theme)\n }, [theme])\n\n const value = {\n theme,\n setTheme: (theme: Theme) => {\n localStorage.setItem(storageKey, theme)\n setTheme(theme)\n },\n }\n\n return (\n <ThemeProviderContext.Provider {...props} value={value}>\n {children}\n </ThemeProviderContext.Provider>\n )\n}\n\nexport function useTheme() {\n const context = useContext(ThemeProviderContext)\n if (context === undefined) {\n throw new Error(\"useTheme must be used within a ThemeProvider\")\n }\n return context\n}\n\nexport type { Theme, ThemeProviderProps, ThemeProviderState }\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { Moon, Sun, Monitor } from \"lucide-react\"\nimport { useTheme } from \"./theme-provider\"\n\nexport function ModeToggle() {\n const { setTheme } = useTheme()\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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\"\n aria-label=\"Alternar tema\"\n >\n <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute inset-0 m-auto h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align=\"end\"\n 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\"\n >\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"light\")}\n >\n <Sun className=\"h-4 w-4\" /> Claro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"dark\")}\n >\n <Moon className=\"h-4 w-4\" /> Escuro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"system\")}\n >\n <Monitor className=\"h-4 w-4\" /> Sistema\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface EmptyStateProps {\n icon?: ReactNode\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={`flex flex-col items-center justify-center py-16 text-center ${className ?? \"\"}`}>\n {icon && <div className=\"mb-4 text-muted-foreground\">{icon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{title}</h3>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n )\n}\n","import * as AlertDialog from \"@radix-ui/react-alert-dialog\"\nimport type { ReactNode } from \"react\"\n\ninterface ConfirmDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n title: string\n description: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n loading?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nexport function ConfirmDialog({\n open,\n onOpenChange,\n onConfirm,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n loading = false,\n variant = \"default\",\n}: ConfirmDialogProps) {\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Portal>\n <AlertDialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <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\">\n <div className=\"flex flex-col space-y-2 text-center sm:text-left\">\n <AlertDialog.Title className=\"text-lg font-semibold\">{title}</AlertDialog.Title>\n <AlertDialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </AlertDialog.Description>\n </div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <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\">\n {cancelLabel}\n </AlertDialog.Cancel>\n <AlertDialog.Action\n onClick={onConfirm}\n disabled={loading}\n 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 ${\n variant === \"destructive\"\n ? \"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n : \"bg-primary text-primary-foreground hover:bg-primary/90\"\n }`}\n >\n {loading ? \"Aguarde...\" : confirmLabel}\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface PageHeaderProps {\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function PageHeader({ title, description, action, className }: PageHeaderProps) {\n return (\n <div\n className={`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? \"\"}`}\n >\n <div className=\"min-w-0\">\n <h1 className=\"truncate text-2xl font-semibold tracking-tight\">\n {title}\n </h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n","interface StatusDotProps {\n active: boolean\n label?: string\n className?: string\n}\n\nexport function StatusDot({ active, label, className }: StatusDotProps) {\n return (\n <span className={`inline-flex items-center gap-2 ${className ?? \"\"}`}>\n <span\n className={`h-2 w-2 rounded-full ${active ? \"bg-green-500\" : \"bg-red-500\"}`}\n />\n {label && <span>{label}</span>}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport type StatusBadgeVariant =\n | \"neutral\"\n | \"info\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n\ninterface StatusBadgeProps {\n variant?: StatusBadgeVariant\n dot?: boolean\n className?: string\n children: ReactNode\n}\n\nconst variantClasses: Record<\n StatusBadgeVariant,\n { badge: string; dot: string }\n> = {\n neutral: {\n badge: \"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300\",\n dot: \"bg-gray-400\",\n },\n info: {\n badge: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400\",\n dot: \"bg-blue-500\",\n },\n success: {\n badge: \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-400\",\n dot: \"bg-green-500\",\n },\n danger: {\n badge: \"bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400\",\n dot: \"bg-red-500\",\n },\n warning: {\n badge: \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400\",\n dot: \"bg-amber-500\",\n },\n}\n\nexport function StatusBadge({\n variant = \"neutral\",\n dot = true,\n className,\n children,\n}: StatusBadgeProps) {\n const classes = variantClasses[variant]\n\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium ${classes.badge} ${className ?? \"\"}`}\n >\n {dot && (\n <span\n className={`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${classes.dot}`}\n />\n )}\n {children}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ProgressBarProps {\n value: number\n size?: \"sm\" | \"md\"\n label?: ReactNode\n valueLabel?: ReactNode\n className?: string\n indicatorClassName?: string\n}\n\nconst sizeClasses = {\n sm: \"h-1.5\",\n md: \"h-2\",\n} as const\n\nexport function ProgressBar({\n value,\n size = \"md\",\n label,\n valueLabel,\n className,\n indicatorClassName,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value))\n\n return (\n <div className={`space-y-1.5 ${className ?? \"\"}`}>\n {(label || valueLabel) && (\n <div className=\"flex items-baseline justify-between gap-2\">\n {label && (\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n )}\n {valueLabel && (\n <span className=\"text-sm font-semibold\">{valueLabel}</span>\n )}\n </div>\n )}\n <div\n className={`w-full overflow-hidden rounded-full bg-muted ${sizeClasses[size]}`}\n >\n <div\n className={`h-full rounded-full transition-all duration-300 ${indicatorClassName ?? \"bg-primary\"}`}\n style={{ width: `${clamped}%` }}\n />\n </div>\n </div>\n )\n}\n","import { type ReactElement, type ReactNode, cloneElement, isValidElement, useId } from \"react\"\n\ninterface FormFieldProps {\n label: string\n htmlFor?: string\n error?: string\n required?: boolean\n children: ReactNode\n className?: string\n}\n\nexport function FormField({ label, htmlFor, error, required, children, className }: FormFieldProps) {\n const errorId = useId()\n\n // Wire accessibility onto the control: mark it invalid and point it at the\n // error message so screen readers announce both.\n const field =\n error && isValidElement(children)\n ? cloneElement(children as ReactElement<Record<string, unknown>>, {\n \"aria-invalid\": true,\n \"aria-describedby\": [\n (children.props as Record<string, unknown>)[\"aria-describedby\"],\n errorId,\n ]\n .filter(Boolean)\n .join(\" \"),\n })\n : children\n\n return (\n <div className={`space-y-2 ${className ?? \"\"}`}>\n <label\n htmlFor={htmlFor}\n className=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n {required && <span className=\"ml-1 text-destructive\">*</span>}\n </label>\n {field}\n {error && (\n <p id={errorId} className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n </div>\n )\n}\n","import * as Dialog from \"@radix-ui/react-dialog\"\nimport { X } from \"lucide-react\"\nimport * as React from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\ninterface FormDialogLayoutProps {\n title: string\n children: ReactNode\n onSubmit: (e: React.FormEvent) => void\n submitLabel?: string\n cancelLabel?: string\n onCancel: () => void\n isSubmitting?: boolean\n isDisabled?: boolean\n}\n\nexport function FormDialogLayout({\n title,\n children,\n onSubmit,\n submitLabel = \"Salvar\",\n cancelLabel = \"Cancelar\",\n onCancel,\n isSubmitting = false,\n isDisabled = false,\n}: FormDialogLayoutProps) {\n return (\n <form onSubmit={onSubmit}>\n <div className=\"flex flex-col space-y-1.5 text-center sm:text-left\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">{title}</h2>\n </div>\n <div className=\"space-y-4 py-4\">{children}</div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <button\n type=\"button\"\n onClick={onCancel}\n 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\"\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || isDisabled}\n 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\"\n >\n {isSubmitting ? \"Salvando...\" : submitLabel}\n </button>\n </div>\n </form>\n )\n}\n\nconst sizeClasses = {\n sm: \"sm:max-w-sm\",\n md: \"sm:max-w-md\",\n lg: \"sm:max-w-lg\",\n xl: \"sm:max-w-xl\",\n \"2xl\": \"sm:max-w-2xl\",\n} as const\n\nexport type FormDialogSize = keyof typeof sizeClasses\n\ninterface FormDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n description?: ReactNode\n children: ReactNode\n footer?: ReactNode\n /** When provided, the dialog renders a <form> wrapping body + footer. */\n onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void\n size?: FormDialogSize\n className?: string\n}\n\n/**\n * Standardized, responsive modal:\n * - mobile: bottom sheet (full width, up to 92vh tall)\n * - desktop: centered dialog (up to 90vh tall)\n * Header and footer stay fixed; only the body scrolls.\n *\n * Also fixes the known Radix bug where `body { pointer-events: none }`\n * can persist after closing a dialog that contained a Select/Popover,\n * which would otherwise make the rest of the page unclickable.\n */\nexport function FormDialog({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n onSubmit,\n size = \"lg\",\n className,\n}: FormDialogProps) {\n React.useEffect(() => {\n if (open) return\n const id = window.setTimeout(() => {\n if (document.body.style.pointerEvents === \"none\") {\n document.body.style.pointerEvents = \"\"\n }\n }, 0)\n return () => window.clearTimeout(id)\n }, [open])\n\n const body = (\n <>\n <div className=\"flex shrink-0 items-start justify-between gap-4 border-b px-6 py-3\">\n <div className=\"min-w-0 space-y-1\">\n <Dialog.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </Dialog.Title>\n {description && (\n <Dialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </Dialog.Description>\n )}\n </div>\n <Dialog.Close\n 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\"\n aria-label=\"Fechar\"\n >\n <X className=\"h-5 w-5\" />\n </Dialog.Close>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-6 py-4\">{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-3 sm:flex-row sm:justify-end\">\n {footer}\n </div>\n )}\n </>\n )\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <Dialog.Content\n onCloseAutoFocus={() => {\n document.body.style.pointerEvents = \"\"\n }}\n className={cn(\n \"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none\",\n \"inset-x-0 bottom-0 rounded-t-2xl\",\n \"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\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n sizeClasses[size],\n className,\n )}\n >\n {onSubmit ? (\n <form\n onSubmit={onSubmit}\n className=\"flex min-h-0 flex-1 flex-col\"\n >\n {body}\n </form>\n ) : (\n body\n )}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthCardProps {\n title: string\n description?: string\n children: ReactNode\n footer?: ReactNode\n}\n\nexport function AuthCard({ title, description, children, footer }: AuthCardProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"mb-6 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n <div className=\"space-y-4\">{children}</div>\n {footer && <div className=\"mt-4\">{footer}</div>}\n </div>\n </div>\n )\n}\n","interface PaginationProps {\n page: number\n onPageChange: (page: number) => void\n hasNextPage: boolean\n hasPreviousPage: boolean\n className?: string\n}\n\nexport function Pagination({ page, onPageChange, hasNextPage, hasPreviousPage, className }: PaginationProps) {\n return (\n <div className={`flex items-center justify-end gap-4 ${className ?? \"\"}`}>\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )\n}\n","interface TableSkeletonProps {\n rows?: number\n columns?: number\n}\n\nexport function TableSkeleton({ rows = 5, columns = 4 }: TableSkeletonProps) {\n return (\n <>\n {Array.from({ length: rows }).map((_, i) => (\n <tr key={i} className=\"border-b transition-colors\">\n {Array.from({ length: columns }).map((_, j) => (\n <td key={j} className=\"p-4 align-middle\">\n <div className=\"h-5 w-full animate-pulse rounded bg-muted\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n )\n}\n","import * as React from \"react\"\n\ninterface SearchInputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n containerClassName?: string\n}\n\nexport const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ containerClassName, className, ...props }, ref) => {\n return (\n <div className={`relative flex-1 ${containerClassName ?? \"\"}`}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n <input\n ref={ref}\n type=\"text\"\n 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 ?? \"\"}`}\n {...props}\n />\n </div>\n )\n }\n)\nSearchInput.displayName = \"SearchInput\"\n","import type { ReactNode } from \"react\"\n\ninterface StatCardProps {\n label: string\n value: ReactNode\n detail?: string\n icon?: ReactNode\n isLoading?: boolean\n}\n\nexport function StatCard({ label, value, detail, icon, isLoading }: StatCardProps) {\n if (isLoading) {\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-4 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"mt-2 h-7 w-16 animate-pulse rounded bg-muted\" />\n <div className=\"mt-1 h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n )\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <span className=\"text-sm font-medium text-muted-foreground\">{label}</span>\n {icon && <span className=\"text-muted-foreground\">{icon}</span>}\n </div>\n <div className=\"text-2xl font-bold\">{value}</div>\n {detail && <p className=\"text-xs text-muted-foreground\">{detail}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface DataTableWrapperProps {\n children: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n page?: number\n onPageChange?: (page: number) => void\n hasNextPage?: boolean\n hasPreviousPage?: boolean\n}\n\nexport function DataTableWrapper({\n children,\n isEmpty,\n isLoading,\n emptyIcon,\n emptyTitle = \"Nenhum registro encontrado\",\n emptyDescription,\n page,\n onPageChange,\n hasNextPage = false,\n hasPreviousPage = false,\n}: DataTableWrapperProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-md border\">{children}</div>\n\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>\n )}\n </div>\n )}\n\n {page !== undefined && onPageChange && (\n <div className=\"flex items-center justify-end gap-4\">\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )}\n </div>\n )\n}\n","import { type MouseEvent, type ReactNode, type TouchEvent, useRef } from \"react\"\n\ninterface MobileCardListProps<T> {\n data: T[]\n renderCard: (item: T, index: number) => ReactNode\n keyExtractor: (item: T) => string\n isLoading?: boolean\n loadingCount?: number\n className?: string\n}\n\n// Movimento (px) acima do qual o gesto é tratado como scroll, não tap.\nconst SCROLL_THRESHOLD = 8\n\nexport function MobileCardList<T>({\n data,\n renderCard,\n keyExtractor,\n isLoading = false,\n loadingCount = 5,\n className,\n}: MobileCardListProps<T>) {\n // Guard contra tap acidental durante o scroll: se o dedo se moveu além do\n // threshold, o clique seguinte (ex.: botão de ações dentro do card) é\n // cancelado na fase de captura, antes de chegar no elemento interativo.\n const start = useRef<{ x: number; y: number } | null>(null)\n const scrolled = useRef(false)\n\n const onTouchStart = (e: TouchEvent<HTMLDivElement>) => {\n const t = e.touches[0]\n start.current = { x: t.clientX, y: t.clientY }\n scrolled.current = false\n }\n\n const onTouchMove = (e: TouchEvent<HTMLDivElement>) => {\n if (!start.current) return\n const t = e.touches[0]\n if (\n Math.abs(t.clientX - start.current.x) > SCROLL_THRESHOLD ||\n Math.abs(t.clientY - start.current.y) > SCROLL_THRESHOLD\n ) {\n scrolled.current = true\n }\n }\n\n const onClickCapture = (e: MouseEvent<HTMLDivElement>) => {\n if (scrolled.current) {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n\n if (isLoading) {\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {Array.from({ length: loadingCount }).map((_, i) => (\n <div key={i} className=\"rounded-xl border p-4\">\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <div className=\"h-5 w-32 animate-pulse rounded bg-muted\" />\n <div className=\"h-5 w-16 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"h-4 w-48 animate-pulse rounded bg-muted\" />\n <div className=\"flex justify-between\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div\n className={`space-y-3 ${className ?? \"\"}`}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n onClickCapture={onClickCapture}\n >\n {data.map((item, index) => (\n <div\n key={keyExtractor(item)}\n className=\"rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]\"\n >\n {renderCard(item, index)}\n </div>\n ))}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ResponsiveDataViewProps {\n table: ReactNode\n cards: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n pagination?: ReactNode\n}\n\nexport function ResponsiveDataView({\n table, cards, isEmpty, isLoading, emptyIcon, emptyTitle = \"Nenhum registro encontrado\", emptyDescription, pagination,\n}: ResponsiveDataViewProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"hidden overflow-x-auto rounded-md border md:block\">{table}</div>\n <div className=\"md:hidden\">{cards}</div>\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>}\n </div>\n )}\n {pagination}\n </div>\n )\n}\n","import { useTheme } from \"./theme-provider\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps<typeof Sonner>\n\nexport function Toaster(props: ToasterProps) {\n const { theme = \"system\" } = useTheme()\n\n return (\n <Sonner\n theme={theme as ToasterProps[\"theme\"]}\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n success:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40\",\n error:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40\",\n },\n }}\n {...props}\n />\n )\n}\n","import { ChevronLeft, ChevronRight, Menu } from \"lucide-react\"\nimport { type ReactNode, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { SidebarNav, type NavItem } from \"./sidebar-nav\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\nimport { UserMenu, type AppUser, type UserMenuItem } from \"./user-menu\"\n\nexport interface AppShellProps {\n brand: ReactNode\n brandCollapsed?: ReactNode\n navItems: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n user?: AppUser\n userMenuItems?: UserMenuItem[]\n onLogout?: () => void\n renderLink?: RenderLink\n headerActions?: ReactNode\n collapsible?: boolean\n defaultCollapsed?: boolean\n children: ReactNode\n}\n\nexport function AppShell({\n brand,\n brandCollapsed,\n navItems,\n activePath,\n isActive,\n isAdmin = false,\n user,\n userMenuItems,\n onLogout,\n renderLink = defaultRenderLink,\n headerActions,\n collapsible = true,\n defaultCollapsed = false,\n children,\n}: AppShellProps) {\n const [collapsed, setCollapsed] = useState(defaultCollapsed)\n const [mobileOpen, setMobileOpen] = useState(false)\n\n const nav = (isCollapsed: boolean, onNavigate?: () => void) => (\n <SidebarNav\n items={navItems}\n activePath={activePath}\n isActive={isActive}\n isAdmin={isAdmin}\n isCollapsed={isCollapsed}\n renderLink={renderLink}\n onNavigate={onNavigate}\n />\n )\n\n return (\n <div className=\"flex h-screen overflow-hidden bg-background\">\n {/* Desktop sidebar */}\n <aside\n className={cn(\n \"hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex\",\n collapsed ? \"w-16\" : \"w-60\",\n )}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(collapsed)}</div>\n {collapsible && (\n <div className=\"border-t p-2\">\n <button\n type=\"button\"\n onClick={() => setCollapsed((v) => !v)}\n 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\"\n aria-label={collapsed ? \"Expandir menu\" : \"Recolher menu\"}\n >\n {collapsed ? <ChevronRight className=\"h-4 w-4\" /> : <ChevronLeft className=\"h-4 w-4\" />}\n </button>\n </div>\n )}\n </aside>\n\n {/* Mobile drawer */}\n <div\n className={cn(\n \"fixed inset-0 z-50 transition-opacity duration-300 md:hidden\",\n mobileOpen ? \"pointer-events-auto opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n onClick={() => setMobileOpen(false)}\n >\n <div className=\"absolute inset-0 bg-black/50\" />\n <div\n className={cn(\n \"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">{brand}</div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(false, () => setMobileOpen(false))}</div>\n </div>\n </div>\n\n {/* Main column */}\n <div className=\"flex flex-1 flex-col overflow-hidden\">\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4\">\n <button\n type=\"button\"\n onClick={() => setMobileOpen(true)}\n 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\"\n aria-label=\"Abrir menu\"\n >\n <Menu className=\"h-4 w-4\" />\n </button>\n <div className=\"ml-auto flex items-center gap-2\">\n {headerActions}\n {(user || onLogout) && (\n <UserMenu user={user} items={userMenuItems} onLogout={onLogout} renderLink={renderLink} />\n )}\n </div>\n </header>\n <main className=\"flex-1 overflow-y-auto\">{children}</main>\n </div>\n </div>\n )\n}\n","import { Fragment, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface NavItem {\n label: string\n href: string\n icon?: ReactNode\n adminOnly?: boolean\n}\n\nexport interface SidebarNavProps {\n items: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n isCollapsed?: boolean\n renderLink?: RenderLink\n onNavigate?: () => void\n}\n\nfunction defaultIsActive(item: NavItem, activePath: string): boolean {\n if (item.href === \"/\") return activePath === \"/\"\n return activePath === item.href || activePath.startsWith(item.href + \"/\")\n}\n\nexport function SidebarNav({\n items,\n activePath,\n isActive = defaultIsActive,\n isAdmin = false,\n isCollapsed = false,\n renderLink = defaultRenderLink,\n onNavigate,\n}: SidebarNavProps) {\n const visible = items.filter((item) => !item.adminOnly || isAdmin)\n\n return (\n <nav className=\"flex flex-col gap-1\">\n {visible.map((item) => {\n const active = isActive(item, activePath)\n const link = renderLink({\n href: item.href,\n onClick: onNavigate,\n title: isCollapsed ? item.label : undefined,\n \"aria-current\": active ? \"page\" : undefined,\n className: cn(\n \"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\n active\n ? \"bg-accent text-accent-foreground font-semibold\"\n : \"text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n isCollapsed && \"justify-center px-2\",\n ),\n children: (\n <>\n {item.icon && <span className=\"shrink-0\">{item.icon}</span>}\n {!isCollapsed && <span className=\"truncate\">{item.label}</span>}\n </>\n ),\n })\n return <Fragment key={item.href}>{link}</Fragment>\n })}\n </nav>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport interface RenderLinkProps {\n href: string\n className?: string\n children: ReactNode\n onClick?: () => void\n title?: string\n \"aria-current\"?: \"page\"\n}\n\nexport type RenderLink = (props: RenderLinkProps) => ReactNode\n\nexport const defaultRenderLink: RenderLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n)\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { LogOut, User } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface AppUser {\n name?: string\n email?: string\n avatarUrl?: string\n}\n\nexport interface UserMenuItem {\n label: string\n icon?: ReactNode\n href?: string\n onClick?: () => void\n}\n\nexport interface UserMenuProps {\n user?: AppUser\n items?: UserMenuItem[]\n onLogout?: () => void\n logoutLabel?: string\n renderLink?: RenderLink\n align?: \"start\" | \"center\" | \"end\"\n}\n\nfunction initials(user?: AppUser): string {\n const source = user?.name?.trim() || user?.email?.trim()\n if (!source) return \"\"\n const parts = source.split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n return source.slice(0, 2).toUpperCase()\n}\n\nconst itemClass =\n \"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\"\n\nexport function UserMenu({\n user,\n items = [],\n onLogout,\n logoutLabel = \"Sair\",\n renderLink = defaultRenderLink,\n align = \"end\",\n}: UserMenuProps) {\n const label = initials(user)\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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-1 focus-visible:ring-ring\"\n aria-label=\"Menu do usuário\"\n data-testid=\"user-menu\"\n >\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt={user.name ?? user.email ?? \"Avatar\"} className=\"h-full w-full object-cover\" />\n ) : label ? (\n <span>{label}</span>\n ) : (\n <User className=\"h-4 w-4\" />\n )}\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {(user?.name || user?.email) && (\n <>\n <div className=\"px-2 py-1.5\">\n {user.name && <p className=\"truncate text-sm font-medium\">{user.name}</p>}\n {user.email && <p className=\"truncate text-xs text-muted-foreground\">{user.email}</p>}\n </div>\n <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />\n </>\n )}\n\n {items.map((item) =>\n item.href ? (\n <DropdownMenu.Item key={item.label} asChild>\n {renderLink({ href: item.href, className: itemClass, children: (\n <>\n {item.icon}\n {item.label}\n </>\n ) })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item key={item.label} className={itemClass} onClick={item.onClick}>\n {item.icon}\n {item.label}\n </DropdownMenu.Item>\n ),\n )}\n\n {onLogout && (\n <>\n {items.length > 0 && <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />}\n <DropdownMenu.Item className={cn(itemClass, \"text-destructive focus:bg-destructive/10\")} onClick={onLogout}>\n <LogOut className=\"h-4 w-4\" />\n {logoutLabel}\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { MoreVertical } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface RowAction {\n label: string\n icon?: ReactNode\n onClick?: () => void\n href?: string\n destructive?: boolean\n disabled?: boolean\n}\n\nexport interface RowActionsMenuProps {\n actions: RowAction[]\n disabled?: boolean\n align?: \"start\" | \"center\" | \"end\"\n label?: string\n renderLink?: RenderLink\n}\n\nconst itemClass =\n \"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\"\n\nexport function RowActionsMenu({\n actions,\n disabled = false,\n align = \"end\",\n label = \"Ações\",\n renderLink = defaultRenderLink,\n}: RowActionsMenuProps) {\n if (actions.length === 0) return null\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={label}\n className=\"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-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {actions.map((action) => {\n const cls = cn(itemClass, action.destructive && \"text-destructive focus:bg-destructive/10\")\n return action.href ? (\n <DropdownMenu.Item key={action.label} asChild disabled={action.disabled}>\n {renderLink({\n href: action.href,\n className: cls,\n children: (\n <>\n {action.icon}\n {action.label}\n </>\n ),\n })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item\n key={action.label}\n className={cls}\n disabled={action.disabled}\n onClick={action.onClick}\n >\n {action.icon}\n {action.label}\n </DropdownMenu.Item>\n )\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","export function extractApiError(err: any, fallbackMessage = \"Ocorreu um erro inesperado.\"): string {\n const detail = err?.body?.detail || err?.message\n if (Array.isArray(detail) && detail.length > 0) {\n return detail[0].msg\n }\n return detail || fallbackMessage\n}\n","import { useCallback, useState } from \"react\"\n\nexport function useDisclosure(initial = false) {\n const [open, setOpen] = useState(initial)\n const onOpen = useCallback(() => setOpen(true), [])\n const onClose = useCallback(() => setOpen(false), [])\n const onToggle = useCallback(() => setOpen((v) => !v), [])\n return { open, onOpen, onClose, onToggle, setOpen }\n}\n","import { toast } from \"sonner\"\nimport { useCallback } from \"react\"\n\ntype ToastStatus = \"success\" | \"error\" | \"info\" | \"warning\"\n\nexport function useCustomToast() {\n const showToast = useCallback(\n (title: string, description?: string, status: ToastStatus = \"success\") => {\n switch (status) {\n case \"success\":\n toast.success(title, { description })\n break\n case \"error\":\n toast.error(title, { description })\n break\n case \"info\":\n toast.info(title, { description })\n break\n case \"warning\":\n toast.warning(title, { description })\n break\n }\n },\n [],\n )\n\n return showToast\n}\n\nexport { toast }\n"],"mappings":"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","names":["theme","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_lucide_react","import_jsx_runtime","sizeClasses","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","_","React","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","Sonner","import_lucide_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","DropdownMenu","import_lucide_react","import_jsx_runtime","import_jsx_runtime","DropdownMenu","import_lucide_react","import_jsx_runtime","itemClass","import_react","import_sonner","import_react"]}
|
package/dist/index.js
CHANGED
|
@@ -585,7 +585,9 @@ function DataTableWrapper({
|
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
// src/components/mobile-card-list.tsx
|
|
588
|
+
import { useRef } from "react";
|
|
588
589
|
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
590
|
+
var SCROLL_THRESHOLD = 8;
|
|
589
591
|
function MobileCardList({
|
|
590
592
|
data,
|
|
591
593
|
renderCard,
|
|
@@ -594,6 +596,26 @@ function MobileCardList({
|
|
|
594
596
|
loadingCount = 5,
|
|
595
597
|
className
|
|
596
598
|
}) {
|
|
599
|
+
const start = useRef(null);
|
|
600
|
+
const scrolled = useRef(false);
|
|
601
|
+
const onTouchStart = (e) => {
|
|
602
|
+
const t = e.touches[0];
|
|
603
|
+
start.current = { x: t.clientX, y: t.clientY };
|
|
604
|
+
scrolled.current = false;
|
|
605
|
+
};
|
|
606
|
+
const onTouchMove = (e) => {
|
|
607
|
+
if (!start.current) return;
|
|
608
|
+
const t = e.touches[0];
|
|
609
|
+
if (Math.abs(t.clientX - start.current.x) > SCROLL_THRESHOLD || Math.abs(t.clientY - start.current.y) > SCROLL_THRESHOLD) {
|
|
610
|
+
scrolled.current = true;
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
const onClickCapture = (e) => {
|
|
614
|
+
if (scrolled.current) {
|
|
615
|
+
e.preventDefault();
|
|
616
|
+
e.stopPropagation();
|
|
617
|
+
}
|
|
618
|
+
};
|
|
597
619
|
if (isLoading) {
|
|
598
620
|
return /* @__PURE__ */ jsx17("div", { className: `space-y-3 ${className ?? ""}`, children: Array.from({ length: loadingCount }).map((_, i) => /* @__PURE__ */ jsx17("div", { className: "rounded-xl border p-4", children: /* @__PURE__ */ jsxs15("div", { className: "space-y-3", children: [
|
|
599
621
|
/* @__PURE__ */ jsxs15("div", { className: "flex justify-between", children: [
|
|
@@ -607,14 +629,23 @@ function MobileCardList({
|
|
|
607
629
|
] })
|
|
608
630
|
] }) }, i)) });
|
|
609
631
|
}
|
|
610
|
-
return /* @__PURE__ */ jsx17(
|
|
632
|
+
return /* @__PURE__ */ jsx17(
|
|
611
633
|
"div",
|
|
612
634
|
{
|
|
613
|
-
className:
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
635
|
+
className: `space-y-3 ${className ?? ""}`,
|
|
636
|
+
onTouchStart,
|
|
637
|
+
onTouchMove,
|
|
638
|
+
onClickCapture,
|
|
639
|
+
children: data.map((item, index) => /* @__PURE__ */ jsx17(
|
|
640
|
+
"div",
|
|
641
|
+
{
|
|
642
|
+
className: "rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]",
|
|
643
|
+
children: renderCard(item, index)
|
|
644
|
+
},
|
|
645
|
+
keyExtractor(item)
|
|
646
|
+
))
|
|
647
|
+
}
|
|
648
|
+
);
|
|
618
649
|
}
|
|
619
650
|
|
|
620
651
|
// src/components/responsive-data-view.tsx
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/theme-provider.tsx","../src/components/mode-toggle.tsx","../src/components/empty-state.tsx","../src/components/confirm-dialog.tsx","../src/components/page-header.tsx","../src/components/status-dot.tsx","../src/components/status-badge.tsx","../src/components/progress-bar.tsx","../src/components/form-field.tsx","../src/components/form-dialog.tsx","../src/lib/utils.ts","../src/components/auth-card.tsx","../src/components/pagination.tsx","../src/components/table-skeleton.tsx","../src/components/search-input.tsx","../src/components/stat-card.tsx","../src/components/data-table-wrapper.tsx","../src/components/mobile-card-list.tsx","../src/components/responsive-data-view.tsx","../src/components/toaster.tsx","../src/components/app-shell.tsx","../src/components/sidebar-nav.tsx","../src/components/types.tsx","../src/components/user-menu.tsx","../src/components/row-actions-menu.tsx","../src/lib/api-error.ts","../src/hooks/use-disclosure.ts","../src/hooks/use-toast.ts"],"sourcesContent":["import { createContext, useContext, useEffect, useState } from \"react\"\n\ntype Theme = \"dark\" | \"light\" | \"system\"\n\ntype ThemeProviderProps = {\n children: React.ReactNode\n defaultTheme?: Theme\n storageKey?: string\n}\n\ntype ThemeProviderState = {\n theme: Theme\n setTheme: (theme: Theme) => void\n}\n\nconst initialState: ThemeProviderState = {\n theme: \"system\",\n setTheme: () => null,\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState)\n\nexport function ThemeProvider({\n children,\n defaultTheme = \"system\",\n storageKey = \"ui-theme\",\n ...props\n}: ThemeProviderProps) {\n const [theme, setTheme] = useState<Theme>(\n () => (localStorage.getItem(storageKey) as Theme) || defaultTheme\n )\n\n useEffect(() => {\n const root = window.document.documentElement\n root.classList.remove(\"light\", \"dark\")\n if (theme === \"system\") {\n const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\"\n root.classList.add(systemTheme)\n return\n }\n root.classList.add(theme)\n }, [theme])\n\n const value = {\n theme,\n setTheme: (theme: Theme) => {\n localStorage.setItem(storageKey, theme)\n setTheme(theme)\n },\n }\n\n return (\n <ThemeProviderContext.Provider {...props} value={value}>\n {children}\n </ThemeProviderContext.Provider>\n )\n}\n\nexport function useTheme() {\n const context = useContext(ThemeProviderContext)\n if (context === undefined) {\n throw new Error(\"useTheme must be used within a ThemeProvider\")\n }\n return context\n}\n\nexport type { Theme, ThemeProviderProps, ThemeProviderState }\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { Moon, Sun, Monitor } from \"lucide-react\"\nimport { useTheme } from \"./theme-provider\"\n\nexport function ModeToggle() {\n const { setTheme } = useTheme()\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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\"\n aria-label=\"Alternar tema\"\n >\n <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute inset-0 m-auto h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align=\"end\"\n 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\"\n >\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"light\")}\n >\n <Sun className=\"h-4 w-4\" /> Claro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"dark\")}\n >\n <Moon className=\"h-4 w-4\" /> Escuro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"system\")}\n >\n <Monitor className=\"h-4 w-4\" /> Sistema\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface EmptyStateProps {\n icon?: ReactNode\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={`flex flex-col items-center justify-center py-16 text-center ${className ?? \"\"}`}>\n {icon && <div className=\"mb-4 text-muted-foreground\">{icon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{title}</h3>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n )\n}\n","import * as AlertDialog from \"@radix-ui/react-alert-dialog\"\nimport type { ReactNode } from \"react\"\n\ninterface ConfirmDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n title: string\n description: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n loading?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nexport function ConfirmDialog({\n open,\n onOpenChange,\n onConfirm,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n loading = false,\n variant = \"default\",\n}: ConfirmDialogProps) {\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Portal>\n <AlertDialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <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\">\n <div className=\"flex flex-col space-y-2 text-center sm:text-left\">\n <AlertDialog.Title className=\"text-lg font-semibold\">{title}</AlertDialog.Title>\n <AlertDialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </AlertDialog.Description>\n </div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <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\">\n {cancelLabel}\n </AlertDialog.Cancel>\n <AlertDialog.Action\n onClick={onConfirm}\n disabled={loading}\n 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 ${\n variant === \"destructive\"\n ? \"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n : \"bg-primary text-primary-foreground hover:bg-primary/90\"\n }`}\n >\n {loading ? \"Aguarde...\" : confirmLabel}\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface PageHeaderProps {\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function PageHeader({ title, description, action, className }: PageHeaderProps) {\n return (\n <div\n className={`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? \"\"}`}\n >\n <div className=\"min-w-0\">\n <h1 className=\"truncate text-2xl font-semibold tracking-tight\">\n {title}\n </h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n","interface StatusDotProps {\n active: boolean\n label?: string\n className?: string\n}\n\nexport function StatusDot({ active, label, className }: StatusDotProps) {\n return (\n <span className={`inline-flex items-center gap-2 ${className ?? \"\"}`}>\n <span\n className={`h-2 w-2 rounded-full ${active ? \"bg-green-500\" : \"bg-red-500\"}`}\n />\n {label && <span>{label}</span>}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport type StatusBadgeVariant =\n | \"neutral\"\n | \"info\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n\ninterface StatusBadgeProps {\n variant?: StatusBadgeVariant\n dot?: boolean\n className?: string\n children: ReactNode\n}\n\nconst variantClasses: Record<\n StatusBadgeVariant,\n { badge: string; dot: string }\n> = {\n neutral: {\n badge: \"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300\",\n dot: \"bg-gray-400\",\n },\n info: {\n badge: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400\",\n dot: \"bg-blue-500\",\n },\n success: {\n badge: \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-400\",\n dot: \"bg-green-500\",\n },\n danger: {\n badge: \"bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400\",\n dot: \"bg-red-500\",\n },\n warning: {\n badge: \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400\",\n dot: \"bg-amber-500\",\n },\n}\n\nexport function StatusBadge({\n variant = \"neutral\",\n dot = true,\n className,\n children,\n}: StatusBadgeProps) {\n const classes = variantClasses[variant]\n\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium ${classes.badge} ${className ?? \"\"}`}\n >\n {dot && (\n <span\n className={`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${classes.dot}`}\n />\n )}\n {children}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ProgressBarProps {\n value: number\n size?: \"sm\" | \"md\"\n label?: ReactNode\n valueLabel?: ReactNode\n className?: string\n indicatorClassName?: string\n}\n\nconst sizeClasses = {\n sm: \"h-1.5\",\n md: \"h-2\",\n} as const\n\nexport function ProgressBar({\n value,\n size = \"md\",\n label,\n valueLabel,\n className,\n indicatorClassName,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value))\n\n return (\n <div className={`space-y-1.5 ${className ?? \"\"}`}>\n {(label || valueLabel) && (\n <div className=\"flex items-baseline justify-between gap-2\">\n {label && (\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n )}\n {valueLabel && (\n <span className=\"text-sm font-semibold\">{valueLabel}</span>\n )}\n </div>\n )}\n <div\n className={`w-full overflow-hidden rounded-full bg-muted ${sizeClasses[size]}`}\n >\n <div\n className={`h-full rounded-full transition-all duration-300 ${indicatorClassName ?? \"bg-primary\"}`}\n style={{ width: `${clamped}%` }}\n />\n </div>\n </div>\n )\n}\n","import { type ReactElement, type ReactNode, cloneElement, isValidElement, useId } from \"react\"\n\ninterface FormFieldProps {\n label: string\n htmlFor?: string\n error?: string\n required?: boolean\n children: ReactNode\n className?: string\n}\n\nexport function FormField({ label, htmlFor, error, required, children, className }: FormFieldProps) {\n const errorId = useId()\n\n // Wire accessibility onto the control: mark it invalid and point it at the\n // error message so screen readers announce both.\n const field =\n error && isValidElement(children)\n ? cloneElement(children as ReactElement<Record<string, unknown>>, {\n \"aria-invalid\": true,\n \"aria-describedby\": [\n (children.props as Record<string, unknown>)[\"aria-describedby\"],\n errorId,\n ]\n .filter(Boolean)\n .join(\" \"),\n })\n : children\n\n return (\n <div className={`space-y-2 ${className ?? \"\"}`}>\n <label\n htmlFor={htmlFor}\n className=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n {required && <span className=\"ml-1 text-destructive\">*</span>}\n </label>\n {field}\n {error && (\n <p id={errorId} className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n </div>\n )\n}\n","import * as Dialog from \"@radix-ui/react-dialog\"\nimport { X } from \"lucide-react\"\nimport * as React from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\ninterface FormDialogLayoutProps {\n title: string\n children: ReactNode\n onSubmit: (e: React.FormEvent) => void\n submitLabel?: string\n cancelLabel?: string\n onCancel: () => void\n isSubmitting?: boolean\n isDisabled?: boolean\n}\n\nexport function FormDialogLayout({\n title,\n children,\n onSubmit,\n submitLabel = \"Salvar\",\n cancelLabel = \"Cancelar\",\n onCancel,\n isSubmitting = false,\n isDisabled = false,\n}: FormDialogLayoutProps) {\n return (\n <form onSubmit={onSubmit}>\n <div className=\"flex flex-col space-y-1.5 text-center sm:text-left\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">{title}</h2>\n </div>\n <div className=\"space-y-4 py-4\">{children}</div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <button\n type=\"button\"\n onClick={onCancel}\n 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\"\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || isDisabled}\n 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\"\n >\n {isSubmitting ? \"Salvando...\" : submitLabel}\n </button>\n </div>\n </form>\n )\n}\n\nconst sizeClasses = {\n sm: \"sm:max-w-sm\",\n md: \"sm:max-w-md\",\n lg: \"sm:max-w-lg\",\n xl: \"sm:max-w-xl\",\n \"2xl\": \"sm:max-w-2xl\",\n} as const\n\nexport type FormDialogSize = keyof typeof sizeClasses\n\ninterface FormDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n description?: ReactNode\n children: ReactNode\n footer?: ReactNode\n /** When provided, the dialog renders a <form> wrapping body + footer. */\n onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void\n size?: FormDialogSize\n className?: string\n}\n\n/**\n * Standardized, responsive modal:\n * - mobile: bottom sheet (full width, up to 92vh tall)\n * - desktop: centered dialog (up to 90vh tall)\n * Header and footer stay fixed; only the body scrolls.\n *\n * Also fixes the known Radix bug where `body { pointer-events: none }`\n * can persist after closing a dialog that contained a Select/Popover,\n * which would otherwise make the rest of the page unclickable.\n */\nexport function FormDialog({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n onSubmit,\n size = \"lg\",\n className,\n}: FormDialogProps) {\n React.useEffect(() => {\n if (open) return\n const id = window.setTimeout(() => {\n if (document.body.style.pointerEvents === \"none\") {\n document.body.style.pointerEvents = \"\"\n }\n }, 0)\n return () => window.clearTimeout(id)\n }, [open])\n\n const body = (\n <>\n <div className=\"flex shrink-0 items-start justify-between gap-4 border-b px-6 py-3\">\n <div className=\"min-w-0 space-y-1\">\n <Dialog.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </Dialog.Title>\n {description && (\n <Dialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </Dialog.Description>\n )}\n </div>\n <Dialog.Close\n 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\"\n aria-label=\"Fechar\"\n >\n <X className=\"h-5 w-5\" />\n </Dialog.Close>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-6 py-4\">{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-3 sm:flex-row sm:justify-end\">\n {footer}\n </div>\n )}\n </>\n )\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <Dialog.Content\n onCloseAutoFocus={() => {\n document.body.style.pointerEvents = \"\"\n }}\n className={cn(\n \"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none\",\n \"inset-x-0 bottom-0 rounded-t-2xl\",\n \"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\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n sizeClasses[size],\n className,\n )}\n >\n {onSubmit ? (\n <form\n onSubmit={onSubmit}\n className=\"flex min-h-0 flex-1 flex-col\"\n >\n {body}\n </form>\n ) : (\n body\n )}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthCardProps {\n title: string\n description?: string\n children: ReactNode\n footer?: ReactNode\n}\n\nexport function AuthCard({ title, description, children, footer }: AuthCardProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"mb-6 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n <div className=\"space-y-4\">{children}</div>\n {footer && <div className=\"mt-4\">{footer}</div>}\n </div>\n </div>\n )\n}\n","interface PaginationProps {\n page: number\n onPageChange: (page: number) => void\n hasNextPage: boolean\n hasPreviousPage: boolean\n className?: string\n}\n\nexport function Pagination({ page, onPageChange, hasNextPage, hasPreviousPage, className }: PaginationProps) {\n return (\n <div className={`flex items-center justify-end gap-4 ${className ?? \"\"}`}>\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )\n}\n","interface TableSkeletonProps {\n rows?: number\n columns?: number\n}\n\nexport function TableSkeleton({ rows = 5, columns = 4 }: TableSkeletonProps) {\n return (\n <>\n {Array.from({ length: rows }).map((_, i) => (\n <tr key={i} className=\"border-b transition-colors\">\n {Array.from({ length: columns }).map((_, j) => (\n <td key={j} className=\"p-4 align-middle\">\n <div className=\"h-5 w-full animate-pulse rounded bg-muted\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n )\n}\n","import * as React from \"react\"\n\ninterface SearchInputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n containerClassName?: string\n}\n\nexport const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ containerClassName, className, ...props }, ref) => {\n return (\n <div className={`relative flex-1 ${containerClassName ?? \"\"}`}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n <input\n ref={ref}\n type=\"text\"\n 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 ?? \"\"}`}\n {...props}\n />\n </div>\n )\n }\n)\nSearchInput.displayName = \"SearchInput\"\n","import type { ReactNode } from \"react\"\n\ninterface StatCardProps {\n label: string\n value: ReactNode\n detail?: string\n icon?: ReactNode\n isLoading?: boolean\n}\n\nexport function StatCard({ label, value, detail, icon, isLoading }: StatCardProps) {\n if (isLoading) {\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-4 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"mt-2 h-7 w-16 animate-pulse rounded bg-muted\" />\n <div className=\"mt-1 h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n )\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <span className=\"text-sm font-medium text-muted-foreground\">{label}</span>\n {icon && <span className=\"text-muted-foreground\">{icon}</span>}\n </div>\n <div className=\"text-2xl font-bold\">{value}</div>\n {detail && <p className=\"text-xs text-muted-foreground\">{detail}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface DataTableWrapperProps {\n children: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n page?: number\n onPageChange?: (page: number) => void\n hasNextPage?: boolean\n hasPreviousPage?: boolean\n}\n\nexport function DataTableWrapper({\n children,\n isEmpty,\n isLoading,\n emptyIcon,\n emptyTitle = \"Nenhum registro encontrado\",\n emptyDescription,\n page,\n onPageChange,\n hasNextPage = false,\n hasPreviousPage = false,\n}: DataTableWrapperProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-md border\">{children}</div>\n\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>\n )}\n </div>\n )}\n\n {page !== undefined && onPageChange && (\n <div className=\"flex items-center justify-end gap-4\">\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface MobileCardListProps<T> {\n data: T[]\n renderCard: (item: T, index: number) => ReactNode\n keyExtractor: (item: T) => string\n isLoading?: boolean\n loadingCount?: number\n className?: string\n}\n\nexport function MobileCardList<T>({\n data,\n renderCard,\n keyExtractor,\n isLoading = false,\n loadingCount = 5,\n className,\n}: MobileCardListProps<T>) {\n if (isLoading) {\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {Array.from({ length: loadingCount }).map((_, i) => (\n <div key={i} className=\"rounded-xl border p-4\">\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <div className=\"h-5 w-32 animate-pulse rounded bg-muted\" />\n <div className=\"h-5 w-16 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"h-4 w-48 animate-pulse rounded bg-muted\" />\n <div className=\"flex justify-between\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {data.map((item, index) => (\n <div\n key={keyExtractor(item)}\n className=\"rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]\"\n >\n {renderCard(item, index)}\n </div>\n ))}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ResponsiveDataViewProps {\n table: ReactNode\n cards: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n pagination?: ReactNode\n}\n\nexport function ResponsiveDataView({\n table, cards, isEmpty, isLoading, emptyIcon, emptyTitle = \"Nenhum registro encontrado\", emptyDescription, pagination,\n}: ResponsiveDataViewProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"hidden overflow-x-auto rounded-md border md:block\">{table}</div>\n <div className=\"md:hidden\">{cards}</div>\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>}\n </div>\n )}\n {pagination}\n </div>\n )\n}\n","import { useTheme } from \"./theme-provider\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps<typeof Sonner>\n\nexport function Toaster(props: ToasterProps) {\n const { theme = \"system\" } = useTheme()\n\n return (\n <Sonner\n theme={theme as ToasterProps[\"theme\"]}\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n success:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40\",\n error:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40\",\n },\n }}\n {...props}\n />\n )\n}\n","import { ChevronLeft, ChevronRight, Menu } from \"lucide-react\"\nimport { type ReactNode, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { SidebarNav, type NavItem } from \"./sidebar-nav\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\nimport { UserMenu, type AppUser, type UserMenuItem } from \"./user-menu\"\n\nexport interface AppShellProps {\n brand: ReactNode\n brandCollapsed?: ReactNode\n navItems: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n user?: AppUser\n userMenuItems?: UserMenuItem[]\n onLogout?: () => void\n renderLink?: RenderLink\n headerActions?: ReactNode\n collapsible?: boolean\n defaultCollapsed?: boolean\n children: ReactNode\n}\n\nexport function AppShell({\n brand,\n brandCollapsed,\n navItems,\n activePath,\n isActive,\n isAdmin = false,\n user,\n userMenuItems,\n onLogout,\n renderLink = defaultRenderLink,\n headerActions,\n collapsible = true,\n defaultCollapsed = false,\n children,\n}: AppShellProps) {\n const [collapsed, setCollapsed] = useState(defaultCollapsed)\n const [mobileOpen, setMobileOpen] = useState(false)\n\n const nav = (isCollapsed: boolean, onNavigate?: () => void) => (\n <SidebarNav\n items={navItems}\n activePath={activePath}\n isActive={isActive}\n isAdmin={isAdmin}\n isCollapsed={isCollapsed}\n renderLink={renderLink}\n onNavigate={onNavigate}\n />\n )\n\n return (\n <div className=\"flex h-screen overflow-hidden bg-background\">\n {/* Desktop sidebar */}\n <aside\n className={cn(\n \"hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex\",\n collapsed ? \"w-16\" : \"w-60\",\n )}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(collapsed)}</div>\n {collapsible && (\n <div className=\"border-t p-2\">\n <button\n type=\"button\"\n onClick={() => setCollapsed((v) => !v)}\n 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\"\n aria-label={collapsed ? \"Expandir menu\" : \"Recolher menu\"}\n >\n {collapsed ? <ChevronRight className=\"h-4 w-4\" /> : <ChevronLeft className=\"h-4 w-4\" />}\n </button>\n </div>\n )}\n </aside>\n\n {/* Mobile drawer */}\n <div\n className={cn(\n \"fixed inset-0 z-50 transition-opacity duration-300 md:hidden\",\n mobileOpen ? \"pointer-events-auto opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n onClick={() => setMobileOpen(false)}\n >\n <div className=\"absolute inset-0 bg-black/50\" />\n <div\n className={cn(\n \"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">{brand}</div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(false, () => setMobileOpen(false))}</div>\n </div>\n </div>\n\n {/* Main column */}\n <div className=\"flex flex-1 flex-col overflow-hidden\">\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4\">\n <button\n type=\"button\"\n onClick={() => setMobileOpen(true)}\n 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\"\n aria-label=\"Abrir menu\"\n >\n <Menu className=\"h-4 w-4\" />\n </button>\n <div className=\"ml-auto flex items-center gap-2\">\n {headerActions}\n {(user || onLogout) && (\n <UserMenu user={user} items={userMenuItems} onLogout={onLogout} renderLink={renderLink} />\n )}\n </div>\n </header>\n <main className=\"flex-1 overflow-y-auto\">{children}</main>\n </div>\n </div>\n )\n}\n","import { Fragment, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface NavItem {\n label: string\n href: string\n icon?: ReactNode\n adminOnly?: boolean\n}\n\nexport interface SidebarNavProps {\n items: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n isCollapsed?: boolean\n renderLink?: RenderLink\n onNavigate?: () => void\n}\n\nfunction defaultIsActive(item: NavItem, activePath: string): boolean {\n if (item.href === \"/\") return activePath === \"/\"\n return activePath === item.href || activePath.startsWith(item.href + \"/\")\n}\n\nexport function SidebarNav({\n items,\n activePath,\n isActive = defaultIsActive,\n isAdmin = false,\n isCollapsed = false,\n renderLink = defaultRenderLink,\n onNavigate,\n}: SidebarNavProps) {\n const visible = items.filter((item) => !item.adminOnly || isAdmin)\n\n return (\n <nav className=\"flex flex-col gap-1\">\n {visible.map((item) => {\n const active = isActive(item, activePath)\n const link = renderLink({\n href: item.href,\n onClick: onNavigate,\n title: isCollapsed ? item.label : undefined,\n \"aria-current\": active ? \"page\" : undefined,\n className: cn(\n \"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\n active\n ? \"bg-accent text-accent-foreground font-semibold\"\n : \"text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n isCollapsed && \"justify-center px-2\",\n ),\n children: (\n <>\n {item.icon && <span className=\"shrink-0\">{item.icon}</span>}\n {!isCollapsed && <span className=\"truncate\">{item.label}</span>}\n </>\n ),\n })\n return <Fragment key={item.href}>{link}</Fragment>\n })}\n </nav>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport interface RenderLinkProps {\n href: string\n className?: string\n children: ReactNode\n onClick?: () => void\n title?: string\n \"aria-current\"?: \"page\"\n}\n\nexport type RenderLink = (props: RenderLinkProps) => ReactNode\n\nexport const defaultRenderLink: RenderLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n)\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { LogOut, User } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface AppUser {\n name?: string\n email?: string\n avatarUrl?: string\n}\n\nexport interface UserMenuItem {\n label: string\n icon?: ReactNode\n href?: string\n onClick?: () => void\n}\n\nexport interface UserMenuProps {\n user?: AppUser\n items?: UserMenuItem[]\n onLogout?: () => void\n logoutLabel?: string\n renderLink?: RenderLink\n align?: \"start\" | \"center\" | \"end\"\n}\n\nfunction initials(user?: AppUser): string {\n const source = user?.name?.trim() || user?.email?.trim()\n if (!source) return \"\"\n const parts = source.split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n return source.slice(0, 2).toUpperCase()\n}\n\nconst itemClass =\n \"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\"\n\nexport function UserMenu({\n user,\n items = [],\n onLogout,\n logoutLabel = \"Sair\",\n renderLink = defaultRenderLink,\n align = \"end\",\n}: UserMenuProps) {\n const label = initials(user)\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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-1 focus-visible:ring-ring\"\n aria-label=\"Menu do usuário\"\n data-testid=\"user-menu\"\n >\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt={user.name ?? user.email ?? \"Avatar\"} className=\"h-full w-full object-cover\" />\n ) : label ? (\n <span>{label}</span>\n ) : (\n <User className=\"h-4 w-4\" />\n )}\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {(user?.name || user?.email) && (\n <>\n <div className=\"px-2 py-1.5\">\n {user.name && <p className=\"truncate text-sm font-medium\">{user.name}</p>}\n {user.email && <p className=\"truncate text-xs text-muted-foreground\">{user.email}</p>}\n </div>\n <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />\n </>\n )}\n\n {items.map((item) =>\n item.href ? (\n <DropdownMenu.Item key={item.label} asChild>\n {renderLink({ href: item.href, className: itemClass, children: (\n <>\n {item.icon}\n {item.label}\n </>\n ) })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item key={item.label} className={itemClass} onClick={item.onClick}>\n {item.icon}\n {item.label}\n </DropdownMenu.Item>\n ),\n )}\n\n {onLogout && (\n <>\n {items.length > 0 && <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />}\n <DropdownMenu.Item className={cn(itemClass, \"text-destructive focus:bg-destructive/10\")} onClick={onLogout}>\n <LogOut className=\"h-4 w-4\" />\n {logoutLabel}\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { MoreVertical } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface RowAction {\n label: string\n icon?: ReactNode\n onClick?: () => void\n href?: string\n destructive?: boolean\n disabled?: boolean\n}\n\nexport interface RowActionsMenuProps {\n actions: RowAction[]\n disabled?: boolean\n align?: \"start\" | \"center\" | \"end\"\n label?: string\n renderLink?: RenderLink\n}\n\nconst itemClass =\n \"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\"\n\nexport function RowActionsMenu({\n actions,\n disabled = false,\n align = \"end\",\n label = \"Ações\",\n renderLink = defaultRenderLink,\n}: RowActionsMenuProps) {\n if (actions.length === 0) return null\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={label}\n className=\"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-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {actions.map((action) => {\n const cls = cn(itemClass, action.destructive && \"text-destructive focus:bg-destructive/10\")\n return action.href ? (\n <DropdownMenu.Item key={action.label} asChild disabled={action.disabled}>\n {renderLink({\n href: action.href,\n className: cls,\n children: (\n <>\n {action.icon}\n {action.label}\n </>\n ),\n })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item\n key={action.label}\n className={cls}\n disabled={action.disabled}\n onClick={action.onClick}\n >\n {action.icon}\n {action.label}\n </DropdownMenu.Item>\n )\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","export function extractApiError(err: any, fallbackMessage = \"Ocorreu um erro inesperado.\"): string {\n const detail = err?.body?.detail || err?.message\n if (Array.isArray(detail) && detail.length > 0) {\n return detail[0].msg\n }\n return detail || fallbackMessage\n}\n","import { useCallback, useState } from \"react\"\n\nexport function useDisclosure(initial = false) {\n const [open, setOpen] = useState(initial)\n const onOpen = useCallback(() => setOpen(true), [])\n const onClose = useCallback(() => setOpen(false), [])\n const onToggle = useCallback(() => setOpen((v) => !v), [])\n return { open, onOpen, onClose, onToggle, setOpen }\n}\n","import { toast } from \"sonner\"\nimport { useCallback } from \"react\"\n\ntype ToastStatus = \"success\" | \"error\" | \"info\" | \"warning\"\n\nexport function useCustomToast() {\n const showToast = useCallback(\n (title: string, description?: string, status: ToastStatus = \"success\") => {\n switch (status) {\n case \"success\":\n toast.success(title, { description })\n break\n case \"error\":\n toast.error(title, { description })\n break\n case \"info\":\n toast.info(title, { description })\n break\n case \"warning\":\n toast.warning(title, { description })\n break\n }\n },\n [],\n )\n\n return showToast\n}\n\nexport { toast }\n"],"mappings":"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","names":["theme","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","sizeClasses","jsx","jsxs","jsx","jsxs","Fragment","jsx","_","React","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useState","Fragment","jsx","Fragment","jsx","jsxs","DropdownMenu","Fragment","jsx","jsxs","jsx","jsxs","useState","DropdownMenu","Fragment","jsx","jsxs","itemClass","useState","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/theme-provider.tsx","../src/components/mode-toggle.tsx","../src/components/empty-state.tsx","../src/components/confirm-dialog.tsx","../src/components/page-header.tsx","../src/components/status-dot.tsx","../src/components/status-badge.tsx","../src/components/progress-bar.tsx","../src/components/form-field.tsx","../src/components/form-dialog.tsx","../src/lib/utils.ts","../src/components/auth-card.tsx","../src/components/pagination.tsx","../src/components/table-skeleton.tsx","../src/components/search-input.tsx","../src/components/stat-card.tsx","../src/components/data-table-wrapper.tsx","../src/components/mobile-card-list.tsx","../src/components/responsive-data-view.tsx","../src/components/toaster.tsx","../src/components/app-shell.tsx","../src/components/sidebar-nav.tsx","../src/components/types.tsx","../src/components/user-menu.tsx","../src/components/row-actions-menu.tsx","../src/lib/api-error.ts","../src/hooks/use-disclosure.ts","../src/hooks/use-toast.ts"],"sourcesContent":["import { createContext, useContext, useEffect, useState } from \"react\"\n\ntype Theme = \"dark\" | \"light\" | \"system\"\n\ntype ThemeProviderProps = {\n children: React.ReactNode\n defaultTheme?: Theme\n storageKey?: string\n}\n\ntype ThemeProviderState = {\n theme: Theme\n setTheme: (theme: Theme) => void\n}\n\nconst initialState: ThemeProviderState = {\n theme: \"system\",\n setTheme: () => null,\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState)\n\nexport function ThemeProvider({\n children,\n defaultTheme = \"system\",\n storageKey = \"ui-theme\",\n ...props\n}: ThemeProviderProps) {\n const [theme, setTheme] = useState<Theme>(\n () => (localStorage.getItem(storageKey) as Theme) || defaultTheme\n )\n\n useEffect(() => {\n const root = window.document.documentElement\n root.classList.remove(\"light\", \"dark\")\n if (theme === \"system\") {\n const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\"\n root.classList.add(systemTheme)\n return\n }\n root.classList.add(theme)\n }, [theme])\n\n const value = {\n theme,\n setTheme: (theme: Theme) => {\n localStorage.setItem(storageKey, theme)\n setTheme(theme)\n },\n }\n\n return (\n <ThemeProviderContext.Provider {...props} value={value}>\n {children}\n </ThemeProviderContext.Provider>\n )\n}\n\nexport function useTheme() {\n const context = useContext(ThemeProviderContext)\n if (context === undefined) {\n throw new Error(\"useTheme must be used within a ThemeProvider\")\n }\n return context\n}\n\nexport type { Theme, ThemeProviderProps, ThemeProviderState }\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { Moon, Sun, Monitor } from \"lucide-react\"\nimport { useTheme } from \"./theme-provider\"\n\nexport function ModeToggle() {\n const { setTheme } = useTheme()\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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\"\n aria-label=\"Alternar tema\"\n >\n <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute inset-0 m-auto h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align=\"end\"\n 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\"\n >\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"light\")}\n >\n <Sun className=\"h-4 w-4\" /> Claro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"dark\")}\n >\n <Moon className=\"h-4 w-4\" /> Escuro\n </DropdownMenu.Item>\n <DropdownMenu.Item\n 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\"\n onClick={() => setTheme(\"system\")}\n >\n <Monitor className=\"h-4 w-4\" /> Sistema\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface EmptyStateProps {\n icon?: ReactNode\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function EmptyState({ icon, title, description, action, className }: EmptyStateProps) {\n return (\n <div className={`flex flex-col items-center justify-center py-16 text-center ${className ?? \"\"}`}>\n {icon && <div className=\"mb-4 text-muted-foreground\">{icon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{title}</h3>\n {description && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n )\n}\n","import * as AlertDialog from \"@radix-ui/react-alert-dialog\"\nimport type { ReactNode } from \"react\"\n\ninterface ConfirmDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n title: string\n description: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n loading?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nexport function ConfirmDialog({\n open,\n onOpenChange,\n onConfirm,\n title,\n description,\n confirmLabel = \"Confirmar\",\n cancelLabel = \"Cancelar\",\n loading = false,\n variant = \"default\",\n}: ConfirmDialogProps) {\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Portal>\n <AlertDialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <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\">\n <div className=\"flex flex-col space-y-2 text-center sm:text-left\">\n <AlertDialog.Title className=\"text-lg font-semibold\">{title}</AlertDialog.Title>\n <AlertDialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </AlertDialog.Description>\n </div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <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\">\n {cancelLabel}\n </AlertDialog.Cancel>\n <AlertDialog.Action\n onClick={onConfirm}\n disabled={loading}\n 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 ${\n variant === \"destructive\"\n ? \"bg-destructive text-destructive-foreground hover:bg-destructive/90\"\n : \"bg-primary text-primary-foreground hover:bg-primary/90\"\n }`}\n >\n {loading ? \"Aguarde...\" : confirmLabel}\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface PageHeaderProps {\n title: string\n description?: string\n action?: ReactNode\n className?: string\n}\n\nexport function PageHeader({ title, description, action, className }: PageHeaderProps) {\n return (\n <div\n className={`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between ${className ?? \"\"}`}\n >\n <div className=\"min-w-0\">\n <h1 className=\"truncate text-2xl font-semibold tracking-tight\">\n {title}\n </h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div className=\"shrink-0\">{action}</div>}\n </div>\n )\n}\n","interface StatusDotProps {\n active: boolean\n label?: string\n className?: string\n}\n\nexport function StatusDot({ active, label, className }: StatusDotProps) {\n return (\n <span className={`inline-flex items-center gap-2 ${className ?? \"\"}`}>\n <span\n className={`h-2 w-2 rounded-full ${active ? \"bg-green-500\" : \"bg-red-500\"}`}\n />\n {label && <span>{label}</span>}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport type StatusBadgeVariant =\n | \"neutral\"\n | \"info\"\n | \"success\"\n | \"danger\"\n | \"warning\"\n\ninterface StatusBadgeProps {\n variant?: StatusBadgeVariant\n dot?: boolean\n className?: string\n children: ReactNode\n}\n\nconst variantClasses: Record<\n StatusBadgeVariant,\n { badge: string; dot: string }\n> = {\n neutral: {\n badge: \"bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300\",\n dot: \"bg-gray-400\",\n },\n info: {\n badge: \"bg-blue-100 text-blue-700 dark:bg-blue-950 dark:text-blue-400\",\n dot: \"bg-blue-500\",\n },\n success: {\n badge: \"bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-400\",\n dot: \"bg-green-500\",\n },\n danger: {\n badge: \"bg-red-100 text-red-700 dark:bg-red-950 dark:text-red-400\",\n dot: \"bg-red-500\",\n },\n warning: {\n badge: \"bg-amber-100 text-amber-700 dark:bg-amber-950 dark:text-amber-400\",\n dot: \"bg-amber-500\",\n },\n}\n\nexport function StatusBadge({\n variant = \"neutral\",\n dot = true,\n className,\n children,\n}: StatusBadgeProps) {\n const classes = variantClasses[variant]\n\n return (\n <span\n className={`inline-flex items-center gap-1.5 rounded-md px-2 py-0.5 text-xs font-medium ${classes.badge} ${className ?? \"\"}`}\n >\n {dot && (\n <span\n className={`inline-block h-1.5 w-1.5 shrink-0 rounded-full ${classes.dot}`}\n />\n )}\n {children}\n </span>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ProgressBarProps {\n value: number\n size?: \"sm\" | \"md\"\n label?: ReactNode\n valueLabel?: ReactNode\n className?: string\n indicatorClassName?: string\n}\n\nconst sizeClasses = {\n sm: \"h-1.5\",\n md: \"h-2\",\n} as const\n\nexport function ProgressBar({\n value,\n size = \"md\",\n label,\n valueLabel,\n className,\n indicatorClassName,\n}: ProgressBarProps) {\n const clamped = Math.min(100, Math.max(0, value))\n\n return (\n <div className={`space-y-1.5 ${className ?? \"\"}`}>\n {(label || valueLabel) && (\n <div className=\"flex items-baseline justify-between gap-2\">\n {label && (\n <span className=\"text-sm text-muted-foreground\">{label}</span>\n )}\n {valueLabel && (\n <span className=\"text-sm font-semibold\">{valueLabel}</span>\n )}\n </div>\n )}\n <div\n className={`w-full overflow-hidden rounded-full bg-muted ${sizeClasses[size]}`}\n >\n <div\n className={`h-full rounded-full transition-all duration-300 ${indicatorClassName ?? \"bg-primary\"}`}\n style={{ width: `${clamped}%` }}\n />\n </div>\n </div>\n )\n}\n","import { type ReactElement, type ReactNode, cloneElement, isValidElement, useId } from \"react\"\n\ninterface FormFieldProps {\n label: string\n htmlFor?: string\n error?: string\n required?: boolean\n children: ReactNode\n className?: string\n}\n\nexport function FormField({ label, htmlFor, error, required, children, className }: FormFieldProps) {\n const errorId = useId()\n\n // Wire accessibility onto the control: mark it invalid and point it at the\n // error message so screen readers announce both.\n const field =\n error && isValidElement(children)\n ? cloneElement(children as ReactElement<Record<string, unknown>>, {\n \"aria-invalid\": true,\n \"aria-describedby\": [\n (children.props as Record<string, unknown>)[\"aria-describedby\"],\n errorId,\n ]\n .filter(Boolean)\n .join(\" \"),\n })\n : children\n\n return (\n <div className={`space-y-2 ${className ?? \"\"}`}>\n <label\n htmlFor={htmlFor}\n className=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n {required && <span className=\"ml-1 text-destructive\">*</span>}\n </label>\n {field}\n {error && (\n <p id={errorId} className=\"text-sm text-destructive\">\n {error}\n </p>\n )}\n </div>\n )\n}\n","import * as Dialog from \"@radix-ui/react-dialog\"\nimport { X } from \"lucide-react\"\nimport * as React from \"react\"\nimport type { ReactNode } from \"react\"\n\nimport { cn } from \"../lib/utils\"\n\ninterface FormDialogLayoutProps {\n title: string\n children: ReactNode\n onSubmit: (e: React.FormEvent) => void\n submitLabel?: string\n cancelLabel?: string\n onCancel: () => void\n isSubmitting?: boolean\n isDisabled?: boolean\n}\n\nexport function FormDialogLayout({\n title,\n children,\n onSubmit,\n submitLabel = \"Salvar\",\n cancelLabel = \"Cancelar\",\n onCancel,\n isSubmitting = false,\n isDisabled = false,\n}: FormDialogLayoutProps) {\n return (\n <form onSubmit={onSubmit}>\n <div className=\"flex flex-col space-y-1.5 text-center sm:text-left\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">{title}</h2>\n </div>\n <div className=\"space-y-4 py-4\">{children}</div>\n <div className=\"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\">\n <button\n type=\"button\"\n onClick={onCancel}\n 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\"\n >\n {cancelLabel}\n </button>\n <button\n type=\"submit\"\n disabled={isSubmitting || isDisabled}\n 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\"\n >\n {isSubmitting ? \"Salvando...\" : submitLabel}\n </button>\n </div>\n </form>\n )\n}\n\nconst sizeClasses = {\n sm: \"sm:max-w-sm\",\n md: \"sm:max-w-md\",\n lg: \"sm:max-w-lg\",\n xl: \"sm:max-w-xl\",\n \"2xl\": \"sm:max-w-2xl\",\n} as const\n\nexport type FormDialogSize = keyof typeof sizeClasses\n\ninterface FormDialogProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n description?: ReactNode\n children: ReactNode\n footer?: ReactNode\n /** When provided, the dialog renders a <form> wrapping body + footer. */\n onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void\n size?: FormDialogSize\n className?: string\n}\n\n/**\n * Standardized, responsive modal:\n * - mobile: bottom sheet (full width, up to 92vh tall)\n * - desktop: centered dialog (up to 90vh tall)\n * Header and footer stay fixed; only the body scrolls.\n *\n * Also fixes the known Radix bug where `body { pointer-events: none }`\n * can persist after closing a dialog that contained a Select/Popover,\n * which would otherwise make the rest of the page unclickable.\n */\nexport function FormDialog({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n onSubmit,\n size = \"lg\",\n className,\n}: FormDialogProps) {\n React.useEffect(() => {\n if (open) return\n const id = window.setTimeout(() => {\n if (document.body.style.pointerEvents === \"none\") {\n document.body.style.pointerEvents = \"\"\n }\n }, 0)\n return () => window.clearTimeout(id)\n }, [open])\n\n const body = (\n <>\n <div className=\"flex shrink-0 items-start justify-between gap-4 border-b px-6 py-3\">\n <div className=\"min-w-0 space-y-1\">\n <Dialog.Title className=\"text-lg font-semibold leading-none tracking-tight\">\n {title}\n </Dialog.Title>\n {description && (\n <Dialog.Description className=\"text-sm text-muted-foreground\">\n {description}\n </Dialog.Description>\n )}\n </div>\n <Dialog.Close\n 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\"\n aria-label=\"Fechar\"\n >\n <X className=\"h-5 w-5\" />\n </Dialog.Close>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-6 py-4\">{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-3 sm:flex-row sm:justify-end\">\n {footer}\n </div>\n )}\n </>\n )\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <Dialog.Content\n onCloseAutoFocus={() => {\n document.body.style.pointerEvents = \"\"\n }}\n className={cn(\n \"fixed z-50 flex max-h-[92vh] flex-col bg-background shadow-lg outline-none\",\n \"inset-x-0 bottom-0 rounded-t-2xl\",\n \"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\",\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n sizeClasses[size],\n className,\n )}\n >\n {onSubmit ? (\n <form\n onSubmit={onSubmit}\n className=\"flex min-h-0 flex-1 flex-col\"\n >\n {body}\n </form>\n ) : (\n body\n )}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import type { ReactNode } from \"react\"\n\ninterface AuthCardProps {\n title: string\n description?: string\n children: ReactNode\n footer?: ReactNode\n}\n\nexport function AuthCard({ title, description, children, footer }: AuthCardProps) {\n return (\n <div className=\"flex min-h-screen items-center justify-center px-4\">\n <div className=\"w-full max-w-sm rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"mb-6 text-center\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n <div className=\"space-y-4\">{children}</div>\n {footer && <div className=\"mt-4\">{footer}</div>}\n </div>\n </div>\n )\n}\n","interface PaginationProps {\n page: number\n onPageChange: (page: number) => void\n hasNextPage: boolean\n hasPreviousPage: boolean\n className?: string\n}\n\nexport function Pagination({ page, onPageChange, hasNextPage, hasPreviousPage, className }: PaginationProps) {\n return (\n <div className={`flex items-center justify-end gap-4 ${className ?? \"\"}`}>\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )\n}\n","interface TableSkeletonProps {\n rows?: number\n columns?: number\n}\n\nexport function TableSkeleton({ rows = 5, columns = 4 }: TableSkeletonProps) {\n return (\n <>\n {Array.from({ length: rows }).map((_, i) => (\n <tr key={i} className=\"border-b transition-colors\">\n {Array.from({ length: columns }).map((_, j) => (\n <td key={j} className=\"p-4 align-middle\">\n <div className=\"h-5 w-full animate-pulse rounded bg-muted\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n )\n}\n","import * as React from \"react\"\n\ninterface SearchInputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n containerClassName?: string\n}\n\nexport const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(\n ({ containerClassName, className, ...props }, ref) => {\n return (\n <div className={`relative flex-1 ${containerClassName ?? \"\"}`}>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n <input\n ref={ref}\n type=\"text\"\n 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 ?? \"\"}`}\n {...props}\n />\n </div>\n )\n }\n)\nSearchInput.displayName = \"SearchInput\"\n","import type { ReactNode } from \"react\"\n\ninterface StatCardProps {\n label: string\n value: ReactNode\n detail?: string\n icon?: ReactNode\n isLoading?: boolean\n}\n\nexport function StatCard({ label, value, detail, icon, isLoading }: StatCardProps) {\n if (isLoading) {\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-4 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"mt-2 h-7 w-16 animate-pulse rounded bg-muted\" />\n <div className=\"mt-1 h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n )\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6 shadow-sm\">\n <div className=\"flex items-center justify-between pb-2\">\n <span className=\"text-sm font-medium text-muted-foreground\">{label}</span>\n {icon && <span className=\"text-muted-foreground\">{icon}</span>}\n </div>\n <div className=\"text-2xl font-bold\">{value}</div>\n {detail && <p className=\"text-xs text-muted-foreground\">{detail}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface DataTableWrapperProps {\n children: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n page?: number\n onPageChange?: (page: number) => void\n hasNextPage?: boolean\n hasPreviousPage?: boolean\n}\n\nexport function DataTableWrapper({\n children,\n isEmpty,\n isLoading,\n emptyIcon,\n emptyTitle = \"Nenhum registro encontrado\",\n emptyDescription,\n page,\n onPageChange,\n hasNextPage = false,\n hasPreviousPage = false,\n}: DataTableWrapperProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-x-auto rounded-md border\">{children}</div>\n\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && (\n <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>\n )}\n </div>\n )}\n\n {page !== undefined && onPageChange && (\n <div className=\"flex items-center justify-end gap-4\">\n <button\n type=\"button\"\n onClick={() => onPageChange(page - 1)}\n disabled={!hasPreviousPage}\n 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\"\n >\n Anterior\n </button>\n <span className=\"text-sm text-muted-foreground\">Página {page}</span>\n <button\n type=\"button\"\n onClick={() => onPageChange(page + 1)}\n disabled={!hasNextPage}\n 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\"\n >\n Próximo\n </button>\n </div>\n )}\n </div>\n )\n}\n","import { type MouseEvent, type ReactNode, type TouchEvent, useRef } from \"react\"\n\ninterface MobileCardListProps<T> {\n data: T[]\n renderCard: (item: T, index: number) => ReactNode\n keyExtractor: (item: T) => string\n isLoading?: boolean\n loadingCount?: number\n className?: string\n}\n\n// Movimento (px) acima do qual o gesto é tratado como scroll, não tap.\nconst SCROLL_THRESHOLD = 8\n\nexport function MobileCardList<T>({\n data,\n renderCard,\n keyExtractor,\n isLoading = false,\n loadingCount = 5,\n className,\n}: MobileCardListProps<T>) {\n // Guard contra tap acidental durante o scroll: se o dedo se moveu além do\n // threshold, o clique seguinte (ex.: botão de ações dentro do card) é\n // cancelado na fase de captura, antes de chegar no elemento interativo.\n const start = useRef<{ x: number; y: number } | null>(null)\n const scrolled = useRef(false)\n\n const onTouchStart = (e: TouchEvent<HTMLDivElement>) => {\n const t = e.touches[0]\n start.current = { x: t.clientX, y: t.clientY }\n scrolled.current = false\n }\n\n const onTouchMove = (e: TouchEvent<HTMLDivElement>) => {\n if (!start.current) return\n const t = e.touches[0]\n if (\n Math.abs(t.clientX - start.current.x) > SCROLL_THRESHOLD ||\n Math.abs(t.clientY - start.current.y) > SCROLL_THRESHOLD\n ) {\n scrolled.current = true\n }\n }\n\n const onClickCapture = (e: MouseEvent<HTMLDivElement>) => {\n if (scrolled.current) {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n\n if (isLoading) {\n return (\n <div className={`space-y-3 ${className ?? \"\"}`}>\n {Array.from({ length: loadingCount }).map((_, i) => (\n <div key={i} className=\"rounded-xl border p-4\">\n <div className=\"space-y-3\">\n <div className=\"flex justify-between\">\n <div className=\"h-5 w-32 animate-pulse rounded bg-muted\" />\n <div className=\"h-5 w-16 animate-pulse rounded bg-muted\" />\n </div>\n <div className=\"h-4 w-48 animate-pulse rounded bg-muted\" />\n <div className=\"flex justify-between\">\n <div className=\"h-4 w-24 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-20 animate-pulse rounded bg-muted\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div\n className={`space-y-3 ${className ?? \"\"}`}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n onClickCapture={onClickCapture}\n >\n {data.map((item, index) => (\n <div\n key={keyExtractor(item)}\n className=\"rounded-xl border p-4 transition-all duration-150 hover:border-foreground/20 active:scale-[0.99]\"\n >\n {renderCard(item, index)}\n </div>\n ))}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\n\ninterface ResponsiveDataViewProps {\n table: ReactNode\n cards: ReactNode\n isEmpty: boolean\n isLoading: boolean\n emptyIcon?: ReactNode\n emptyTitle?: string\n emptyDescription?: string\n pagination?: ReactNode\n}\n\nexport function ResponsiveDataView({\n table, cards, isEmpty, isLoading, emptyIcon, emptyTitle = \"Nenhum registro encontrado\", emptyDescription, pagination,\n}: ResponsiveDataViewProps) {\n return (\n <div className=\"space-y-4\">\n <div className=\"hidden overflow-x-auto rounded-md border md:block\">{table}</div>\n <div className=\"md:hidden\">{cards}</div>\n {!isLoading && isEmpty && (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n {emptyIcon && <div className=\"mb-4 text-muted-foreground\">{emptyIcon}</div>}\n <h3 className=\"text-lg font-semibold tracking-tight\">{emptyTitle}</h3>\n {emptyDescription && <p className=\"mt-1 max-w-sm text-sm text-muted-foreground\">{emptyDescription}</p>}\n </div>\n )}\n {pagination}\n </div>\n )\n}\n","import { useTheme } from \"./theme-provider\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps<typeof Sonner>\n\nexport function Toaster(props: ToasterProps) {\n const { theme = \"system\" } = useTheme()\n\n return (\n <Sonner\n theme={theme as ToasterProps[\"theme\"]}\n className=\"toaster group\"\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n success:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40\",\n error:\n \"group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40\",\n },\n }}\n {...props}\n />\n )\n}\n","import { ChevronLeft, ChevronRight, Menu } from \"lucide-react\"\nimport { type ReactNode, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { SidebarNav, type NavItem } from \"./sidebar-nav\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\nimport { UserMenu, type AppUser, type UserMenuItem } from \"./user-menu\"\n\nexport interface AppShellProps {\n brand: ReactNode\n brandCollapsed?: ReactNode\n navItems: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n user?: AppUser\n userMenuItems?: UserMenuItem[]\n onLogout?: () => void\n renderLink?: RenderLink\n headerActions?: ReactNode\n collapsible?: boolean\n defaultCollapsed?: boolean\n children: ReactNode\n}\n\nexport function AppShell({\n brand,\n brandCollapsed,\n navItems,\n activePath,\n isActive,\n isAdmin = false,\n user,\n userMenuItems,\n onLogout,\n renderLink = defaultRenderLink,\n headerActions,\n collapsible = true,\n defaultCollapsed = false,\n children,\n}: AppShellProps) {\n const [collapsed, setCollapsed] = useState(defaultCollapsed)\n const [mobileOpen, setMobileOpen] = useState(false)\n\n const nav = (isCollapsed: boolean, onNavigate?: () => void) => (\n <SidebarNav\n items={navItems}\n activePath={activePath}\n isActive={isActive}\n isAdmin={isAdmin}\n isCollapsed={isCollapsed}\n renderLink={renderLink}\n onNavigate={onNavigate}\n />\n )\n\n return (\n <div className=\"flex h-screen overflow-hidden bg-background\">\n {/* Desktop sidebar */}\n <aside\n className={cn(\n \"hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex\",\n collapsed ? \"w-16\" : \"w-60\",\n )}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(collapsed)}</div>\n {collapsible && (\n <div className=\"border-t p-2\">\n <button\n type=\"button\"\n onClick={() => setCollapsed((v) => !v)}\n 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\"\n aria-label={collapsed ? \"Expandir menu\" : \"Recolher menu\"}\n >\n {collapsed ? <ChevronRight className=\"h-4 w-4\" /> : <ChevronLeft className=\"h-4 w-4\" />}\n </button>\n </div>\n )}\n </aside>\n\n {/* Mobile drawer */}\n <div\n className={cn(\n \"fixed inset-0 z-50 transition-opacity duration-300 md:hidden\",\n mobileOpen ? \"pointer-events-auto opacity-100\" : \"pointer-events-none opacity-0\",\n )}\n onClick={() => setMobileOpen(false)}\n >\n <div className=\"absolute inset-0 bg-black/50\" />\n <div\n className={cn(\n \"absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex h-14 shrink-0 items-center border-b px-4\">{brand}</div>\n <div className=\"flex-1 overflow-y-auto px-2 py-4\">{nav(false, () => setMobileOpen(false))}</div>\n </div>\n </div>\n\n {/* Main column */}\n <div className=\"flex flex-1 flex-col overflow-hidden\">\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4\">\n <button\n type=\"button\"\n onClick={() => setMobileOpen(true)}\n 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\"\n aria-label=\"Abrir menu\"\n >\n <Menu className=\"h-4 w-4\" />\n </button>\n <div className=\"ml-auto flex items-center gap-2\">\n {headerActions}\n {(user || onLogout) && (\n <UserMenu user={user} items={userMenuItems} onLogout={onLogout} renderLink={renderLink} />\n )}\n </div>\n </header>\n <main className=\"flex-1 overflow-y-auto\">{children}</main>\n </div>\n </div>\n )\n}\n","import { Fragment, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface NavItem {\n label: string\n href: string\n icon?: ReactNode\n adminOnly?: boolean\n}\n\nexport interface SidebarNavProps {\n items: NavItem[]\n activePath: string\n isActive?: (item: NavItem, activePath: string) => boolean\n isAdmin?: boolean\n isCollapsed?: boolean\n renderLink?: RenderLink\n onNavigate?: () => void\n}\n\nfunction defaultIsActive(item: NavItem, activePath: string): boolean {\n if (item.href === \"/\") return activePath === \"/\"\n return activePath === item.href || activePath.startsWith(item.href + \"/\")\n}\n\nexport function SidebarNav({\n items,\n activePath,\n isActive = defaultIsActive,\n isAdmin = false,\n isCollapsed = false,\n renderLink = defaultRenderLink,\n onNavigate,\n}: SidebarNavProps) {\n const visible = items.filter((item) => !item.adminOnly || isAdmin)\n\n return (\n <nav className=\"flex flex-col gap-1\">\n {visible.map((item) => {\n const active = isActive(item, activePath)\n const link = renderLink({\n href: item.href,\n onClick: onNavigate,\n title: isCollapsed ? item.label : undefined,\n \"aria-current\": active ? \"page\" : undefined,\n className: cn(\n \"flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors\",\n active\n ? \"bg-accent text-accent-foreground font-semibold\"\n : \"text-muted-foreground hover:bg-accent hover:text-accent-foreground\",\n isCollapsed && \"justify-center px-2\",\n ),\n children: (\n <>\n {item.icon && <span className=\"shrink-0\">{item.icon}</span>}\n {!isCollapsed && <span className=\"truncate\">{item.label}</span>}\n </>\n ),\n })\n return <Fragment key={item.href}>{link}</Fragment>\n })}\n </nav>\n )\n}\n","import type { ReactNode } from \"react\"\n\nexport interface RenderLinkProps {\n href: string\n className?: string\n children: ReactNode\n onClick?: () => void\n title?: string\n \"aria-current\"?: \"page\"\n}\n\nexport type RenderLink = (props: RenderLinkProps) => ReactNode\n\nexport const defaultRenderLink: RenderLink = ({ children, ...props }) => (\n <a {...props}>{children}</a>\n)\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { LogOut, User } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface AppUser {\n name?: string\n email?: string\n avatarUrl?: string\n}\n\nexport interface UserMenuItem {\n label: string\n icon?: ReactNode\n href?: string\n onClick?: () => void\n}\n\nexport interface UserMenuProps {\n user?: AppUser\n items?: UserMenuItem[]\n onLogout?: () => void\n logoutLabel?: string\n renderLink?: RenderLink\n align?: \"start\" | \"center\" | \"end\"\n}\n\nfunction initials(user?: AppUser): string {\n const source = user?.name?.trim() || user?.email?.trim()\n if (!source) return \"\"\n const parts = source.split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n return source.slice(0, 2).toUpperCase()\n}\n\nconst itemClass =\n \"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\"\n\nexport function UserMenu({\n user,\n items = [],\n onLogout,\n logoutLabel = \"Sair\",\n renderLink = defaultRenderLink,\n align = \"end\",\n}: UserMenuProps) {\n const label = initials(user)\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n 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-1 focus-visible:ring-ring\"\n aria-label=\"Menu do usuário\"\n data-testid=\"user-menu\"\n >\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt={user.name ?? user.email ?? \"Avatar\"} className=\"h-full w-full object-cover\" />\n ) : label ? (\n <span>{label}</span>\n ) : (\n <User className=\"h-4 w-4\" />\n )}\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {(user?.name || user?.email) && (\n <>\n <div className=\"px-2 py-1.5\">\n {user.name && <p className=\"truncate text-sm font-medium\">{user.name}</p>}\n {user.email && <p className=\"truncate text-xs text-muted-foreground\">{user.email}</p>}\n </div>\n <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />\n </>\n )}\n\n {items.map((item) =>\n item.href ? (\n <DropdownMenu.Item key={item.label} asChild>\n {renderLink({ href: item.href, className: itemClass, children: (\n <>\n {item.icon}\n {item.label}\n </>\n ) })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item key={item.label} className={itemClass} onClick={item.onClick}>\n {item.icon}\n {item.label}\n </DropdownMenu.Item>\n ),\n )}\n\n {onLogout && (\n <>\n {items.length > 0 && <DropdownMenu.Separator className=\"-mx-1 my-1 h-px bg-border\" />}\n <DropdownMenu.Item className={cn(itemClass, \"text-destructive focus:bg-destructive/10\")} onClick={onLogout}>\n <LogOut className=\"h-4 w-4\" />\n {logoutLabel}\n </DropdownMenu.Item>\n </>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\"\nimport { MoreVertical } from \"lucide-react\"\nimport type { ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport type { RenderLink } from \"./types\"\nimport { defaultRenderLink } from \"./types\"\n\nexport interface RowAction {\n label: string\n icon?: ReactNode\n onClick?: () => void\n href?: string\n destructive?: boolean\n disabled?: boolean\n}\n\nexport interface RowActionsMenuProps {\n actions: RowAction[]\n disabled?: boolean\n align?: \"start\" | \"center\" | \"end\"\n label?: string\n renderLink?: RenderLink\n}\n\nconst itemClass =\n \"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\"\n\nexport function RowActionsMenu({\n actions,\n disabled = false,\n align = \"end\",\n label = \"Ações\",\n renderLink = defaultRenderLink,\n}: RowActionsMenuProps) {\n if (actions.length === 0) return null\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={label}\n className=\"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-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\"\n >\n <MoreVertical className=\"h-4 w-4\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n align={align}\n sideOffset={6}\n 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\"\n >\n {actions.map((action) => {\n const cls = cn(itemClass, action.destructive && \"text-destructive focus:bg-destructive/10\")\n return action.href ? (\n <DropdownMenu.Item key={action.label} asChild disabled={action.disabled}>\n {renderLink({\n href: action.href,\n className: cls,\n children: (\n <>\n {action.icon}\n {action.label}\n </>\n ),\n })}\n </DropdownMenu.Item>\n ) : (\n <DropdownMenu.Item\n key={action.label}\n className={cls}\n disabled={action.disabled}\n onClick={action.onClick}\n >\n {action.icon}\n {action.label}\n </DropdownMenu.Item>\n )\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n )\n}\n","export function extractApiError(err: any, fallbackMessage = \"Ocorreu um erro inesperado.\"): string {\n const detail = err?.body?.detail || err?.message\n if (Array.isArray(detail) && detail.length > 0) {\n return detail[0].msg\n }\n return detail || fallbackMessage\n}\n","import { useCallback, useState } from \"react\"\n\nexport function useDisclosure(initial = false) {\n const [open, setOpen] = useState(initial)\n const onOpen = useCallback(() => setOpen(true), [])\n const onClose = useCallback(() => setOpen(false), [])\n const onToggle = useCallback(() => setOpen((v) => !v), [])\n return { open, onOpen, onClose, onToggle, setOpen }\n}\n","import { toast } from \"sonner\"\nimport { useCallback } from \"react\"\n\ntype ToastStatus = \"success\" | \"error\" | \"info\" | \"warning\"\n\nexport function useCustomToast() {\n const showToast = useCallback(\n (title: string, description?: string, status: ToastStatus = \"success\") => {\n switch (status) {\n case \"success\":\n toast.success(title, { description })\n break\n case \"error\":\n toast.error(title, { description })\n break\n case \"info\":\n toast.info(title, { description })\n break\n case \"warning\":\n toast.warning(title, { description })\n break\n }\n },\n [],\n )\n\n return showToast\n}\n\nexport { toast }\n"],"mappings":"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","names":["theme","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","sizeClasses","jsx","jsxs","jsx","jsxs","Fragment","jsx","_","React","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useState","Fragment","jsx","Fragment","jsx","jsxs","DropdownMenu","Fragment","jsx","jsxs","jsx","jsxs","useState","DropdownMenu","Fragment","jsx","jsxs","itemClass","useState","useCallback"]}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type MouseEvent, type ReactNode, type TouchEvent, useRef } from "react"
|
|
2
2
|
|
|
3
3
|
interface MobileCardListProps<T> {
|
|
4
4
|
data: T[]
|
|
@@ -9,6 +9,9 @@ interface MobileCardListProps<T> {
|
|
|
9
9
|
className?: string
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// Movimento (px) acima do qual o gesto é tratado como scroll, não tap.
|
|
13
|
+
const SCROLL_THRESHOLD = 8
|
|
14
|
+
|
|
12
15
|
export function MobileCardList<T>({
|
|
13
16
|
data,
|
|
14
17
|
renderCard,
|
|
@@ -17,6 +20,36 @@ export function MobileCardList<T>({
|
|
|
17
20
|
loadingCount = 5,
|
|
18
21
|
className,
|
|
19
22
|
}: MobileCardListProps<T>) {
|
|
23
|
+
// Guard contra tap acidental durante o scroll: se o dedo se moveu além do
|
|
24
|
+
// threshold, o clique seguinte (ex.: botão de ações dentro do card) é
|
|
25
|
+
// cancelado na fase de captura, antes de chegar no elemento interativo.
|
|
26
|
+
const start = useRef<{ x: number; y: number } | null>(null)
|
|
27
|
+
const scrolled = useRef(false)
|
|
28
|
+
|
|
29
|
+
const onTouchStart = (e: TouchEvent<HTMLDivElement>) => {
|
|
30
|
+
const t = e.touches[0]
|
|
31
|
+
start.current = { x: t.clientX, y: t.clientY }
|
|
32
|
+
scrolled.current = false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const onTouchMove = (e: TouchEvent<HTMLDivElement>) => {
|
|
36
|
+
if (!start.current) return
|
|
37
|
+
const t = e.touches[0]
|
|
38
|
+
if (
|
|
39
|
+
Math.abs(t.clientX - start.current.x) > SCROLL_THRESHOLD ||
|
|
40
|
+
Math.abs(t.clientY - start.current.y) > SCROLL_THRESHOLD
|
|
41
|
+
) {
|
|
42
|
+
scrolled.current = true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const onClickCapture = (e: MouseEvent<HTMLDivElement>) => {
|
|
47
|
+
if (scrolled.current) {
|
|
48
|
+
e.preventDefault()
|
|
49
|
+
e.stopPropagation()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
20
53
|
if (isLoading) {
|
|
21
54
|
return (
|
|
22
55
|
<div className={`space-y-3 ${className ?? ""}`}>
|
|
@@ -40,7 +73,12 @@ export function MobileCardList<T>({
|
|
|
40
73
|
}
|
|
41
74
|
|
|
42
75
|
return (
|
|
43
|
-
<div
|
|
76
|
+
<div
|
|
77
|
+
className={`space-y-3 ${className ?? ""}`}
|
|
78
|
+
onTouchStart={onTouchStart}
|
|
79
|
+
onTouchMove={onTouchMove}
|
|
80
|
+
onClickCapture={onClickCapture}
|
|
81
|
+
>
|
|
44
82
|
{data.map((item, index) => (
|
|
45
83
|
<div
|
|
46
84
|
key={keyExtractor(item)}
|