@motor-hero/ui-kit 0.8.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.
- package/dist/components/app-shell.d.ts +22 -0
- package/dist/components/app-shell.d.ts.map +1 -0
- package/dist/components/sidebar-nav.d.ts +19 -0
- package/dist/components/sidebar-nav.d.ts.map +1 -0
- package/dist/components/types.d.ts +12 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/user-menu.d.ts +23 -0
- package/dist/components/user-menu.d.ts.map +1 -0
- package/dist/index.cjs +236 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +227 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/app-shell.tsx +127 -0
- package/src/components/sidebar-nav.tsx +66 -0
- package/src/components/types.tsx +16 -0
- package/src/components/user-menu.tsx +116 -0
- package/src/index.ts +10 -0
|
@@ -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
|
|
785
|
+
var import_react4 = require("react");
|
|
561
786
|
function useDisclosure(initial = false) {
|
|
562
|
-
const [open, setOpen] = (0,
|
|
563
|
-
const onOpen = (0,
|
|
564
|
-
const onClose = (0,
|
|
565
|
-
const onToggle = (0,
|
|
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
|
|
796
|
+
var import_react5 = require("react");
|
|
572
797
|
function useCustomToast() {
|
|
573
|
-
const showToast = (0,
|
|
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,
|