@motor-hero/ui-kit 0.8.0 → 0.9.1

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.
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from "react";
2
+ import { type NavItem } from "./sidebar-nav";
3
+ import type { RenderLink } from "./types";
4
+ import { type AppUser, type UserMenuItem } from "./user-menu";
5
+ export interface AppShellProps {
6
+ brand: ReactNode;
7
+ brandCollapsed?: ReactNode;
8
+ navItems: NavItem[];
9
+ activePath: string;
10
+ isActive?: (item: NavItem, activePath: string) => boolean;
11
+ isAdmin?: boolean;
12
+ user?: AppUser;
13
+ userMenuItems?: UserMenuItem[];
14
+ onLogout?: () => void;
15
+ renderLink?: RenderLink;
16
+ headerActions?: ReactNode;
17
+ collapsible?: boolean;
18
+ defaultCollapsed?: boolean;
19
+ children: ReactNode;
20
+ }
21
+ export declare function AppShell({ brand, brandCollapsed, navItems, activePath, isActive, isAdmin, user, userMenuItems, onLogout, renderLink, headerActions, collapsible, defaultCollapsed, children, }: AppShellProps): import("react/jsx-runtime").JSX.Element;
22
+ //# sourceMappingURL=app-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/components/app-shell.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAA;AAEhD,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAEvE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAA;IAChB,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,cAAc,EACd,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAe,EACf,IAAI,EACJ,aAAa,EACb,QAAQ,EACR,UAA8B,EAC9B,aAAa,EACb,WAAkB,EAClB,gBAAwB,EACxB,QAAQ,GACT,EAAE,aAAa,2CAsFf"}
@@ -0,0 +1,19 @@
1
+ import { type ReactNode } from "react";
2
+ import type { RenderLink } from "./types";
3
+ export interface NavItem {
4
+ label: string;
5
+ href: string;
6
+ icon?: ReactNode;
7
+ adminOnly?: boolean;
8
+ }
9
+ export interface SidebarNavProps {
10
+ items: NavItem[];
11
+ activePath: string;
12
+ isActive?: (item: NavItem, activePath: string) => boolean;
13
+ isAdmin?: boolean;
14
+ isCollapsed?: boolean;
15
+ renderLink?: RenderLink;
16
+ onNavigate?: () => void;
17
+ }
18
+ export declare function SidebarNav({ items, activePath, isActive, isAdmin, isCollapsed, renderLink, onNavigate, }: SidebarNavProps): import("react/jsx-runtime").JSX.Element;
19
+ //# sourceMappingURL=sidebar-nav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-nav.d.ts","sourceRoot":"","sources":["../../src/components/sidebar-nav.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGzC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAA;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAOD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,UAAU,EACV,QAA0B,EAC1B,OAAe,EACf,WAAmB,EACnB,UAA8B,EAC9B,UAAU,GACX,EAAE,eAAe,2CA8BjB"}
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from "react";
2
+ export interface RenderLinkProps {
3
+ href: string;
4
+ className?: string;
5
+ children: ReactNode;
6
+ onClick?: () => void;
7
+ title?: string;
8
+ "aria-current"?: "page";
9
+ }
10
+ export type RenderLink = (props: RenderLinkProps) => ReactNode;
11
+ export declare const defaultRenderLink: RenderLink;
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/components/types.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,SAAS,CAAA;AAE9D,eAAO,MAAM,iBAAiB,EAAE,UAE/B,CAAA"}
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+ import type { RenderLink } from "./types";
3
+ export interface AppUser {
4
+ name?: string;
5
+ email?: string;
6
+ avatarUrl?: string;
7
+ }
8
+ export interface UserMenuItem {
9
+ label: string;
10
+ icon?: ReactNode;
11
+ href?: string;
12
+ onClick?: () => void;
13
+ }
14
+ export interface UserMenuProps {
15
+ user?: AppUser;
16
+ items?: UserMenuItem[];
17
+ onLogout?: () => void;
18
+ logoutLabel?: string;
19
+ renderLink?: RenderLink;
20
+ align?: "start" | "center" | "end";
21
+ }
22
+ export declare function UserMenu({ user, items, onLogout, logoutLabel, renderLink, align, }: UserMenuProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=user-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-menu.d.ts","sourceRoot":"","sources":["../../src/components/user-menu.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGzC,MAAM,WAAW,OAAO;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,YAAY,EAAE,CAAA;IACtB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;CACnC;AAaD,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,KAAU,EACV,QAAQ,EACR,WAAoB,EACpB,UAA8B,EAC9B,KAAa,GACd,EAAE,aAAa,2CAoEf"}
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AppShell: () => AppShell,
33
34
  AuthCard: () => AuthCard,
34
35
  ConfirmDialog: () => ConfirmDialog,
35
36
  DataTableWrapper: () => DataTableWrapper,
@@ -42,12 +43,15 @@ __export(index_exports, {
42
43
  Pagination: () => Pagination,
43
44
  ResponsiveDataView: () => ResponsiveDataView,
44
45
  SearchInput: () => SearchInput,
46
+ SidebarNav: () => SidebarNav,
45
47
  StatCard: () => StatCard,
46
48
  StatusDot: () => StatusDot,
47
49
  TableSkeleton: () => TableSkeleton,
48
50
  ThemeProvider: () => ThemeProvider,
49
51
  Toaster: () => Toaster,
52
+ UserMenu: () => UserMenu,
50
53
  cn: () => cn,
54
+ defaultRenderLink: () => defaultRenderLink,
51
55
  extractApiError: () => extractApiError,
52
56
  toast: () => import_sonner2.toast,
53
57
  useCustomToast: () => useCustomToast,
@@ -540,6 +544,10 @@ function Toaster(props) {
540
544
  );
541
545
  }
542
546
 
547
+ // src/components/app-shell.tsx
548
+ var import_lucide_react3 = require("lucide-react");
549
+ var import_react3 = require("react");
550
+
543
551
  // src/lib/utils.ts
544
552
  var import_clsx = require("clsx");
545
553
  var import_tailwind_merge = require("tailwind-merge");
@@ -547,6 +555,223 @@ function cn(...inputs) {
547
555
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
548
556
  }
549
557
 
558
+ // src/components/sidebar-nav.tsx
559
+ var import_react2 = require("react");
560
+
561
+ // src/components/types.tsx
562
+ var import_jsx_runtime18 = require("react/jsx-runtime");
563
+ var defaultRenderLink = ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { ...props, children });
564
+
565
+ // src/components/sidebar-nav.tsx
566
+ var import_jsx_runtime19 = require("react/jsx-runtime");
567
+ function defaultIsActive(item, activePath) {
568
+ if (item.href === "/") return activePath === "/";
569
+ return activePath === item.href || activePath.startsWith(item.href + "/");
570
+ }
571
+ function SidebarNav({
572
+ items,
573
+ activePath,
574
+ isActive = defaultIsActive,
575
+ isAdmin = false,
576
+ isCollapsed = false,
577
+ renderLink = defaultRenderLink,
578
+ onNavigate
579
+ }) {
580
+ const visible = items.filter((item) => !item.adminOnly || isAdmin);
581
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("nav", { className: "flex flex-col gap-1", children: visible.map((item) => {
582
+ const active = isActive(item, activePath);
583
+ const link = renderLink({
584
+ href: item.href,
585
+ onClick: onNavigate,
586
+ title: isCollapsed ? item.label : void 0,
587
+ "aria-current": active ? "page" : void 0,
588
+ className: cn(
589
+ "flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
590
+ active ? "bg-accent text-accent-foreground font-semibold" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
591
+ isCollapsed && "justify-center px-2"
592
+ ),
593
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
594
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0", children: item.icon }),
595
+ !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate", children: item.label })
596
+ ] })
597
+ });
598
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react2.Fragment, { children: link }, item.href);
599
+ }) });
600
+ }
601
+
602
+ // src/components/user-menu.tsx
603
+ var DropdownMenu2 = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
604
+ var import_lucide_react2 = require("lucide-react");
605
+ var import_jsx_runtime20 = require("react/jsx-runtime");
606
+ function initials(user) {
607
+ const source = user?.name?.trim() || user?.email?.trim();
608
+ if (!source) return "";
609
+ const parts = source.split(/\s+/);
610
+ if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
611
+ return source.slice(0, 2).toUpperCase();
612
+ }
613
+ 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";
614
+ function UserMenu({
615
+ user,
616
+ items = [],
617
+ onLogout,
618
+ logoutLabel = "Sair",
619
+ renderLink = defaultRenderLink,
620
+ align = "end"
621
+ }) {
622
+ const label = initials(user);
623
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu2.Root, { children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
625
+ "button",
626
+ {
627
+ type: "button",
628
+ 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",
629
+ "aria-label": "Menu do usu\xE1rio",
630
+ "data-testid": "user-menu",
631
+ children: user?.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: user.avatarUrl, alt: user.name ?? user.email ?? "Avatar", className: "h-full w-full object-cover" }) : label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: label }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react2.User, { className: "h-4 w-4" })
632
+ }
633
+ ) }),
634
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenu2.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
635
+ DropdownMenu2.Content,
636
+ {
637
+ align,
638
+ sideOffset: 6,
639
+ 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",
640
+ children: [
641
+ (user?.name || user?.email) && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
642
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "px-2 py-1.5", children: [
643
+ user.name && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "truncate text-sm font-medium", children: user.name }),
644
+ user.email && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: user.email })
645
+ ] }),
646
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenu2.Separator, { className: "-mx-1 my-1 h-px bg-border" })
647
+ ] }),
648
+ items.map(
649
+ (item) => item.href ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenu2.Item, { asChild: true, children: renderLink({ href: item.href, className: itemClass, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
650
+ item.icon,
651
+ item.label
652
+ ] }) }) }, item.label) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu2.Item, { className: itemClass, onClick: item.onClick, children: [
653
+ item.icon,
654
+ item.label
655
+ ] }, item.label)
656
+ ),
657
+ onLogout && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
658
+ items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenu2.Separator, { className: "-mx-1 my-1 h-px bg-border" }),
659
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu2.Item, { className: cn(itemClass, "text-destructive focus:bg-destructive/10"), onClick: onLogout, children: [
660
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react2.LogOut, { className: "h-4 w-4" }),
661
+ logoutLabel
662
+ ] })
663
+ ] })
664
+ ]
665
+ }
666
+ ) })
667
+ ] });
668
+ }
669
+
670
+ // src/components/app-shell.tsx
671
+ var import_jsx_runtime21 = require("react/jsx-runtime");
672
+ function AppShell({
673
+ brand,
674
+ brandCollapsed,
675
+ navItems,
676
+ activePath,
677
+ isActive,
678
+ isAdmin = false,
679
+ user,
680
+ userMenuItems,
681
+ onLogout,
682
+ renderLink = defaultRenderLink,
683
+ headerActions,
684
+ collapsible = true,
685
+ defaultCollapsed = false,
686
+ children
687
+ }) {
688
+ const [collapsed, setCollapsed] = (0, import_react3.useState)(defaultCollapsed);
689
+ const [mobileOpen, setMobileOpen] = (0, import_react3.useState)(false);
690
+ const nav = (isCollapsed, onNavigate) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
691
+ SidebarNav,
692
+ {
693
+ items: navItems,
694
+ activePath,
695
+ isActive,
696
+ isAdmin,
697
+ isCollapsed,
698
+ renderLink,
699
+ onNavigate
700
+ }
701
+ );
702
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex h-screen overflow-hidden bg-background", children: [
703
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
704
+ "aside",
705
+ {
706
+ className: cn(
707
+ "hidden shrink-0 flex-col border-r bg-card transition-all duration-300 md:flex",
708
+ collapsed ? "w-16" : "w-60"
709
+ ),
710
+ children: [
711
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: collapsed ? brandCollapsed ?? brand : brand }),
712
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(collapsed) }),
713
+ collapsible && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "border-t p-2", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
714
+ "button",
715
+ {
716
+ type: "button",
717
+ onClick: () => setCollapsed((v) => !v),
718
+ 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",
719
+ "aria-label": collapsed ? "Expandir menu" : "Recolher menu",
720
+ children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react3.ChevronRight, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react3.ChevronLeft, { className: "h-4 w-4" })
721
+ }
722
+ ) })
723
+ ]
724
+ }
725
+ ),
726
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
727
+ "div",
728
+ {
729
+ className: cn(
730
+ "fixed inset-0 z-50 transition-opacity duration-300 md:hidden",
731
+ mobileOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
732
+ ),
733
+ onClick: () => setMobileOpen(false),
734
+ children: [
735
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute inset-0 bg-black/50" }),
736
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
737
+ "div",
738
+ {
739
+ className: cn(
740
+ "absolute left-0 top-0 flex h-full w-64 flex-col border-r bg-card transition-transform duration-300",
741
+ mobileOpen ? "translate-x-0" : "-translate-x-full"
742
+ ),
743
+ onClick: (e) => e.stopPropagation(),
744
+ children: [
745
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex h-14 shrink-0 items-center border-b px-4", children: brand }),
746
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 overflow-y-auto px-2 py-4", children: nav(false, () => setMobileOpen(false)) })
747
+ ]
748
+ }
749
+ )
750
+ ]
751
+ }
752
+ ),
753
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b bg-background px-4", children: [
755
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
756
+ "button",
757
+ {
758
+ type: "button",
759
+ onClick: () => setMobileOpen(true),
760
+ 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",
761
+ "aria-label": "Abrir menu",
762
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react3.Menu, { className: "h-4 w-4" })
763
+ }
764
+ ),
765
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ml-auto flex items-center gap-2", children: [
766
+ headerActions,
767
+ (user || onLogout) && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(UserMenu, { user, items: userMenuItems, onLogout, renderLink })
768
+ ] })
769
+ ] }),
770
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("main", { className: "flex-1 overflow-y-auto", children })
771
+ ] })
772
+ ] });
773
+ }
774
+
550
775
  // src/lib/api-error.ts
551
776
  function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
552
777
  const detail = err?.body?.detail || err?.message;
@@ -557,20 +782,20 @@ function extractApiError(err, fallbackMessage = "Ocorreu um erro inesperado.") {
557
782
  }
558
783
 
559
784
  // src/hooks/use-disclosure.ts
560
- var import_react2 = require("react");
785
+ var import_react4 = require("react");
561
786
  function useDisclosure(initial = false) {
562
- const [open, setOpen] = (0, import_react2.useState)(initial);
563
- const onOpen = (0, import_react2.useCallback)(() => setOpen(true), []);
564
- const onClose = (0, import_react2.useCallback)(() => setOpen(false), []);
565
- const onToggle = (0, import_react2.useCallback)(() => setOpen((v) => !v), []);
787
+ const [open, setOpen] = (0, import_react4.useState)(initial);
788
+ const onOpen = (0, import_react4.useCallback)(() => setOpen(true), []);
789
+ const onClose = (0, import_react4.useCallback)(() => setOpen(false), []);
790
+ const onToggle = (0, import_react4.useCallback)(() => setOpen((v) => !v), []);
566
791
  return { open, onOpen, onClose, onToggle, setOpen };
567
792
  }
568
793
 
569
794
  // src/hooks/use-toast.ts
570
795
  var import_sonner2 = require("sonner");
571
- var import_react3 = require("react");
796
+ var import_react5 = require("react");
572
797
  function useCustomToast() {
573
- const showToast = (0, import_react3.useCallback)(
798
+ const showToast = (0, import_react5.useCallback)(
574
799
  (title, description, status = "success") => {
575
800
  switch (status) {
576
801
  case "success":
@@ -593,6 +818,7 @@ function useCustomToast() {
593
818
  }
594
819
  // Annotate the CommonJS export names for ESM import in node:
595
820
  0 && (module.exports = {
821
+ AppShell,
596
822
  AuthCard,
597
823
  ConfirmDialog,
598
824
  DataTableWrapper,
@@ -605,12 +831,15 @@ function useCustomToast() {
605
831
  Pagination,
606
832
  ResponsiveDataView,
607
833
  SearchInput,
834
+ SidebarNav,
608
835
  StatCard,
609
836
  StatusDot,
610
837
  TableSkeleton,
611
838
  ThemeProvider,
612
839
  Toaster,
840
+ UserMenu,
613
841
  cn,
842
+ defaultRenderLink,
614
843
  extractApiError,
615
844
  toast,
616
845
  useCustomToast,