@pactor-app/ui 1.1.0 → 1.3.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,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,19 +17,28 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/layout/index.ts
21
31
  var layout_exports = {};
22
32
  __export(layout_exports, {
23
- ShadcnAdminLayout: () => ShadcnAdminLayout,
24
- ShadcnBlankLayout: () => ShadcnBlankLayout,
25
- ShadcnLandingLayout: () => ShadcnLandingLayout,
26
- ShadcnLoginLayout: () => ShadcnLoginLayout,
33
+ AdminLayout: () => AdminLayout,
34
+ BlankLayout: () => BlankLayout,
35
+ ChatLayout: () => ChatLayout,
36
+ LandingLayout: () => LandingLayout,
37
+ LoginLayout: () => LoginLayout,
27
38
  collectDefaultOpenKeys: () => collectDefaultOpenKeys,
28
- createShadcnLayoutRegistry: () => createShadcnLayoutRegistry,
39
+ createLayoutRegistry: () => createLayoutRegistry,
29
40
  findMenuChain: () => findMenuChain,
30
- registerShadcnLayouts: () => registerShadcnLayouts,
41
+ registerBuiltinLayouts: () => registerBuiltinLayouts,
31
42
  resolveLayout: () => resolveLayout
32
43
  });
33
44
  module.exports = __toCommonJS(layout_exports);
@@ -76,7 +87,7 @@ function collectDefaultOpenKeys(registry, activeMenuId) {
76
87
  return keys;
77
88
  }
78
89
 
79
- // src/layout/admin/ShadcnAdminLayout.tsx
90
+ // src/layout/admin/AdminLayout.tsx
80
91
  var import_permission = require("@pactor-app/permission");
81
92
  var import_router = require("@pactor-app/router");
82
93
  var import_runtime = require("@pactor-app/runtime");
@@ -202,7 +213,7 @@ function PopoverContent({
202
213
  {
203
214
  "data-slot": "popover-content",
204
215
  className: cn(
205
- "z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
216
+ "z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md shadow-(color:--shadow-color) outline-none duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
206
217
  className
207
218
  ),
208
219
  ...props
@@ -397,7 +408,7 @@ function useBreakpointBelow(breakpoint) {
397
408
  return breakpoint !== void 0 && matches;
398
409
  }
399
410
 
400
- // src/layout/admin/ShadcnAdminLayout.tsx
411
+ // src/layout/admin/AdminLayout.tsx
401
412
  var import_jsx_runtime4 = require("react/jsx-runtime");
402
413
  function buildVisibleMenuTree(registry, permissionChecker) {
403
414
  const tree = registry.tree();
@@ -413,7 +424,7 @@ function navigateMenuItem(menu, bridge) {
413
424
  }
414
425
  bridge.push(menu.path);
415
426
  }
416
- var menuItemClass = "flex w-full cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50";
427
+ var menuItemClass = "flex w-full cursor-pointer items-center gap-2 rounded-md px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-(--menu-hover-background) hover:text-(--menu-hover-foreground) disabled:pointer-events-none disabled:opacity-50";
417
428
  function CollapsedGroupFlyout({
418
429
  menu,
419
430
  registry,
@@ -519,7 +530,7 @@ function MenuTree({
519
530
  className: cn(
520
531
  menuItemClass,
521
532
  "mx-auto size-10 justify-center px-0 font-semibold",
522
- menu.id === activeMenuId && "bg-accent font-semibold text-accent-foreground"
533
+ menu.id === activeMenuId && "bg-(--menu-active-background) font-semibold text-(--menu-active-foreground)"
523
534
  ),
524
535
  disabled: menu.disabled,
525
536
  title: menu.title,
@@ -582,7 +593,7 @@ function MenuTree({
582
593
  "data-active": menu.id === activeMenuId || void 0,
583
594
  className: cn(
584
595
  menuItemClass,
585
- menu.id === activeMenuId && "bg-accent font-semibold text-accent-foreground"
596
+ menu.id === activeMenuId && "bg-(--menu-active-background) font-semibold text-(--menu-active-foreground)"
586
597
  ),
587
598
  disabled: menu.disabled,
588
599
  title: menu.title,
@@ -598,7 +609,7 @@ function MenuTree({
598
609
  }
599
610
  );
600
611
  }
601
- function ShadcnAdminLayout({
612
+ function AdminLayout({
602
613
  config = {},
603
614
  brand,
604
615
  registry,
@@ -688,7 +699,7 @@ function ShadcnAdminLayout({
688
699
  {
689
700
  "data-slot": "admin-header",
690
701
  className: cn(
691
- "flex h-14 items-center gap-4 border-b border-border bg-background px-6",
702
+ "flex h-14 items-center gap-4 border-b border-border bg-card px-6",
692
703
  fixedHeader && "sticky top-0 z-20"
693
704
  ),
694
705
  children: [
@@ -715,7 +726,7 @@ function ShadcnAdminLayout({
715
726
  className: cn(
716
727
  menuItemClass,
717
728
  "size-10 justify-center px-0 font-semibold",
718
- (menu.id === secondaryTopId || menu.id === activeTopId) && "bg-accent text-accent-foreground"
729
+ (menu.id === secondaryTopId || menu.id === activeTopId) && "bg-(--menu-active-background) text-(--menu-active-foreground)"
719
730
  ),
720
731
  disabled: menu.disabled,
721
732
  title: menu.title,
@@ -739,7 +750,7 @@ function ShadcnAdminLayout({
739
750
  "data-slot": "admin-sidebar",
740
751
  "data-collapsed": effectiveCollapsed || void 0,
741
752
  className: cn(
742
- "shrink-0 overflow-auto border-r border-border bg-background py-2",
753
+ "shrink-0 overflow-auto border-r border-border bg-sidebar py-2",
743
754
  effectiveCollapsed ? "w-16 px-1.5" : "w-52",
744
755
  fixedSider && (mode === "side-full" ? "sticky top-0 h-screen" : "sticky top-14 h-[calc(100vh-3.5rem)]")
745
756
  ),
@@ -786,7 +797,7 @@ function ShadcnAdminLayout({
786
797
  "data-slot": "admin-collapse-trigger",
787
798
  "aria-label": effectiveCollapsed ? t("pactor.layout.expandSidebar") : t("pactor.layout.collapseSidebar"),
788
799
  "aria-expanded": !effectiveCollapsed,
789
- className: "sticky bottom-0 flex w-full cursor-pointer items-center justify-center border-t border-border bg-background py-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
800
+ className: "sticky bottom-0 flex w-full cursor-pointer items-center justify-center border-t border-border bg-sidebar py-2 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
790
801
  onClick: () => setCollapsed((value) => !value),
791
802
  children: effectiveCollapsed ? "\xBB" : "\xAB"
792
803
  }
@@ -800,7 +811,7 @@ function ShadcnAdminLayout({
800
811
  {
801
812
  "data-slot": "admin-tabs",
802
813
  role: "tablist",
803
- className: "flex items-center gap-1 border-b border-border bg-background px-4 pt-2",
814
+ className: "flex items-center gap-1 border-b border-border bg-card px-4 pt-2",
804
815
  children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
805
816
  "div",
806
817
  {
@@ -809,7 +820,7 @@ function ShadcnAdminLayout({
809
820
  role: "presentation",
810
821
  className: cn(
811
822
  "inline-flex items-center gap-1 rounded-t-md border border-b-0 border-border px-3 py-1.5 text-sm",
812
- tab.key === currentPath ? "bg-background font-medium text-foreground" : "bg-muted text-muted-foreground"
823
+ tab.key === currentPath ? "bg-card font-medium text-foreground" : "bg-muted text-muted-foreground"
813
824
  ),
814
825
  children: [
815
826
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -905,9 +916,9 @@ function ShadcnAdminLayout({
905
916
  );
906
917
  }
907
918
 
908
- // src/layout/basic/ShadcnBlankLayout.tsx
919
+ // src/layout/basic/BlankLayout.tsx
909
920
  var import_jsx_runtime5 = require("react/jsx-runtime");
910
- function ShadcnBlankLayout({ children }) {
921
+ function BlankLayout({ children }) {
911
922
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
912
923
  "div",
913
924
  {
@@ -918,15 +929,1023 @@ function ShadcnBlankLayout({ children }) {
918
929
  );
919
930
  }
920
931
 
921
- // src/ui/card.tsx
932
+ // src/layout/chat/ChatLayout.tsx
933
+ var import_permission2 = require("@pactor-app/permission");
934
+ var import_react5 = require("react");
935
+
936
+ // src/ui/tooltip.tsx
937
+ var import_tooltip = require("@base-ui/react/tooltip");
922
938
  var import_jsx_runtime6 = require("react/jsx-runtime");
923
- function Card({ className, ...props }) {
939
+ function TooltipProvider({
940
+ delay = 0,
941
+ ...props
942
+ }) {
924
943
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
944
+ import_tooltip.Tooltip.Provider,
945
+ {
946
+ "data-slot": "tooltip-provider",
947
+ delay,
948
+ ...props
949
+ }
950
+ );
951
+ }
952
+ function Tooltip({
953
+ ...props
954
+ }) {
955
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Root, { "data-slot": "tooltip", ...props }) });
956
+ }
957
+ function TooltipTrigger({
958
+ ...props
959
+ }) {
960
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
961
+ }
962
+ function TooltipContent({
963
+ className,
964
+ side = "top",
965
+ sideOffset = 4,
966
+ align = "center",
967
+ children,
968
+ ...props
969
+ }) {
970
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
971
+ import_tooltip.Tooltip.Positioner,
972
+ {
973
+ align,
974
+ side,
975
+ sideOffset,
976
+ className: "isolate z-50",
977
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
978
+ import_tooltip.Tooltip.Popup,
979
+ {
980
+ "data-slot": "tooltip-content",
981
+ className: cn(
982
+ "z-50 w-fit origin-(--transform-origin) rounded-md bg-primary px-3 py-1.5 text-xs text-balance text-primary-foreground duration-200 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
983
+ className
984
+ ),
985
+ ...props,
986
+ children: [
987
+ children,
988
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Arrow, { className: "z-50 size-2.5 rotate-45 rounded-[2px] bg-primary fill-primary data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1" })
989
+ ]
990
+ }
991
+ )
992
+ }
993
+ ) });
994
+ }
995
+
996
+ // src/components/components/Sidebar/rail-tooltip.tsx
997
+ var import_jsx_runtime7 = require("react/jsx-runtime");
998
+ function RailTooltip({
999
+ label,
1000
+ children
1001
+ }) {
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Tooltip, { children: [
1003
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TooltipTrigger, { render: children }),
1004
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TooltipContent, { side: "right", sideOffset: 8, children: label })
1005
+ ] });
1006
+ }
1007
+
1008
+ // src/components/components/Sidebar/index.tsx
1009
+ var import_runtime2 = require("@pactor-app/runtime");
1010
+ var import_react4 = require("react");
1011
+
1012
+ // src/ui/sidebar.tsx
1013
+ var React = __toESM(require("react"), 1);
1014
+ var import_class_variance_authority2 = require("class-variance-authority");
1015
+ var import_lucide_react4 = require("lucide-react");
1016
+
1017
+ // src/hooks/use-mobile.ts
1018
+ var import_react3 = require("react");
1019
+ var MOBILE_MEDIA_QUERY = "(max-width: 767px)";
1020
+ function useIsMobile() {
1021
+ const [isMobile, setIsMobile] = (0, import_react3.useState)(
1022
+ () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(MOBILE_MEDIA_QUERY).matches
1023
+ );
1024
+ (0, import_react3.useEffect)(() => {
1025
+ if (typeof window.matchMedia !== "function") {
1026
+ return;
1027
+ }
1028
+ const media = window.matchMedia(MOBILE_MEDIA_QUERY);
1029
+ const onChange = (event) => {
1030
+ setIsMobile(event.matches);
1031
+ };
1032
+ setIsMobile(media.matches);
1033
+ media.addEventListener("change", onChange);
1034
+ return () => media.removeEventListener("change", onChange);
1035
+ }, []);
1036
+ return isMobile;
1037
+ }
1038
+
1039
+ // src/ui/sheet.tsx
1040
+ var import_dialog = require("@base-ui/react/dialog");
1041
+ var import_lucide_react3 = require("lucide-react");
1042
+ var import_class_variance_authority = require("class-variance-authority");
1043
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1044
+ function Sheet({
1045
+ ...props
1046
+ }) {
1047
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_dialog.Dialog.Root, { "data-slot": "sheet", ...props });
1048
+ }
1049
+ function SheetPortal({
1050
+ ...props
1051
+ }) {
1052
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_dialog.Dialog.Portal, { "data-slot": "sheet-portal", ...props });
1053
+ }
1054
+ function SheetOverlay({
1055
+ className,
1056
+ ...props
1057
+ }) {
1058
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1059
+ import_dialog.Dialog.Backdrop,
1060
+ {
1061
+ "data-slot": "sheet-overlay",
1062
+ className: cn(
1063
+ "fixed inset-0 z-50 bg-(--overlay-background) data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
1064
+ className
1065
+ ),
1066
+ ...props
1067
+ }
1068
+ );
1069
+ }
1070
+ var sheetVariants = (0, import_class_variance_authority.cva)(
1071
+ "fixed z-50 flex flex-col gap-4 border-border bg-popover shadow-lg shadow-(color:--shadow-color) transition ease-in-out data-open:animate-in data-open:duration-300 data-closed:animate-out data-closed:duration-200",
1072
+ {
1073
+ variants: {
1074
+ side: {
1075
+ right: "inset-y-0 right-0 h-full w-3/4 border-l data-open:slide-in-from-right data-closed:slide-out-to-right sm:max-w-sm",
1076
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-open:slide-in-from-left data-closed:slide-out-to-left sm:max-w-sm",
1077
+ top: "inset-x-0 top-0 border-b data-open:slide-in-from-top data-closed:slide-out-to-top",
1078
+ bottom: "inset-x-0 bottom-0 border-t data-open:slide-in-from-bottom data-closed:slide-out-to-bottom"
1079
+ }
1080
+ },
1081
+ defaultVariants: {
1082
+ side: "right"
1083
+ }
1084
+ }
1085
+ );
1086
+ function SheetContent({
1087
+ className,
1088
+ children,
1089
+ side = "right",
1090
+ ...props
1091
+ }) {
1092
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(SheetPortal, { "data-slot": "sheet-portal", children: [
1093
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SheetOverlay, {}),
1094
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1095
+ import_dialog.Dialog.Popup,
1096
+ {
1097
+ "data-slot": "sheet-content",
1098
+ className: cn(sheetVariants({ side }), className),
1099
+ ...props,
1100
+ children: [
1101
+ children,
1102
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1103
+ import_dialog.Dialog.Close,
1104
+ {
1105
+ "data-slot": "sheet-close",
1106
+ render: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1107
+ "button",
1108
+ {
1109
+ type: "button",
1110
+ className: "absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-none disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
1111
+ }
1112
+ ),
1113
+ children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react3.XIcon, {}),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "sr-only", children: "Close" })
1116
+ ]
1117
+ }
1118
+ )
1119
+ ]
1120
+ }
1121
+ )
1122
+ ] });
1123
+ }
1124
+ function SheetHeader({ className, ...props }) {
1125
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1126
+ "div",
1127
+ {
1128
+ "data-slot": "sheet-header",
1129
+ className: cn("flex flex-col gap-1.5 p-4", className),
1130
+ ...props
1131
+ }
1132
+ );
1133
+ }
1134
+ function SheetTitle({
1135
+ className,
1136
+ ...props
1137
+ }) {
1138
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1139
+ import_dialog.Dialog.Title,
1140
+ {
1141
+ "data-slot": "sheet-title",
1142
+ className: cn("font-semibold text-foreground", className),
1143
+ ...props
1144
+ }
1145
+ );
1146
+ }
1147
+ function SheetDescription({
1148
+ className,
1149
+ ...props
1150
+ }) {
1151
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1152
+ import_dialog.Dialog.Description,
1153
+ {
1154
+ "data-slot": "sheet-description",
1155
+ className: cn("text-sm text-muted-foreground", className),
1156
+ ...props
1157
+ }
1158
+ );
1159
+ }
1160
+
1161
+ // src/ui/sidebar.tsx
1162
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1163
+ var SIDEBAR_COOKIE_NAME = "sidebar_state";
1164
+ var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
1165
+ var SIDEBAR_WIDTH = "16rem";
1166
+ var SIDEBAR_WIDTH_MOBILE = "18rem";
1167
+ var SIDEBAR_WIDTH_ICON = "3rem";
1168
+ var SIDEBAR_KEYBOARD_SHORTCUT = "b";
1169
+ var SidebarContext = React.createContext(null);
1170
+ function useSidebar() {
1171
+ const context = React.useContext(SidebarContext);
1172
+ if (!context) {
1173
+ throw new Error("useSidebar must be used within a SidebarProvider.");
1174
+ }
1175
+ return context;
1176
+ }
1177
+ function SidebarProvider({
1178
+ defaultOpen = true,
1179
+ open: openProp,
1180
+ onOpenChange: setOpenProp,
1181
+ className,
1182
+ style,
1183
+ children,
1184
+ ...props
1185
+ }) {
1186
+ const isMobile = useIsMobile();
1187
+ const [openMobile, setOpenMobile] = React.useState(false);
1188
+ const [_open, _setOpen] = React.useState(defaultOpen);
1189
+ const open = openProp ?? _open;
1190
+ const setOpen = React.useCallback(
1191
+ (value) => {
1192
+ const openState = typeof value === "function" ? value(open) : value;
1193
+ if (setOpenProp) {
1194
+ setOpenProp(openState);
1195
+ } else {
1196
+ _setOpen(openState);
1197
+ }
1198
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
1199
+ },
1200
+ [setOpenProp, open]
1201
+ );
1202
+ const toggleSidebar = React.useCallback(() => {
1203
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
1204
+ }, [isMobile, setOpen, setOpenMobile]);
1205
+ React.useEffect(() => {
1206
+ const handleKeyDown = (event) => {
1207
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
1208
+ event.preventDefault();
1209
+ toggleSidebar();
1210
+ }
1211
+ };
1212
+ window.addEventListener("keydown", handleKeyDown);
1213
+ return () => window.removeEventListener("keydown", handleKeyDown);
1214
+ }, [toggleSidebar]);
1215
+ const state = open ? "expanded" : "collapsed";
1216
+ const contextValue = React.useMemo(
1217
+ () => ({
1218
+ state,
1219
+ open,
1220
+ setOpen,
1221
+ isMobile,
1222
+ openMobile,
1223
+ setOpenMobile,
1224
+ toggleSidebar
1225
+ }),
1226
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
1227
+ );
1228
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipProvider, { delay: 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1229
+ "div",
1230
+ {
1231
+ "data-slot": "sidebar-wrapper",
1232
+ style: {
1233
+ "--sidebar-width": SIDEBAR_WIDTH,
1234
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
1235
+ ...style
1236
+ },
1237
+ className: cn(
1238
+ "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar",
1239
+ className
1240
+ ),
1241
+ ...props,
1242
+ children
1243
+ }
1244
+ ) }) });
1245
+ }
1246
+ function SidebarRoot({
1247
+ side = "left",
1248
+ variant = "sidebar",
1249
+ collapsible = "offcanvas",
1250
+ className,
1251
+ children,
1252
+ ...props
1253
+ }) {
1254
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
1255
+ if (collapsible === "none") {
1256
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1257
+ "div",
1258
+ {
1259
+ "data-slot": "sidebar",
1260
+ className: cn(
1261
+ "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
1262
+ className
1263
+ ),
1264
+ ...props,
1265
+ children
1266
+ }
1267
+ );
1268
+ }
1269
+ if (isMobile) {
1270
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1271
+ SheetContent,
1272
+ {
1273
+ "data-sidebar": "sidebar",
1274
+ "data-slot": "sidebar",
1275
+ "data-mobile": "true",
1276
+ className: "w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
1277
+ style: {
1278
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE
1279
+ },
1280
+ side,
1281
+ children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(SheetHeader, { className: "sr-only", children: [
1283
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SheetTitle, { children: "Sidebar" }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SheetDescription, { children: "Displays the mobile sidebar." })
1285
+ ] }),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex h-full w-full flex-col", children })
1287
+ ]
1288
+ }
1289
+ ) });
1290
+ }
1291
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1292
+ "div",
1293
+ {
1294
+ className: "group peer hidden text-sidebar-foreground md:block",
1295
+ "data-state": state,
1296
+ "data-collapsible": state === "collapsed" ? collapsible : "",
1297
+ "data-variant": variant,
1298
+ "data-side": side,
1299
+ "data-slot": "sidebar",
1300
+ children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1302
+ "div",
1303
+ {
1304
+ "data-slot": "sidebar-gap",
1305
+ className: cn(
1306
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
1307
+ "group-data-[collapsible=offcanvas]:w-0",
1308
+ "group-data-[side=right]:rotate-180",
1309
+ variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
1310
+ )
1311
+ }
1312
+ ),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1314
+ "div",
1315
+ {
1316
+ "data-slot": "sidebar-container",
1317
+ className: cn(
1318
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
1319
+ side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
1320
+ variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
1321
+ className
1322
+ ),
1323
+ ...props,
1324
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1325
+ "div",
1326
+ {
1327
+ "data-sidebar": "sidebar",
1328
+ "data-slot": "sidebar-inner",
1329
+ className: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm",
1330
+ children
1331
+ }
1332
+ )
1333
+ }
1334
+ )
1335
+ ]
1336
+ }
1337
+ );
1338
+ }
1339
+ function SidebarInset({ className, ...props }) {
1340
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1341
+ "main",
1342
+ {
1343
+ "data-slot": "sidebar-inset",
1344
+ className: cn(
1345
+ "relative flex w-full flex-1 flex-col bg-background",
1346
+ "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
1347
+ className
1348
+ ),
1349
+ ...props
1350
+ }
1351
+ );
1352
+ }
1353
+ function SidebarHeader({ className, ...props }) {
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1355
+ "div",
1356
+ {
1357
+ "data-slot": "sidebar-header",
1358
+ "data-sidebar": "header",
1359
+ className: cn("flex flex-col gap-2 p-2", className),
1360
+ ...props
1361
+ }
1362
+ );
1363
+ }
1364
+ function SidebarFooter({ className, ...props }) {
1365
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1366
+ "div",
1367
+ {
1368
+ "data-slot": "sidebar-footer",
1369
+ "data-sidebar": "footer",
1370
+ className: cn("flex flex-col gap-2 p-2", className),
1371
+ ...props
1372
+ }
1373
+ );
1374
+ }
1375
+ function SidebarContent({ className, ...props }) {
1376
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1377
+ "div",
1378
+ {
1379
+ "data-slot": "sidebar-content",
1380
+ "data-sidebar": "content",
1381
+ className: cn(
1382
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
1383
+ className
1384
+ ),
1385
+ ...props
1386
+ }
1387
+ );
1388
+ }
1389
+ function renderAsChild(children, dataSlot, className, rest) {
1390
+ if (!React.isValidElement(children)) {
1391
+ return null;
1392
+ }
1393
+ return React.cloneElement(children, {
1394
+ "data-slot": dataSlot,
1395
+ className: cn(
1396
+ className,
1397
+ children.props.className
1398
+ ),
1399
+ ...rest
1400
+ });
1401
+ }
1402
+ function SidebarMenu({ className, ...props }) {
1403
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1404
+ "ul",
1405
+ {
1406
+ "data-slot": "sidebar-menu",
1407
+ "data-sidebar": "menu",
1408
+ className: cn("flex w-full min-w-0 flex-col gap-1", className),
1409
+ ...props
1410
+ }
1411
+ );
1412
+ }
1413
+ function SidebarMenuItem({ className, ...props }) {
1414
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1415
+ "li",
1416
+ {
1417
+ "data-slot": "sidebar-menu-item",
1418
+ "data-sidebar": "menu-item",
1419
+ className: cn("group/menu-item relative", className),
1420
+ ...props
1421
+ }
1422
+ );
1423
+ }
1424
+ var sidebarMenuButtonVariants = (0, import_class_variance_authority2.cva)(
1425
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
1426
+ {
1427
+ variants: {
1428
+ variant: {
1429
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
1430
+ outline: "bg-sidebar shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]"
1431
+ },
1432
+ size: {
1433
+ default: "h-8 text-sm",
1434
+ sm: "h-7 text-xs",
1435
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
1436
+ }
1437
+ },
1438
+ defaultVariants: {
1439
+ variant: "default",
1440
+ size: "default"
1441
+ }
1442
+ }
1443
+ );
1444
+ function SidebarMenuButton({
1445
+ asChild = false,
1446
+ isActive = false,
1447
+ variant = "default",
1448
+ size = "default",
1449
+ tooltip,
1450
+ className,
1451
+ children,
1452
+ ...props
1453
+ }) {
1454
+ const { isMobile, state } = useSidebar();
1455
+ const cls = cn(sidebarMenuButtonVariants({ variant, size }), className);
1456
+ const button = asChild ? renderAsChild(children, "sidebar-menu-button", cls, {
1457
+ "data-sidebar": "menu-button",
1458
+ "data-size": size,
1459
+ "data-active": isActive,
1460
+ ...props
1461
+ }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1462
+ "button",
1463
+ {
1464
+ "data-slot": "sidebar-menu-button",
1465
+ "data-sidebar": "menu-button",
1466
+ "data-size": size,
1467
+ "data-active": isActive,
1468
+ className: cls,
1469
+ ...props,
1470
+ children
1471
+ }
1472
+ );
1473
+ if (!tooltip) {
1474
+ return button;
1475
+ }
1476
+ if (typeof tooltip === "string") {
1477
+ tooltip = {
1478
+ children: tooltip
1479
+ };
1480
+ }
1481
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { render: button }),
1483
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1484
+ TooltipContent,
1485
+ {
1486
+ side: "right",
1487
+ align: "center",
1488
+ hidden: state !== "collapsed" || isMobile,
1489
+ ...tooltip
1490
+ }
1491
+ )
1492
+ ] });
1493
+ }
1494
+
1495
+ // src/components/components/Sidebar/index.tsx
1496
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1497
+ function useSidebarDrawer() {
1498
+ try {
1499
+ const ctx = useSidebar();
1500
+ return {
1501
+ close: () => ctx.setOpenMobile(false),
1502
+ collapsed: ctx.state === "collapsed"
1503
+ };
1504
+ } catch {
1505
+ return null;
1506
+ }
1507
+ }
1508
+ function useOptionalRenderer() {
1509
+ try {
1510
+ return (0, import_runtime2.useRenderer)();
1511
+ } catch {
1512
+ return null;
1513
+ }
1514
+ }
1515
+ function SidebarContentSlot({ content }) {
1516
+ const renderer = useOptionalRenderer();
1517
+ if (renderer !== null && typeof content === "object" && content !== null && !("$$typeof" in content) && "type" in content) {
1518
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderer.renderChildren([content]) });
1519
+ }
1520
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: content });
1521
+ }
1522
+ function isBrandObject(brand) {
1523
+ return typeof brand === "object" && brand !== null && !("$$typeof" in brand) && "title" in brand;
1524
+ }
1525
+ function BrandNode({ brand, collapsed }) {
1526
+ if (brand === void 0 || brand === null) {
1527
+ return null;
1528
+ }
1529
+ if (isBrandObject(brand)) {
1530
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1531
+ brand.logo ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1532
+ "img",
1533
+ {
1534
+ "data-slot": "sidebar-brand-logo",
1535
+ src: brand.logo,
1536
+ alt: brand.title,
1537
+ className: "size-6 shrink-0"
1538
+ }
1539
+ ) : null,
1540
+ collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate text-sm font-semibold", children: brand.title })
1541
+ ] });
1542
+ }
1543
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: brand });
1544
+ }
1545
+ function SidebarNavItems({ items }) {
1546
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarMenu, { children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarNavEntry, { item, depth: 0 }, item.href ?? item.label ?? index)) });
1547
+ }
1548
+ function SidebarNavEntry({ item, depth }) {
1549
+ const iconNode = item.icon ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: item.icon, size: "sm" }) : null;
1550
+ const labelNode = item.label;
1551
+ const button = item.href ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarMenuButton, { asChild: true, tooltip: item.label, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("a", { href: item.href, children: [
1552
+ iconNode,
1553
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: labelNode })
1554
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SidebarMenuButton, { tooltip: item.label, children: [
1555
+ iconNode,
1556
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: labelNode })
1557
+ ] });
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SidebarMenuItem, { children: [
1559
+ button,
1560
+ item.children && item.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: cn("ml-4"), children: item.children.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1561
+ SidebarNavEntry,
1562
+ {
1563
+ item: child,
1564
+ depth: depth + 1
1565
+ },
1566
+ child.href ?? child.label ?? index
1567
+ )) })
1568
+ ] });
1569
+ }
1570
+ function Sidebar({
1571
+ brand,
1572
+ items = [],
1573
+ content,
1574
+ sidebarFooter,
1575
+ collapsible,
1576
+ onCollapse,
1577
+ locationKey,
1578
+ drawer = true,
1579
+ className,
1580
+ style,
1581
+ children
1582
+ }) {
1583
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1584
+ SidebarProvider,
1585
+ {
1586
+ defaultOpen: true,
1587
+ className,
1588
+ style,
1589
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1590
+ SidebarInner,
1591
+ {
1592
+ brand,
1593
+ items,
1594
+ content,
1595
+ sidebarFooter,
1596
+ collapsible,
1597
+ onCollapse,
1598
+ locationKey,
1599
+ drawer,
1600
+ children
1601
+ }
1602
+ )
1603
+ }
1604
+ );
1605
+ }
1606
+ function SidebarInner({
1607
+ brand,
1608
+ items = [],
1609
+ content,
1610
+ sidebarFooter,
1611
+ collapsible,
1612
+ onCollapse,
1613
+ locationKey,
1614
+ drawer = true,
1615
+ children
1616
+ }) {
1617
+ const { t } = (0, import_runtime2.useI18n)();
1618
+ const isMobile = useIsMobile();
1619
+ const { state, setOpenMobile, toggleSidebar } = useSidebar();
1620
+ const collapsed = state === "collapsed";
1621
+ const prevCollapsed = (0, import_react4.useRef)(collapsed);
1622
+ (0, import_react4.useEffect)(() => {
1623
+ if (prevCollapsed.current !== collapsed) {
1624
+ prevCollapsed.current = collapsed;
1625
+ onCollapse?.(collapsed);
1626
+ }
1627
+ }, [collapsed, onCollapse]);
1628
+ (0, import_react4.useEffect)(() => {
1629
+ if (locationKey !== void 0) {
1630
+ setOpenMobile(false);
1631
+ }
1632
+ }, [locationKey, setOpenMobile]);
1633
+ const collapsedEffective = collapsible === true && collapsed && !isMobile;
1634
+ const brandNode = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BrandNode, { brand, collapsed: collapsedEffective });
1635
+ const sidebarContent = content !== void 0 && content !== null ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarContentSlot, { content }) : items.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarNavItems, { items }) : null;
1636
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1638
+ SidebarRoot,
1639
+ {
1640
+ collapsible: collapsible ? "icon" : "offcanvas",
1641
+ children: [
1642
+ (brand !== void 0 || collapsible) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1643
+ "div",
1644
+ {
1645
+ "data-slot": "sidebar-brand",
1646
+ className: cn(
1647
+ "flex h-14 shrink-0 items-center gap-2 px-2",
1648
+ collapsedEffective && "justify-center px-0"
1649
+ ),
1650
+ children: [
1651
+ collapsedEffective ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: brandNode }),
1652
+ collapsible && !isMobile && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1653
+ "button",
1654
+ {
1655
+ type: "button",
1656
+ "data-slot": "sidebar-collapse-trigger",
1657
+ "aria-label": collapsedEffective ? t("pactor.layout.expandSidebar") : t("pactor.layout.collapseSidebar"),
1658
+ "aria-expanded": !collapsedEffective,
1659
+ className: "flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-sidebar-foreground/60 transition-colors hover:bg-sidebar-accent hover:text-sidebar-foreground",
1660
+ onClick: toggleSidebar,
1661
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: collapsedEffective ? "chevron-right" : "chevron-left", size: 16 })
1662
+ }
1663
+ )
1664
+ ]
1665
+ }
1666
+ ) }),
1667
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarContent, { children: sidebarContent }),
1668
+ sidebarFooter !== void 0 && sidebarFooter !== null && !collapsedEffective && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarFooter, { children: sidebarFooter })
1669
+ ]
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SidebarInset, { children: [
1673
+ drawer && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1674
+ "div",
1675
+ {
1676
+ "data-slot": "sidebar-topbar",
1677
+ className: "flex h-14 items-center gap-2 border-b border-sidebar-border bg-sidebar px-3 md:hidden",
1678
+ children: [
1679
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1680
+ "button",
1681
+ {
1682
+ type: "button",
1683
+ "data-slot": "sidebar-menu-trigger",
1684
+ "aria-label": t("pactor.layout.openNavigation"),
1685
+ className: "flex size-8 items-center justify-center rounded-md text-sidebar-foreground/60 transition-colors hover:bg-sidebar-accent hover:text-sidebar-foreground",
1686
+ onClick: toggleSidebar,
1687
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "menu", size: 18 })
1688
+ }
1689
+ ),
1690
+ brandNode
1691
+ ]
1692
+ }
1693
+ ),
1694
+ children
1695
+ ] })
1696
+ ] });
1697
+ }
1698
+
1699
+ // src/components/components/Menu/index.tsx
1700
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1701
+ function Menu2({
1702
+ items = [],
1703
+ mode = "inline",
1704
+ selectedKey,
1705
+ onSelect,
1706
+ className,
1707
+ style
1708
+ }) {
1709
+ const drawer = useSidebarDrawer();
1710
+ const collapsed = mode === "inline" && drawer?.collapsed === true;
1711
+ let previousGroup;
1712
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1713
+ "nav",
1714
+ {
1715
+ "data-slot": "menu",
1716
+ "data-mode": mode,
1717
+ "data-collapsed": collapsed || void 0,
1718
+ className: cn(
1719
+ mode === "horizontal" ? "flex items-center gap-1" : "flex flex-col gap-0.5 p-2",
1720
+ className
1721
+ ),
1722
+ style,
1723
+ children: items.map((item) => {
1724
+ let groupLabel;
1725
+ if (!collapsed && mode === "inline" && item.group !== void 0 && item.group !== previousGroup) {
1726
+ groupLabel = item.group;
1727
+ }
1728
+ previousGroup = item.group;
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-slot": "menu-group-entry", children: [
1730
+ groupLabel !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1731
+ "div",
1732
+ {
1733
+ "data-slot": "menu-group",
1734
+ className: "px-3 pb-1 pt-3 text-xs font-medium text-muted-foreground first:pt-1",
1735
+ children: groupLabel
1736
+ }
1737
+ ),
1738
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1739
+ MenuEntry,
1740
+ {
1741
+ item,
1742
+ mode,
1743
+ depth: 0,
1744
+ selectedKey,
1745
+ onSelect,
1746
+ collapsed
1747
+ }
1748
+ )
1749
+ ] }, item.key);
1750
+ })
1751
+ }
1752
+ );
1753
+ }
1754
+ function MenuEntry({
1755
+ item,
1756
+ mode,
1757
+ depth,
1758
+ selectedKey,
1759
+ onSelect,
1760
+ collapsed = false
1761
+ }) {
1762
+ const selected = item.key === selectedKey;
1763
+ const button = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1764
+ "button",
1765
+ {
1766
+ type: "button",
1767
+ "data-slot": "menu-item",
1768
+ "aria-current": selected ? "page" : void 0,
1769
+ disabled: item.disabled,
1770
+ className: cn(
1771
+ "flex w-full items-center gap-2 rounded-md text-sm transition-colors",
1772
+ mode === "horizontal" ? "px-3 py-2" : "px-3 py-2 text-left",
1773
+ collapsed && "justify-center px-0",
1774
+ selected ? "bg-(--menu-active-background) font-medium text-(--menu-active-foreground)" : "cursor-pointer text-muted-foreground hover:bg-(--menu-hover-background)/50 hover:text-foreground",
1775
+ item.disabled && "cursor-not-allowed opacity-50 hover:bg-transparent hover:text-muted-foreground"
1776
+ ),
1777
+ style: mode === "inline" && depth > 0 && !collapsed ? { paddingLeft: 12 + depth * 16 } : void 0,
1778
+ onClick: () => {
1779
+ if (!item.disabled) {
1780
+ onSelect?.(item.key);
1781
+ }
1782
+ },
1783
+ children: [
1784
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: item.icon, size: "sm" }) : null,
1785
+ collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "min-w-0 flex-1 truncate text-left", children: item.label }),
1786
+ item.dot && !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "data-slot": "menu-item-dot", className: "size-1.5 shrink-0 rounded-full bg-destructive" }) : null,
1787
+ item.badge !== void 0 && !collapsed ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1788
+ "span",
1789
+ {
1790
+ "data-slot": "menu-item-badge",
1791
+ className: "shrink-0 rounded-full bg-muted px-1.5 py-0.5 text-xs text-muted-foreground",
1792
+ children: item.badge
1793
+ }
1794
+ ) : null
1795
+ ]
1796
+ }
1797
+ );
1798
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-slot": "menu-entry", "data-key": item.key, children: [
1799
+ collapsed ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RailTooltip, { label: item.label, children: button }) : button,
1800
+ item.children?.map((child) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1801
+ MenuEntry,
1802
+ {
1803
+ item: child,
1804
+ mode,
1805
+ depth: depth + 1,
1806
+ selectedKey,
1807
+ onSelect,
1808
+ collapsed
1809
+ },
1810
+ child.key
1811
+ ))
1812
+ ] });
1813
+ }
1814
+
1815
+ // src/layout/chat/ChatLayout.tsx
1816
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1817
+ function ChatLayout({
1818
+ brand,
1819
+ menu,
1820
+ registry,
1821
+ bridge,
1822
+ route: routeProp,
1823
+ permissionChecker,
1824
+ activeMenuKey,
1825
+ onMenuSelect,
1826
+ collapsible,
1827
+ sidebar,
1828
+ sidebarFooter,
1829
+ children
1830
+ }) {
1831
+ const registryMenus = (0, import_react5.useMemo)(() => {
1832
+ if (menu !== void 0 || registry === void 0) {
1833
+ return [];
1834
+ }
1835
+ const tree = registry.tree();
1836
+ const visible = permissionChecker !== void 0 ? (0, import_permission2.filterMenusByPermission)(tree, permissionChecker) : tree;
1837
+ return visible.flatMap((item) => menuItemToMenuData(item));
1838
+ }, [menu, registry, permissionChecker]);
1839
+ const menuItems = menu ?? registryMenus;
1840
+ const [bridgePath, setBridgePath] = (0, import_react5.useState)(
1841
+ () => bridge?.getLocation().pathname ?? "/"
1842
+ );
1843
+ (0, import_react5.useEffect)(() => {
1844
+ if (bridge === void 0) {
1845
+ return;
1846
+ }
1847
+ return bridge.subscribe((location) => {
1848
+ setBridgePath(location.pathname);
1849
+ });
1850
+ }, [bridge]);
1851
+ const activeKey = (0, import_react5.useMemo)(() => {
1852
+ if (activeMenuKey !== void 0) {
1853
+ return activeMenuKey;
1854
+ }
1855
+ const path = routeProp?.path ?? bridgePath;
1856
+ return menuItems.find((item) => item.path === path)?.key;
1857
+ }, [activeMenuKey, routeProp, bridgePath, menuItems]);
1858
+ const handleSelect = (key) => {
1859
+ const item = menuItems.find((m) => m.key === key);
1860
+ if (item === void 0 || item.disabled === true) {
1861
+ return;
1862
+ }
1863
+ if (onMenuSelect !== void 0) {
1864
+ onMenuSelect(key, item);
1865
+ return;
1866
+ }
1867
+ if (bridge !== void 0 && item.path !== void 0) {
1868
+ bridge.push(item.path);
1869
+ }
1870
+ };
1871
+ const sidebarContent = sidebar !== void 0 && sidebar !== null ? sidebar : menuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1872
+ Menu2,
1873
+ {
1874
+ items: menuItems.map((item) => chatMenuItemToUiMenuItem(item)),
1875
+ selectedKey: activeKey,
1876
+ onSelect: handleSelect
1877
+ }
1878
+ ) : void 0;
1879
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1880
+ Sidebar,
1881
+ {
1882
+ brand,
1883
+ content: sidebarContent,
1884
+ sidebarFooter,
1885
+ collapsible,
1886
+ locationKey: routeProp?.path ?? bridgePath,
1887
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1888
+ "div",
1889
+ {
1890
+ "data-slot": "chat-layout-content",
1891
+ className: "flex min-h-0 flex-1 flex-col",
1892
+ children
1893
+ }
1894
+ )
1895
+ }
1896
+ );
1897
+ }
1898
+ function chatMenuItemToUiMenuItem(item) {
1899
+ return {
1900
+ key: item.key,
1901
+ label: item.label,
1902
+ icon: item.icon,
1903
+ badge: item.badge,
1904
+ dot: item.dot,
1905
+ group: item.group,
1906
+ disabled: item.disabled
1907
+ };
1908
+ }
1909
+ function menuItemToMenuData(item) {
1910
+ if (item.type === "group") {
1911
+ const children = (item.children ?? []).flatMap(
1912
+ (child) => menuItemToMenuData(child)
1913
+ );
1914
+ if (children.length === 0) {
1915
+ return [];
1916
+ }
1917
+ return children.map((child, index) => ({
1918
+ ...child,
1919
+ group: index === 0 ? item.title : void 0
1920
+ }));
1921
+ }
1922
+ if (item.hidden === true) {
1923
+ return [];
1924
+ }
1925
+ const ext = item;
1926
+ return [
1927
+ {
1928
+ key: item.id,
1929
+ label: item.title,
1930
+ icon: item.icon,
1931
+ path: item.path,
1932
+ badge: item.badge,
1933
+ dot: ext.dot,
1934
+ group: ext.group,
1935
+ disabled: item.disabled
1936
+ }
1937
+ ];
1938
+ }
1939
+
1940
+ // src/ui/card.tsx
1941
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1942
+ function Card({ className, ...props }) {
1943
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
925
1944
  "div",
926
1945
  {
927
1946
  "data-slot": "card",
928
1947
  className: cn(
929
- "flex flex-col gap-6 rounded-xl border border-border bg-card py-6 text-card-foreground shadow-sm",
1948
+ "flex flex-col gap-6 rounded-xl border border-border bg-card py-6 text-card-foreground shadow-(--card-shadow)",
930
1949
  className
931
1950
  ),
932
1951
  ...props
@@ -934,7 +1953,7 @@ function Card({ className, ...props }) {
934
1953
  );
935
1954
  }
936
1955
  function CardHeader({ className, ...props }) {
937
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1956
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
938
1957
  "div",
939
1958
  {
940
1959
  "data-slot": "card-header",
@@ -947,7 +1966,7 @@ function CardHeader({ className, ...props }) {
947
1966
  );
948
1967
  }
949
1968
  function CardTitle({ className, ...props }) {
950
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1969
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
951
1970
  "div",
952
1971
  {
953
1972
  "data-slot": "card-title",
@@ -957,7 +1976,7 @@ function CardTitle({ className, ...props }) {
957
1976
  );
958
1977
  }
959
1978
  function CardContent({ className, ...props }) {
960
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1979
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
961
1980
  "div",
962
1981
  {
963
1982
  "data-slot": "card-content",
@@ -967,27 +1986,27 @@ function CardContent({ className, ...props }) {
967
1986
  );
968
1987
  }
969
1988
 
970
- // src/layout/basic/ShadcnLoginLayout.tsx
971
- var import_jsx_runtime7 = require("react/jsx-runtime");
972
- function ShadcnLoginLayout({
1989
+ // src/layout/basic/LoginLayout.tsx
1990
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1991
+ function LoginLayout({
973
1992
  variant = "center",
974
1993
  brand,
975
1994
  children
976
1995
  }) {
977
- const brandBlock = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-slot": "login-brand", className: "flex flex-col items-center gap-2", children: [
1996
+ const brandBlock = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { "data-slot": "login-brand", className: "flex flex-col items-center gap-2", children: [
978
1997
  brand.logo,
979
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { className: "text-xl font-semibold", children: brand.title }),
980
- brand.description !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-muted-foreground", children: brand.description })
1998
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { className: "text-xl font-semibold", children: brand.title }),
1999
+ brand.description !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "text-sm text-muted-foreground", children: brand.description })
981
2000
  ] });
982
2001
  if (variant === "split") {
983
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2002
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
984
2003
  "div",
985
2004
  {
986
2005
  "data-slot": "login-layout",
987
2006
  "data-variant": "split",
988
2007
  className: "grid min-h-screen grid-cols-2 bg-background text-foreground",
989
2008
  children: [
990
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2009
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
991
2010
  "div",
992
2011
  {
993
2012
  "data-slot": "login-brand-panel",
@@ -995,7 +2014,7 @@ function ShadcnLoginLayout({
995
2014
  children: brandBlock
996
2015
  }
997
2016
  ),
998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2017
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
999
2018
  "div",
1000
2019
  {
1001
2020
  "data-slot": "login-form-panel",
@@ -1007,46 +2026,46 @@ function ShadcnLoginLayout({
1007
2026
  }
1008
2027
  );
1009
2028
  }
1010
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2029
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1011
2030
  "div",
1012
2031
  {
1013
2032
  "data-slot": "login-layout",
1014
2033
  "data-variant": "center",
1015
2034
  className: "flex min-h-screen items-center justify-center bg-muted/40 text-foreground",
1016
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Card, { "data-slot": "login-card", className: "w-full max-w-sm gap-4 py-6", children: [
1017
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CardHeader, { className: "px-6", children: [
1018
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardTitle, { className: "sr-only", children: brand.title }),
2035
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Card, { "data-slot": "login-card", className: "w-full max-w-sm gap-4 py-6", children: [
2036
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(CardHeader, { className: "px-6", children: [
2037
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CardTitle, { className: "sr-only", children: brand.title }),
1019
2038
  brandBlock
1020
2039
  ] }),
1021
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardContent, { className: "flex flex-col gap-4 px-6", children })
2040
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CardContent, { className: "flex flex-col gap-4 px-6", children })
1022
2041
  ] })
1023
2042
  }
1024
2043
  );
1025
2044
  }
1026
2045
 
1027
- // src/layout/basic/ShadcnLandingLayout.tsx
1028
- var import_jsx_runtime8 = require("react/jsx-runtime");
1029
- function ShadcnLandingLayout({
2046
+ // src/layout/basic/LandingLayout.tsx
2047
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2048
+ function LandingLayout({
1030
2049
  navbar,
1031
2050
  footer,
1032
2051
  children
1033
2052
  }) {
1034
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2053
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1035
2054
  "div",
1036
2055
  {
1037
2056
  "data-slot": "landing-layout",
1038
2057
  className: "flex min-h-screen flex-col bg-background text-foreground",
1039
2058
  children: [
1040
- navbar !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2059
+ navbar !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1041
2060
  "header",
1042
2061
  {
1043
2062
  "data-slot": "landing-navbar",
1044
- className: "border-b border-border bg-background",
2063
+ className: "border-b border-border bg-card",
1045
2064
  children: navbar
1046
2065
  }
1047
2066
  ),
1048
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("main", { "data-slot": "landing-content", className: "flex-1", children }),
1049
- footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2067
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("main", { "data-slot": "landing-content", className: "flex-1", children }),
2068
+ footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1050
2069
  "footer",
1051
2070
  {
1052
2071
  "data-slot": "landing-footer",
@@ -1061,15 +2080,16 @@ function ShadcnLandingLayout({
1061
2080
 
1062
2081
  // src/layout/registry.ts
1063
2082
  var import_core = require("@pactor-app/core");
1064
- function registerShadcnLayouts(registry) {
1065
- registry.register("admin", ShadcnAdminLayout);
1066
- registry.register("blank", ShadcnBlankLayout);
1067
- registry.register("login", ShadcnLoginLayout);
1068
- registry.register("landing", ShadcnLandingLayout);
2083
+ function registerBuiltinLayouts(registry) {
2084
+ registry.register("admin", AdminLayout);
2085
+ registry.register("blank", BlankLayout);
2086
+ registry.register("login", LoginLayout);
2087
+ registry.register("landing", LandingLayout);
2088
+ registry.register("chat", ChatLayout);
1069
2089
  }
1070
- function createShadcnLayoutRegistry() {
2090
+ function createLayoutRegistry() {
1071
2091
  const registry = new import_core.Registry("LayoutRegistry");
1072
- registerShadcnLayouts(registry);
2092
+ registerBuiltinLayouts(registry);
1073
2093
  return registry;
1074
2094
  }
1075
2095
  function resolveLayout(registry, type) {
@@ -1078,19 +2098,20 @@ function resolveLayout(registry, type) {
1078
2098
  console.warn(
1079
2099
  `[pactor-layout] unknown layout type "${type}", fallback to BlankLayout`
1080
2100
  );
1081
- return ShadcnBlankLayout;
2101
+ return BlankLayout;
1082
2102
  }
1083
2103
  return component;
1084
2104
  }
1085
2105
  // Annotate the CommonJS export names for ESM import in node:
1086
2106
  0 && (module.exports = {
1087
- ShadcnAdminLayout,
1088
- ShadcnBlankLayout,
1089
- ShadcnLandingLayout,
1090
- ShadcnLoginLayout,
2107
+ AdminLayout,
2108
+ BlankLayout,
2109
+ ChatLayout,
2110
+ LandingLayout,
2111
+ LoginLayout,
1091
2112
  collectDefaultOpenKeys,
1092
- createShadcnLayoutRegistry,
2113
+ createLayoutRegistry,
1093
2114
  findMenuChain,
1094
- registerShadcnLayouts,
2115
+ registerBuiltinLayouts,
1095
2116
  resolveLayout
1096
2117
  });