@motor-hero/ui-kit 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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/form-field.tsx","../src/components/form-dialog.tsx","../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/lib/utils.ts","../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 { FormField } from \"./components/form-field\"\nexport { FormDialogLayout } 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// 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=\"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 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 className={`flex items-center justify-between ${className ?? \"\"}`}>\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div>{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\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 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 {children}\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\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","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 { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA+D;AAsD3D;AAvCJ,IAAM,eAAmC;AAAA,EACvC,OAAO;AAAA,EACP,UAAU,MAAM;AAClB;AAEA,IAAM,2BAAuB,4BAAkC,YAAY;AAEpE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,eAAe;AAAA,EACf,aAAa;AAAA,EACb,GAAG;AACL,GAAuB;AACrB,QAAM,CAAC,OAAO,QAAQ,QAAI;AAAA,IACxB,MAAO,aAAa,QAAQ,UAAU,KAAe;AAAA,EACvD;AAEA,8BAAU,MAAM;AACd,UAAM,OAAO,OAAO,SAAS;AAC7B,SAAK,UAAU,OAAO,SAAS,MAAM;AACrC,QAAI,UAAU,UAAU;AACtB,YAAM,cAAc,OAAO,WAAW,8BAA8B,EAAE,UAClE,SACA;AACJ,WAAK,UAAU,IAAI,WAAW;AAC9B;AAAA,IACF;AACA,SAAK,UAAU,IAAI,KAAK;AAAA,EAC1B,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,UAAU,CAACA,WAAiB;AAC1B,mBAAa,QAAQ,YAAYA,MAAK;AACtC,eAASA,MAAK;AAAA,IAChB;AAAA,EACF;AAEA,SACE,4CAAC,qBAAqB,UAArB,EAA+B,GAAG,OAAO,OACvC,UACH;AAEJ;AAEO,SAAS,WAAW;AACzB,QAAM,cAAU,yBAAW,oBAAoB;AAC/C,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;;;AClEA,mBAA8B;AAC9B,0BAAmC;AAS3B,IAAAC,sBAAA;AAND,SAAS,aAAa;AAC3B,QAAM,EAAE,SAAS,IAAI,SAAS;AAE9B,SACE,8CAAc,mBAAb,EACC;AAAA,iDAAc,sBAAb,EAAqB,SAAO,MAC3B;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,cAAW;AAAA,QAEX;AAAA,uDAAC,2BAAI,WAAU,0EAAyE;AAAA,UACxF,6CAAC,4BAAK,WAAU,kFAAiF;AAAA;AAAA;AAAA,IACnG,GACF;AAAA,IACA,6CAAc,qBAAb,EACC;AAAA,MAAc;AAAA,MAAb;AAAA,QACC,OAAM;AAAA,QACN,WAAU;AAAA,QAEV;AAAA;AAAA,YAAc;AAAA,YAAb;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM,SAAS,OAAO;AAAA,cAE/B;AAAA,6DAAC,2BAAI,WAAU,WAAU;AAAA,gBAAE;AAAA;AAAA;AAAA,UAC7B;AAAA,UACA;AAAA,YAAc;AAAA,YAAb;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM,SAAS,MAAM;AAAA,cAE9B;AAAA,6DAAC,4BAAK,WAAU,WAAU;AAAA,gBAAE;AAAA;AAAA;AAAA,UAC9B;AAAA,UACA;AAAA,YAAc;AAAA,YAAb;AAAA,cACC,WAAU;AAAA,cACV,SAAS,MAAM,SAAS,QAAQ;AAAA,cAEhC;AAAA,6DAAC,+BAAQ,WAAU,WAAU;AAAA,gBAAE;AAAA;AAAA;AAAA,UACjC;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;;;AClCI,IAAAC,sBAAA;AAFG,SAAS,WAAW,EAAE,MAAM,OAAO,aAAa,QAAQ,UAAU,GAAoB;AAC3F,SACE,8CAAC,SAAI,WAAW,+DAA+D,aAAa,EAAE,IAC3F;AAAA,YAAQ,6CAAC,SAAI,WAAU,8BAA8B,gBAAK;AAAA,IAC3D,6CAAC,QAAG,WAAU,wCAAwC,iBAAM;AAAA,IAC3D,eACC,6CAAC,OAAE,WAAU,+CAA+C,uBAAY;AAAA,IAEzE,UAAU,6CAAC,SAAI,WAAU,QAAQ,kBAAO;AAAA,KAC3C;AAEJ;;;ACrBA,kBAA6B;AA6BrB,IAAAC,sBAAA;AAdD,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd,UAAU;AAAA,EACV,UAAU;AACZ,GAAuB;AACrB,SACE,6CAAa,kBAAZ,EAAiB,MAAY,cAC5B,wDAAa,oBAAZ,EACC;AAAA,iDAAa,qBAAZ,EAAoB,WAAU,0JAAyJ;AAAA,IACxL,8CAAa,qBAAZ,EAAoB,WAAU,ufAC7B;AAAA,oDAAC,SAAI,WAAU,oDACb;AAAA,qDAAa,mBAAZ,EAAkB,WAAU,yBAAyB,iBAAM;AAAA,QAC5D,6CAAa,yBAAZ,EAAwB,WAAU,iCAChC,uBACH;AAAA,SACF;AAAA,MACA,8CAAC,SAAI,WAAU,0DACb;AAAA,qDAAa,oBAAZ,EAAmB,WAAU,sUAC3B,uBACH;AAAA,QACA;AAAA,UAAa;AAAA,UAAZ;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,WAAW,oPACT,YAAY,gBACR,uEACA,wDACN;AAAA,YAEC,oBAAU,eAAe;AAAA;AAAA,QAC5B;AAAA,SACF;AAAA,OACF;AAAA,KACF,GACF;AAEJ;;;AC7CM,IAAAC,sBAAA;AAHC,SAAS,WAAW,EAAE,OAAO,aAAa,QAAQ,UAAU,GAAoB;AACrF,SACE,8CAAC,SAAI,WAAW,qCAAqC,aAAa,EAAE,IAClE;AAAA,kDAAC,SACC;AAAA,mDAAC,QAAG,WAAU,yCAAyC,iBAAM;AAAA,MAC5D,eACC,6CAAC,OAAE,WAAU,iCAAiC,uBAAY;AAAA,OAE9D;AAAA,IACC,UAAU,6CAAC,SAAK,kBAAO;AAAA,KAC1B;AAEJ;;;ACbI,IAAAC,sBAAA;AAFG,SAAS,UAAU,EAAE,QAAQ,OAAO,UAAU,GAAmB;AACtE,SACE,8CAAC,UAAK,WAAW,kCAAkC,aAAa,EAAE,IAChE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,wBAAwB,SAAS,iBAAiB,YAAY;AAAA;AAAA,IAC3E;AAAA,IACC,SAAS,6CAAC,UAAM,iBAAM;AAAA,KACzB;AAEJ;;;ACDM,IAAAC,sBAAA;AAHC,SAAS,UAAU,EAAE,OAAO,SAAS,OAAO,UAAU,UAAU,UAAU,GAAmB;AAClG,SACE,8CAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IAC1C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAU;AAAA,QAET;AAAA;AAAA,UACA,YAAY,6CAAC,UAAK,WAAU,yBAAwB,eAAC;AAAA;AAAA;AAAA,IACxD;AAAA,IACC;AAAA,IACA,SAAS,6CAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,KAC3D;AAEJ;;;ACCQ,IAAAC,sBAAA;AAbD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd;AAAA,EACA,eAAe;AAAA,EACf,aAAa;AACf,GAA0B;AACxB,SACE,8CAAC,UAAK,UACJ;AAAA,iDAAC,SAAI,WAAU,sDACb,uDAAC,QAAG,WAAU,qDAAqD,iBAAM,GAC3E;AAAA,IACA,6CAAC,SAAI,WAAU,kBAAkB,UAAS;AAAA,IAC1C,8CAAC,SAAI,WAAU,0DACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,gBAAgB;AAAA,UAC1B,WAAU;AAAA,UAET,yBAAe,gBAAgB;AAAA;AAAA,MAClC;AAAA,OACF;AAAA,KACF;AAEJ;;;AClCQ,IAAAC,sBAAA;AAJD,SAAS,SAAS,EAAE,OAAO,aAAa,UAAU,OAAO,GAAkB;AAChF,SACE,6CAAC,SAAI,WAAU,sDACb,wDAAC,SAAI,WAAU,2DACb;AAAA,kDAAC,SAAI,WAAU,oBACb;AAAA,mDAAC,QAAG,WAAU,yCAAyC,iBAAM;AAAA,MAC5D,eACC,6CAAC,OAAE,WAAU,sCAAsC,uBAAY;AAAA,OAEnE;AAAA,IACA,6CAAC,SAAI,WAAU,aAAa,UAAS;AAAA,IACpC,UAAU,6CAAC,SAAI,WAAU,QAAQ,kBAAO;AAAA,KAC3C,GACF;AAEJ;;;ACbM,IAAAC,uBAAA;AAHC,SAAS,WAAW,EAAE,MAAM,cAAc,aAAa,iBAAiB,UAAU,GAAoB;AAC3G,SACE,+CAAC,SAAI,WAAW,uCAAuC,aAAa,EAAE,IACpE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,aAAa,OAAO,CAAC;AAAA,QACpC,UAAU,CAAC;AAAA,QACX,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,IACA,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,MAAQ;AAAA,OAAK;AAAA,IAC7D;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,aAAa,OAAO,CAAC;AAAA,QACpC,UAAU,CAAC;AAAA,QACX,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;;;ACvBI,IAAAC,uBAAA;AAFG,SAAS,cAAc,EAAE,OAAO,GAAG,UAAU,EAAE,GAAuB;AAC3E,SACE,+EACG,gBAAM,KAAK,EAAE,QAAQ,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,MACpC,8CAAC,QAAW,WAAU,8BACnB,gBAAM,KAAK,EAAE,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAACC,IAAG,MACvC,8CAAC,QAAW,WAAU,oBACpB,wDAAC,SAAI,WAAU,6CAA4C,KADpD,CAET,CACD,KALM,CAMT,CACD,GACH;AAEJ;;;ACnBA,YAAuB;AAUf,IAAAC,uBAAA;AAJD,IAAM,cAAoB;AAAA,EAC/B,CAAC,EAAE,oBAAoB,WAAW,GAAG,MAAM,GAAG,QAAQ;AACpD,WACE,+CAAC,SAAI,WAAW,mBAAmB,sBAAsB,EAAE,IACzD;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAM;AAAA,UACN,QAAO;AAAA,UACP,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,QAAO;AAAA,UACP,aAAY;AAAA,UACZ,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,WAAU;AAAA,UAEV;AAAA,0DAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,YAC9B,8CAAC,UAAK,GAAE,kBAAiB;AAAA;AAAA;AAAA,MAC3B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,MAAK;AAAA,UACL,WAAW,+QAA+Q,aAAa,EAAE;AAAA,UACxS,GAAG;AAAA;AAAA,MACN;AAAA,OACF;AAAA,EAEJ;AACF;AACA,YAAY,cAAc;;;ACrBlB,IAAAC,uBAAA;AAJD,SAAS,SAAS,EAAE,OAAO,OAAO,QAAQ,MAAM,UAAU,GAAkB;AACjF,MAAI,WAAW;AACb,WACE,+CAAC,SAAI,WAAU,2CACb;AAAA,qDAAC,SAAI,WAAU,0CACb;AAAA,sDAAC,SAAI,WAAU,2CAA0C;AAAA,QACzD,8CAAC,SAAI,WAAU,0CAAyC;AAAA,SAC1D;AAAA,MACA,8CAAC,SAAI,WAAU,gDAA+C;AAAA,MAC9D,8CAAC,SAAI,WAAU,gDAA+C;AAAA,OAChE;AAAA,EAEJ;AAEA,SACE,+CAAC,SAAI,WAAU,2CACb;AAAA,mDAAC,SAAI,WAAU,0CACb;AAAA,oDAAC,UAAK,WAAU,6CAA6C,iBAAM;AAAA,MAClE,QAAQ,8CAAC,UAAK,WAAU,yBAAyB,gBAAK;AAAA,OACzD;AAAA,IACA,8CAAC,SAAI,WAAU,sBAAsB,iBAAM;AAAA,IAC1C,UAAU,8CAAC,OAAE,WAAU,iCAAiC,kBAAO;AAAA,KAClE;AAEJ;;;ACLM,IAAAC,uBAAA;AAdC,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,kBAAkB;AACpB,GAA0B;AACxB,SACE,+CAAC,SAAI,WAAU,aACb;AAAA,kDAAC,SAAI,WAAU,qCAAqC,UAAS;AAAA,IAE5D,CAAC,aAAa,WACb,+CAAC,SAAI,WAAU,+DACZ;AAAA,mBAAa,8CAAC,SAAI,WAAU,8BAA8B,qBAAU;AAAA,MACrE,8CAAC,QAAG,WAAU,wCAAwC,sBAAW;AAAA,MAChE,oBACC,8CAAC,OAAE,WAAU,+CAA+C,4BAAiB;AAAA,OAEjF;AAAA,IAGD,SAAS,UAAa,gBACrB,+CAAC,SAAI,WAAU,uCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,aAAa,OAAO,CAAC;AAAA,UACpC,UAAU,CAAC;AAAA,UACX,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,+CAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,QAAQ;AAAA,SAAK;AAAA,MAC7D;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,aAAa,OAAO,CAAC;AAAA,UACpC,UAAU,CAAC;AAAA,UACX,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF;AAAA,KAEJ;AAEJ;;;ACvCc,IAAAC,uBAAA;AAdP,SAAS,eAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf;AACF,GAA2B;AACzB,MAAI,WAAW;AACb,WACE,8CAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC,gBAAM,KAAK,EAAE,QAAQ,aAAa,CAAC,EAAE,IAAI,CAAC,GAAG,MAC5C,8CAAC,SAAY,WAAU,yBACrB,yDAAC,SAAI,WAAU,aACb;AAAA,qDAAC,SAAI,WAAU,wBACb;AAAA,sDAAC,SAAI,WAAU,2CAA0C;AAAA,QACzD,8CAAC,SAAI,WAAU,2CAA0C;AAAA,SAC3D;AAAA,MACA,8CAAC,SAAI,WAAU,2CAA0C;AAAA,MACzD,+CAAC,SAAI,WAAU,wBACb;AAAA,sDAAC,SAAI,WAAU,2CAA0C;AAAA,QACzD,8CAAC,SAAI,WAAU,2CAA0C;AAAA,SAC3D;AAAA,OACF,KAXQ,CAYV,CACD,GACH;AAAA,EAEJ;AAEA,SACE,8CAAC,SAAI,WAAW,aAAa,aAAa,EAAE,IACzC,eAAK,IAAI,CAAC,MAAM,UACf;AAAA,IAAC;AAAA;AAAA,MAEC,WAAU;AAAA,MAET,qBAAW,MAAM,KAAK;AAAA;AAAA,IAHlB,aAAa,IAAI;AAAA,EAIxB,CACD,GACH;AAEJ;;;ACnCM,IAAAC,uBAAA;AALC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EAAO;AAAA,EAAO;AAAA,EAAS;AAAA,EAAW;AAAA,EAAW,aAAa;AAAA,EAA8B;AAAA,EAAkB;AAC5G,GAA4B;AAC1B,SACE,+CAAC,SAAI,WAAU,aACb;AAAA,kDAAC,SAAI,WAAU,qDAAqD,iBAAM;AAAA,IAC1E,8CAAC,SAAI,WAAU,aAAa,iBAAM;AAAA,IACjC,CAAC,aAAa,WACb,+CAAC,SAAI,WAAU,+DACZ;AAAA,mBAAa,8CAAC,SAAI,WAAU,8BAA8B,qBAAU;AAAA,MACrE,8CAAC,QAAG,WAAU,wCAAwC,sBAAW;AAAA,MAChE,oBAAoB,8CAAC,OAAE,WAAU,+CAA+C,4BAAiB;AAAA,OACpG;AAAA,IAED;AAAA,KACH;AAEJ;;;AC7BA,oBAAkC;AAQ9B,IAAAC,uBAAA;AAJG,SAAS,QAAQ,OAAqB;AAC3C,QAAM,EAAE,QAAQ,SAAS,IAAI,SAAS;AAEtC,SACE;AAAA,IAAC,cAAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,cAAc;AAAA,QACZ,YAAY;AAAA,UACV,OACE;AAAA,UACF,aAAa;AAAA,UACb,cACE;AAAA,UACF,cACE;AAAA,UACF,SACE;AAAA,UACF,OACE;AAAA,QACJ;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;;;AC9BA,kBAAsC;AACtC,4BAAwB;AAEjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;ACLO,SAAS,gBAAgB,KAAU,kBAAkB,+BAAuC;AACjG,QAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,MAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,GAAG;AAC9C,WAAO,OAAO,CAAC,EAAE;AAAA,EACnB;AACA,SAAO,UAAU;AACnB;;;ACNA,IAAAC,gBAAsC;AAE/B,SAAS,cAAc,UAAU,OAAO;AAC7C,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,OAAO;AACxC,QAAM,aAAS,2BAAY,MAAM,QAAQ,IAAI,GAAG,CAAC,CAAC;AAClD,QAAM,cAAU,2BAAY,MAAM,QAAQ,KAAK,GAAG,CAAC,CAAC;AACpD,QAAM,eAAW,2BAAY,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AACzD,SAAO,EAAE,MAAM,QAAQ,SAAS,UAAU,QAAQ;AACpD;;;ACRA,IAAAC,iBAAsB;AACtB,IAAAC,gBAA4B;AAIrB,SAAS,iBAAiB;AAC/B,QAAM,gBAAY;AAAA,IAChB,CAAC,OAAe,aAAsB,SAAsB,cAAc;AACxE,cAAQ,QAAQ;AAAA,QACd,KAAK;AACH,+BAAM,QAAQ,OAAO,EAAE,YAAY,CAAC;AACpC;AAAA,QACF,KAAK;AACH,+BAAM,MAAM,OAAO,EAAE,YAAY,CAAC;AAClC;AAAA,QACF,KAAK;AACH,+BAAM,KAAK,OAAO,EAAE,YAAY,CAAC;AACjC;AAAA,QACF,KAAK;AACH,+BAAM,QAAQ,OAAO,EAAE,YAAY,CAAC;AACpC;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":["theme","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","_","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","Sonner","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/form-field.tsx","../src/components/form-dialog.tsx","../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/lib/utils.ts","../src/components/sidebar-nav.tsx","../src/components/types.tsx","../src/components/user-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 { FormField } from \"./components/form-field\"\nexport { FormDialogLayout } 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 { 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=\"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 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 className={`flex items-center justify-between ${className ?? \"\"}`}>\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">{title}</h1>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {action && <div>{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\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 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 {children}\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n </div>\n )\n}\n","import type { ReactNode } from \"react\"\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","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 { type ClassValue, clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\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 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","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_jsx_runtime","import_jsx_runtime","import_jsx_runtime","_","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","import_react","import_sonner","import_react"]}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,14 @@ export { DataTableWrapper } from "./components/data-table-wrapper";
16
16
  export { MobileCardList } from "./components/mobile-card-list";
17
17
  export { ResponsiveDataView } from "./components/responsive-data-view";
18
18
  export { Toaster } from "./components/toaster";
19
+ export { AppShell } from "./components/app-shell";
20
+ export type { AppShellProps } from "./components/app-shell";
21
+ export { SidebarNav } from "./components/sidebar-nav";
22
+ export type { NavItem, SidebarNavProps } from "./components/sidebar-nav";
23
+ export { UserMenu } from "./components/user-menu";
24
+ export type { AppUser, UserMenuItem, UserMenuProps } from "./components/user-menu";
25
+ export { defaultRenderLink } from "./components/types";
26
+ export type { RenderLink, RenderLinkProps } from "./components/types";
19
27
  export { cn } from "./lib/utils";
20
28
  export { extractApiError } from "./lib/api-error";
21
29
  export { useDisclosure } from "./hooks/use-disclosure";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACrE,YAAY,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAGhG,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAG9C,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACrE,YAAY,EAAE,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAGhG,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAG9C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGrE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA"}
package/dist/index.js CHANGED
@@ -482,6 +482,10 @@ function Toaster(props) {
482
482
  );
483
483
  }
484
484
 
485
+ // src/components/app-shell.tsx
486
+ import { ChevronLeft, ChevronRight, Menu } from "lucide-react";
487
+ import { useState as useState2 } from "react";
488
+
485
489
  // src/lib/utils.ts
486
490
  import { clsx } from "clsx";
487
491
  import { twMerge } from "tailwind-merge";
@@ -489,6 +493,223 @@ function cn(...inputs) {
489
493
  return twMerge(clsx(inputs));
490
494
  }
491
495
 
496
+ // src/components/sidebar-nav.tsx
497
+ import { Fragment as Fragment2 } from "react";
498
+
499
+ // src/components/types.tsx
500
+ import { jsx as jsx18 } from "react/jsx-runtime";
501
+ var defaultRenderLink = ({ children, ...props }) => /* @__PURE__ */ jsx18("a", { ...props, children });
502
+
503
+ // src/components/sidebar-nav.tsx
504
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
505
+ function defaultIsActive(item, activePath) {
506
+ if (item.href === "/") return activePath === "/";
507
+ return activePath === item.href || activePath.startsWith(item.href + "/");
508
+ }
509
+ function SidebarNav({
510
+ items,
511
+ activePath,
512
+ isActive = defaultIsActive,
513
+ isAdmin = false,
514
+ isCollapsed = false,
515
+ renderLink = defaultRenderLink,
516
+ onNavigate
517
+ }) {
518
+ const visible = items.filter((item) => !item.adminOnly || isAdmin);
519
+ return /* @__PURE__ */ jsx19("nav", { className: "flex flex-col gap-1", children: visible.map((item) => {
520
+ const active = isActive(item, activePath);
521
+ const link = renderLink({
522
+ href: item.href,
523
+ onClick: onNavigate,
524
+ title: isCollapsed ? item.label : void 0,
525
+ "aria-current": active ? "page" : void 0,
526
+ className: cn(
527
+ "flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
528
+ active ? "bg-accent text-accent-foreground font-semibold" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
529
+ isCollapsed && "justify-center px-2"
530
+ ),
531
+ children: /* @__PURE__ */ jsxs15(Fragment3, { children: [
532
+ item.icon && /* @__PURE__ */ jsx19("span", { className: "shrink-0", children: item.icon }),
533
+ !isCollapsed && /* @__PURE__ */ jsx19("span", { className: "truncate", children: item.label })
534
+ ] })
535
+ });
536
+ return /* @__PURE__ */ jsx19(Fragment2, { children: link }, item.href);
537
+ }) });
538
+ }
539
+
540
+ // src/components/user-menu.tsx
541
+ import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
542
+ import { LogOut, User } from "lucide-react";
543
+ import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
544
+ function initials(user) {
545
+ const source = user?.name?.trim() || user?.email?.trim();
546
+ if (!source) return "";
547
+ const parts = source.split(/\s+/);
548
+ if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
549
+ return source.slice(0, 2).toUpperCase();
550
+ }
551
+ var itemClass = "flex w-full cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent focus:bg-accent";
552
+ function UserMenu({
553
+ user,
554
+ items = [],
555
+ onLogout,
556
+ logoutLabel = "Sair",
557
+ renderLink = defaultRenderLink,
558
+ align = "end"
559
+ }) {
560
+ const label = initials(user);
561
+ return /* @__PURE__ */ jsxs16(DropdownMenu2.Root, { children: [
562
+ /* @__PURE__ */ jsx20(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx20(
563
+ "button",
564
+ {
565
+ type: "button",
566
+ 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",
567
+ "aria-label": "Menu do usu\xE1rio",
568
+ "data-testid": "user-menu",
569
+ children: user?.avatarUrl ? /* @__PURE__ */ jsx20("img", { src: user.avatarUrl, alt: user.name ?? user.email ?? "Avatar", className: "h-full w-full object-cover" }) : label ? /* @__PURE__ */ jsx20("span", { children: label }) : /* @__PURE__ */ jsx20(User, { className: "h-4 w-4" })
570
+ }
571
+ ) }),
572
+ /* @__PURE__ */ jsx20(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs16(
573
+ DropdownMenu2.Content,
574
+ {
575
+ align,
576
+ sideOffset: 6,
577
+ 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",
578
+ children: [
579
+ (user?.name || user?.email) && /* @__PURE__ */ jsxs16(Fragment4, { children: [
580
+ /* @__PURE__ */ jsxs16("div", { className: "px-2 py-1.5", children: [
581
+ user.name && /* @__PURE__ */ jsx20("p", { className: "truncate text-sm font-medium", children: user.name }),
582
+ user.email && /* @__PURE__ */ jsx20("p", { className: "truncate text-xs text-muted-foreground", children: user.email })
583
+ ] }),
584
+ /* @__PURE__ */ jsx20(DropdownMenu2.Separator, { className: "-mx-1 my-1 h-px bg-border" })
585
+ ] }),
586
+ items.map(
587
+ (item) => item.href ? /* @__PURE__ */ jsx20(DropdownMenu2.Item, { asChild: true, children: renderLink({ href: item.href, className: itemClass, children: /* @__PURE__ */ jsxs16(Fragment4, { children: [
588
+ item.icon,
589
+ item.label
590
+ ] }) }) }, item.label) : /* @__PURE__ */ jsxs16(DropdownMenu2.Item, { className: itemClass, onClick: item.onClick, children: [
591
+ item.icon,
592
+ item.label
593
+ ] }, item.label)
594
+ ),
595
+ onLogout && /* @__PURE__ */ jsxs16(Fragment4, { children: [
596
+ items.length > 0 && /* @__PURE__ */ jsx20(DropdownMenu2.Separator, { className: "-mx-1 my-1 h-px bg-border" }),
597
+ /* @__PURE__ */ jsxs16(DropdownMenu2.Item, { className: cn(itemClass, "text-destructive focus:bg-destructive/10"), onClick: onLogout, children: [
598
+ /* @__PURE__ */ jsx20(LogOut, { className: "h-4 w-4" }),
599
+ logoutLabel
600
+ ] })
601
+ ] })
602
+ ]
603
+ }
604
+ ) })
605
+ ] });
606
+ }
607
+
608
+ // src/components/app-shell.tsx
609
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
610
+ function AppShell({
611
+ brand,
612
+ brandCollapsed,
613
+ navItems,
614
+ activePath,
615
+ isActive,
616
+ isAdmin = false,
617
+ user,
618
+ userMenuItems,
619
+ onLogout,
620
+ renderLink = defaultRenderLink,
621
+ headerActions,
622
+ collapsible = true,
623
+ defaultCollapsed = false,
624
+ children
625
+ }) {
626
+ const [collapsed, setCollapsed] = useState2(defaultCollapsed);
627
+ const [mobileOpen, setMobileOpen] = useState2(false);
628
+ const nav = (isCollapsed, onNavigate) => /* @__PURE__ */ jsx21(
629
+ SidebarNav,
630
+ {
631
+ items: navItems,
632
+ activePath,
633
+ isActive,
634
+ isAdmin,
635
+ isCollapsed,
636
+ renderLink,
637
+ onNavigate
638
+ }
639
+ );
640
+ return /* @__PURE__ */ jsxs17("div", { className: "flex h-screen overflow-hidden bg-background", children: [
641
+ /* @__PURE__ */ jsxs17(
642
+ "aside",
643
+ {
644
+ className: cn(
645
+ "hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex",
646
+ collapsed ? "w-16" : "w-60"
647
+ ),
648
+ children: [
649
+ /* @__PURE__ */ jsx21("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: collapsed ? brandCollapsed ?? brand : brand }),
650
+ /* @__PURE__ */ jsx21("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(collapsed) }),
651
+ collapsible && /* @__PURE__ */ jsx21("div", { className: "border-t p-2", children: /* @__PURE__ */ jsx21(
652
+ "button",
653
+ {
654
+ type: "button",
655
+ onClick: () => setCollapsed((v) => !v),
656
+ 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",
657
+ "aria-label": collapsed ? "Expandir menu" : "Recolher menu",
658
+ children: collapsed ? /* @__PURE__ */ jsx21(ChevronRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx21(ChevronLeft, { className: "h-4 w-4" })
659
+ }
660
+ ) })
661
+ ]
662
+ }
663
+ ),
664
+ /* @__PURE__ */ jsxs17(
665
+ "div",
666
+ {
667
+ className: cn(
668
+ "fixed inset-0 z-50 transition-opacity duration-300 md:hidden",
669
+ mobileOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
670
+ ),
671
+ onClick: () => setMobileOpen(false),
672
+ children: [
673
+ /* @__PURE__ */ jsx21("div", { className: "absolute inset-0 bg-black/50" }),
674
+ /* @__PURE__ */ jsxs17(
675
+ "div",
676
+ {
677
+ className: cn(
678
+ "absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300",
679
+ mobileOpen ? "translate-x-0" : "-translate-x-full"
680
+ ),
681
+ onClick: (e) => e.stopPropagation(),
682
+ children: [
683
+ /* @__PURE__ */ jsx21("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: brand }),
684
+ /* @__PURE__ */ jsx21("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(false, () => setMobileOpen(false)) })
685
+ ]
686
+ }
687
+ )
688
+ ]
689
+ }
690
+ ),
691
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
692
+ /* @__PURE__ */ jsxs17("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4", children: [
693
+ /* @__PURE__ */ jsx21(
694
+ "button",
695
+ {
696
+ type: "button",
697
+ onClick: () => setMobileOpen(true),
698
+ 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",
699
+ "aria-label": "Abrir menu",
700
+ children: /* @__PURE__ */ jsx21(Menu, { className: "h-4 w-4" })
701
+ }
702
+ ),
703
+ /* @__PURE__ */ jsxs17("div", { className: "ml-auto flex items-center gap-2", children: [
704
+ headerActions,
705
+ (user || onLogout) && /* @__PURE__ */ jsx21(UserMenu, { user, items: userMenuItems, onLogout, renderLink })
706
+ ] })
707
+ ] }),
708
+ /* @__PURE__ */ jsx21("main", { className: "flex-1 overflow-y-auto", children })
709
+ ] })
710
+ ] });
711
+ }
712
+
492
713
  // src/lib/api-error.ts
493
714
  function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
494
715
  const detail = err?.body?.detail || err?.message;
@@ -499,9 +720,9 @@ function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
499
720
  }
500
721
 
501
722
  // src/hooks/use-disclosure.ts
502
- import { useCallback, useState as useState2 } from "react";
723
+ import { useCallback, useState as useState3 } from "react";
503
724
  function useDisclosure(initial = false) {
504
- const [open, setOpen] = useState2(initial);
725
+ const [open, setOpen] = useState3(initial);
505
726
  const onOpen = useCallback(() => setOpen(true), []);
506
727
  const onClose = useCallback(() => setOpen(false), []);
507
728
  const onToggle = useCallback(() => setOpen((v) => !v), []);
@@ -534,6 +755,7 @@ function useCustomToast() {
534
755
  return showToast;
535
756
  }
536
757
  export {
758
+ AppShell,
537
759
  AuthCard,
538
760
  ConfirmDialog,
539
761
  DataTableWrapper,
@@ -546,12 +768,15 @@ export {
546
768
  Pagination,
547
769
  ResponsiveDataView,
548
770
  SearchInput,
771
+ SidebarNav,
549
772
  StatCard,
550
773
  StatusDot,
551
774
  TableSkeleton,
552
775
  ThemeProvider,
553
776
  Toaster,
777
+ UserMenu,
554
778
  cn,
779
+ defaultRenderLink,
555
780
  extractApiError,
556
781
  toast,
557
782
  useCustomToast,