@fayz-ai/ui 0.2.0 → 0.5.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/chunk-22J2RTMN.js +1397 -0
- package/dist/chunk-22J2RTMN.js.map +1 -0
- package/dist/chunk-2P7T6QQK.cjs +206 -0
- package/dist/chunk-2P7T6QQK.cjs.map +1 -0
- package/dist/chunk-7TBDPNLY.cjs +649 -0
- package/dist/chunk-7TBDPNLY.cjs.map +1 -0
- package/dist/chunk-CZ6X6PZT.js +1237 -0
- package/dist/chunk-CZ6X6PZT.js.map +1 -0
- package/dist/chunk-D6SXPF4F.cjs +397 -0
- package/dist/chunk-D6SXPF4F.cjs.map +1 -0
- package/dist/chunk-DNYVEOAX.js +11 -0
- package/dist/chunk-DNYVEOAX.js.map +1 -0
- package/dist/chunk-E526FHZ4.js +169 -0
- package/dist/chunk-E526FHZ4.js.map +1 -0
- package/dist/chunk-GE6XUREM.cjs +1277 -0
- package/dist/chunk-GE6XUREM.cjs.map +1 -0
- package/dist/chunk-GFH5HOCO.js +605 -0
- package/dist/chunk-GFH5HOCO.js.map +1 -0
- package/dist/chunk-IWBXYV4U.js +203 -0
- package/dist/chunk-IWBXYV4U.js.map +1 -0
- package/dist/chunk-MYZT2OG7.js +350 -0
- package/dist/chunk-MYZT2OG7.js.map +1 -0
- package/dist/chunk-O5F4LLSL.js +445 -0
- package/dist/chunk-O5F4LLSL.js.map +1 -0
- package/dist/chunk-TDGSY5W6.cjs +474 -0
- package/dist/chunk-TDGSY5W6.cjs.map +1 -0
- package/dist/chunk-VVVZO2LE.cjs +13 -0
- package/dist/chunk-VVVZO2LE.cjs.map +1 -0
- package/dist/chunk-W4XXXJRW.cjs +196 -0
- package/dist/chunk-W4XXXJRW.cjs.map +1 -0
- package/dist/chunk-YB5ZJKNG.cjs +1484 -0
- package/dist/chunk-YB5ZJKNG.cjs.map +1 -0
- package/dist/dashboard/index.cjs +102 -0
- package/dist/dashboard/index.cjs.map +1 -0
- package/dist/dashboard/index.js +5 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/index.cjs +569 -4304
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +15 -4152
- package/dist/index.js.map +1 -1
- package/dist/layout/index.cjs +90 -0
- package/dist/layout/index.cjs.map +1 -0
- package/dist/layout/index.js +5 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/preset.cjs +18 -0
- package/dist/preset.cjs.map +1 -0
- package/dist/preset.js +3 -0
- package/dist/preset.js.map +1 -0
- package/dist/primitives/index.cjs +347 -0
- package/dist/primitives/index.cjs.map +1 -0
- package/dist/primitives/index.js +6 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/theme/index.cjs +41 -0
- package/dist/theme/index.cjs.map +1 -0
- package/dist/theme/index.js +4 -0
- package/dist/theme/index.js.map +1 -0
- package/package.json +10 -10
|
@@ -0,0 +1,1237 @@
|
|
|
1
|
+
import { useCrossModuleBack, useBackHandler, SaveBarProvider, SaveBar } from './chunk-E526FHZ4.js';
|
|
2
|
+
import { cn } from './chunk-DNYVEOAX.js';
|
|
3
|
+
import * as React3 from 'react';
|
|
4
|
+
import { Workflow, Star, MessageSquare, LayoutDashboard, Award, Zap, Mic, UsersRound, Disc3, ListMusic, Eye, Music, Layers, Banknote, CalendarDays, Radio, PartyPopper, Wheat, Egg, Apple, LeafyGreen, LayoutTemplate, Heart, PawPrint, Cat, Dog, Search, List, Plus, Filter, Building2, Contact, Handshake, MapPin, UtensilsCrossed, Camera, Tag, Percent, Globe, MessageCircle, BookOpen, UserCog, Briefcase, ClipboardList, Wrench, Target, ShoppingCart, Megaphone, DollarSign, Mail, FileText, BarChart3, Package, Calendar, Bell, CreditCard, Settings, Users, Home, PanelLeftClose, PanelLeft, Menu, ChevronRight, ChevronLeft, TreePalm, UserPlus, ArrowDownRight, ArrowUpRight, Ruler, Warehouse, Wallet, Sparkles, AlertTriangle, Clock, CircleDollarSign, TrendingUp, Receipt, Landmark, TableProperties, SlidersHorizontal, Plug, ArrowLeftRight, ArrowUpCircle, ArrowDownCircle, ChevronDown } from 'lucide-react';
|
|
5
|
+
import * as Tooltip from '@radix-ui/react-tooltip';
|
|
6
|
+
import { create } from 'zustand';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import * as Popover from '@radix-ui/react-popover';
|
|
9
|
+
import { createPortal } from 'react-dom';
|
|
10
|
+
import { useTranslation } from '@fayz-ai/core';
|
|
11
|
+
|
|
12
|
+
var useLayoutStore = create((set) => ({
|
|
13
|
+
sidebarOpen: true,
|
|
14
|
+
sidebarCollapsed: false,
|
|
15
|
+
mobileDrawerOpen: false,
|
|
16
|
+
commandPaletteOpen: false,
|
|
17
|
+
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
|
|
18
|
+
setSidebarCollapsed: (collapsed) => set({ sidebarCollapsed: collapsed }),
|
|
19
|
+
toggleMobileDrawer: () => set((state) => ({ mobileDrawerOpen: !state.mobileDrawerOpen })),
|
|
20
|
+
setCommandPaletteOpen: (open) => set({ commandPaletteOpen: open })
|
|
21
|
+
}));
|
|
22
|
+
var ICON_MAP = {
|
|
23
|
+
Home,
|
|
24
|
+
Users,
|
|
25
|
+
Settings,
|
|
26
|
+
CreditCard,
|
|
27
|
+
Bell,
|
|
28
|
+
Calendar,
|
|
29
|
+
Package,
|
|
30
|
+
BarChart3,
|
|
31
|
+
FileText,
|
|
32
|
+
Mail,
|
|
33
|
+
DollarSign,
|
|
34
|
+
Megaphone,
|
|
35
|
+
ShoppingCart,
|
|
36
|
+
Target,
|
|
37
|
+
Wrench,
|
|
38
|
+
ClipboardList,
|
|
39
|
+
Briefcase,
|
|
40
|
+
UserCog,
|
|
41
|
+
BookOpen,
|
|
42
|
+
MessageCircle,
|
|
43
|
+
Globe,
|
|
44
|
+
Percent,
|
|
45
|
+
Tag,
|
|
46
|
+
Camera,
|
|
47
|
+
UtensilsCrossed,
|
|
48
|
+
MapPin,
|
|
49
|
+
Handshake,
|
|
50
|
+
Contact,
|
|
51
|
+
Building2,
|
|
52
|
+
Filter,
|
|
53
|
+
Plus,
|
|
54
|
+
List,
|
|
55
|
+
Search,
|
|
56
|
+
Dog,
|
|
57
|
+
Cat,
|
|
58
|
+
PawPrint,
|
|
59
|
+
Heart,
|
|
60
|
+
LayoutTemplate,
|
|
61
|
+
LeafyGreen,
|
|
62
|
+
Apple,
|
|
63
|
+
Egg,
|
|
64
|
+
Wheat,
|
|
65
|
+
PartyPopper,
|
|
66
|
+
Radio,
|
|
67
|
+
CalendarDays,
|
|
68
|
+
Banknote,
|
|
69
|
+
Layers,
|
|
70
|
+
Music,
|
|
71
|
+
Eye,
|
|
72
|
+
ListMusic,
|
|
73
|
+
Disc3,
|
|
74
|
+
UsersRound,
|
|
75
|
+
Mic,
|
|
76
|
+
Zap,
|
|
77
|
+
Award,
|
|
78
|
+
LayoutDashboard,
|
|
79
|
+
MessageSquare,
|
|
80
|
+
Star,
|
|
81
|
+
Workflow
|
|
82
|
+
};
|
|
83
|
+
function getIcon(name) {
|
|
84
|
+
return ICON_MAP[name] ?? Home;
|
|
85
|
+
}
|
|
86
|
+
function NavItem({
|
|
87
|
+
item,
|
|
88
|
+
collapsed,
|
|
89
|
+
isActive,
|
|
90
|
+
onNavigate
|
|
91
|
+
}) {
|
|
92
|
+
const Icon = getIcon(item.icon);
|
|
93
|
+
const content = /* @__PURE__ */ jsxs(
|
|
94
|
+
"button",
|
|
95
|
+
{
|
|
96
|
+
onClick: () => onNavigate(item.route),
|
|
97
|
+
className: cn(
|
|
98
|
+
"flex w-full items-center gap-3 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors",
|
|
99
|
+
"hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
|
|
100
|
+
isActive ? "bg-sidebar-accent font-semibold text-sidebar-accent-foreground shadow-sm" : "text-sidebar-foreground/80",
|
|
101
|
+
collapsed && "justify-center px-2"
|
|
102
|
+
),
|
|
103
|
+
children: [
|
|
104
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
105
|
+
!collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
106
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
|
|
107
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto rounded-full bg-primary px-2 py-0.5 text-xs font-semibold text-primary-foreground", children: item.badge })
|
|
108
|
+
] })
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
if (collapsed) {
|
|
113
|
+
return /* @__PURE__ */ jsxs(Tooltip.Root, { delayDuration: 0, children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: content }),
|
|
115
|
+
/* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsxs(
|
|
116
|
+
Tooltip.Content,
|
|
117
|
+
{
|
|
118
|
+
side: "right",
|
|
119
|
+
sideOffset: 8,
|
|
120
|
+
className: "fayz-glass-surface z-50 rounded-md bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md",
|
|
121
|
+
children: [
|
|
122
|
+
item.label,
|
|
123
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-2 rounded-full bg-primary px-1.5 py-0.5 text-xs text-primary-foreground", children: item.badge }),
|
|
124
|
+
/* @__PURE__ */ jsx(Tooltip.Arrow, { className: "fill-popover" })
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
) })
|
|
128
|
+
] });
|
|
129
|
+
}
|
|
130
|
+
return content;
|
|
131
|
+
}
|
|
132
|
+
function NavGroup({
|
|
133
|
+
item,
|
|
134
|
+
collapsed,
|
|
135
|
+
currentPath,
|
|
136
|
+
onNavigate
|
|
137
|
+
}) {
|
|
138
|
+
const [open, setOpen] = React3.useState(
|
|
139
|
+
() => item.children?.some((c) => currentPath === c.route || currentPath.startsWith(c.route + "/")) ?? false
|
|
140
|
+
);
|
|
141
|
+
const Icon = getIcon(item.icon);
|
|
142
|
+
const isChildActive = item.children?.some(
|
|
143
|
+
(c) => currentPath === c.route || currentPath.startsWith(c.route + "/")
|
|
144
|
+
);
|
|
145
|
+
if (collapsed) {
|
|
146
|
+
return /* @__PURE__ */ jsxs(Tooltip.Root, { delayDuration: 0, children: [
|
|
147
|
+
/* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
148
|
+
"button",
|
|
149
|
+
{
|
|
150
|
+
onClick: () => onNavigate(item.route),
|
|
151
|
+
className: cn(
|
|
152
|
+
"flex w-full items-center justify-center rounded-md px-2 py-2 text-sm font-medium transition-colors",
|
|
153
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
154
|
+
isChildActive ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-muted"
|
|
155
|
+
),
|
|
156
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" })
|
|
157
|
+
}
|
|
158
|
+
) }),
|
|
159
|
+
/* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsxs(Tooltip.Content, { side: "right", sideOffset: 8, className: "fayz-glass-surface z-50 rounded-md bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md", children: [
|
|
160
|
+
item.label,
|
|
161
|
+
/* @__PURE__ */ jsx(Tooltip.Arrow, { className: "fill-popover" })
|
|
162
|
+
] }) })
|
|
163
|
+
] });
|
|
164
|
+
}
|
|
165
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
166
|
+
/* @__PURE__ */ jsxs(
|
|
167
|
+
"button",
|
|
168
|
+
{
|
|
169
|
+
onClick: () => setOpen(!open),
|
|
170
|
+
className: cn(
|
|
171
|
+
"flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
172
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
173
|
+
isChildActive ? "text-sidebar-accent-foreground" : "text-sidebar-muted"
|
|
174
|
+
),
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
|
|
178
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: cn("h-3.5 w-3.5 shrink-0 transition-transform", open && "rotate-180") })
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
),
|
|
182
|
+
open && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l border-sidebar-border/50 pl-3", children: item.children?.map((child) => {
|
|
183
|
+
const ChildIcon = getIcon(child.icon);
|
|
184
|
+
const isActive = currentPath === child.route || currentPath.startsWith(child.route + "/");
|
|
185
|
+
return /* @__PURE__ */ jsxs(
|
|
186
|
+
"button",
|
|
187
|
+
{
|
|
188
|
+
onClick: () => onNavigate(child.route),
|
|
189
|
+
className: cn(
|
|
190
|
+
"flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
|
|
191
|
+
isActive ? "font-medium text-sidebar-accent-foreground" : "text-sidebar-muted hover:text-sidebar-accent-foreground"
|
|
192
|
+
),
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ jsx(ChildIcon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
195
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: child.label })
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
child.id
|
|
199
|
+
);
|
|
200
|
+
}) })
|
|
201
|
+
] });
|
|
202
|
+
}
|
|
203
|
+
function Sidebar({
|
|
204
|
+
navigation,
|
|
205
|
+
logo,
|
|
206
|
+
collapsed,
|
|
207
|
+
onToggle,
|
|
208
|
+
onNavigate,
|
|
209
|
+
currentPath: currentPathProp = "/",
|
|
210
|
+
user: _user,
|
|
211
|
+
orgSwitcher,
|
|
212
|
+
topContent,
|
|
213
|
+
footerContent,
|
|
214
|
+
borderless,
|
|
215
|
+
userMenuSlot,
|
|
216
|
+
notificationSlot,
|
|
217
|
+
unreadCount = 0
|
|
218
|
+
}) {
|
|
219
|
+
const currentPath = currentPathProp;
|
|
220
|
+
const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
|
|
221
|
+
const mainItems = navigation.filter((item) => item.section === "main");
|
|
222
|
+
const secondaryItems = navigation.filter((item) => item.section === "secondary");
|
|
223
|
+
const settingsItems = navigation.filter((item) => item.section === "settings");
|
|
224
|
+
const handleNavigate = (route) => {
|
|
225
|
+
onNavigate?.(route);
|
|
226
|
+
};
|
|
227
|
+
return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsxs(
|
|
228
|
+
"aside",
|
|
229
|
+
{
|
|
230
|
+
"data-print": "hide",
|
|
231
|
+
className: cn(
|
|
232
|
+
"flex h-full flex-col bg-sidebar text-sidebar-foreground transition-all duration-200",
|
|
233
|
+
!borderless && "border-r border-sidebar-border",
|
|
234
|
+
collapsed ? "w-16" : "w-64"
|
|
235
|
+
),
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ jsxs(
|
|
238
|
+
"div",
|
|
239
|
+
{
|
|
240
|
+
className: cn(
|
|
241
|
+
"flex h-14 items-center justify-between px-4",
|
|
242
|
+
!borderless && "border-b border-sidebar-border",
|
|
243
|
+
collapsed && "justify-center px-2"
|
|
244
|
+
),
|
|
245
|
+
children: [
|
|
246
|
+
!collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
247
|
+
logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }),
|
|
248
|
+
/* @__PURE__ */ jsx(
|
|
249
|
+
"button",
|
|
250
|
+
{
|
|
251
|
+
onClick: onToggle,
|
|
252
|
+
className: "ml-auto rounded-md p-1.5 text-sidebar-muted transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
253
|
+
"aria-label": "Collapse sidebar",
|
|
254
|
+
children: /* @__PURE__ */ jsx(PanelLeftClose, { className: "h-4 w-4" })
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
] }),
|
|
258
|
+
collapsed && /* @__PURE__ */ jsx(
|
|
259
|
+
"button",
|
|
260
|
+
{
|
|
261
|
+
onClick: onToggle,
|
|
262
|
+
className: "rounded-md p-1.5 text-sidebar-muted transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
263
|
+
"aria-label": "Expand sidebar",
|
|
264
|
+
children: /* @__PURE__ */ jsx(PanelLeft, { className: "h-4 w-4" })
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
),
|
|
270
|
+
/* @__PURE__ */ jsxs("nav", { className: "flex-1 space-y-1 overflow-y-auto p-2", children: [
|
|
271
|
+
topContent && /* @__PURE__ */ jsx("div", { className: "mb-4 space-y-2", children: topContent }),
|
|
272
|
+
mainItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-1", children: mainItems.map(
|
|
273
|
+
(item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, currentPath, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
|
|
274
|
+
NavItem,
|
|
275
|
+
{
|
|
276
|
+
item,
|
|
277
|
+
collapsed,
|
|
278
|
+
isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
|
|
279
|
+
onNavigate: handleNavigate
|
|
280
|
+
},
|
|
281
|
+
item.id
|
|
282
|
+
)
|
|
283
|
+
) }),
|
|
284
|
+
secondaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6 space-y-1", children: secondaryItems.map(
|
|
285
|
+
(item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, currentPath, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
|
|
286
|
+
NavItem,
|
|
287
|
+
{
|
|
288
|
+
item,
|
|
289
|
+
collapsed,
|
|
290
|
+
isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
|
|
291
|
+
onNavigate: handleNavigate
|
|
292
|
+
},
|
|
293
|
+
item.id
|
|
294
|
+
)
|
|
295
|
+
) })
|
|
296
|
+
] }),
|
|
297
|
+
settingsItems.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("p-2 space-y-1", !borderless && "border-t border-sidebar-border"), children: settingsItems.map((item) => /* @__PURE__ */ jsx(
|
|
298
|
+
NavItem,
|
|
299
|
+
{
|
|
300
|
+
item,
|
|
301
|
+
collapsed,
|
|
302
|
+
isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
|
|
303
|
+
onNavigate: handleNavigate
|
|
304
|
+
},
|
|
305
|
+
item.id
|
|
306
|
+
)) }),
|
|
307
|
+
footerContent && /* @__PURE__ */ jsx("div", { className: cn("p-2", !borderless && "border-t border-sidebar-border"), children: /* @__PURE__ */ jsx("div", { className: "space-y-2", children: footerContent }) }),
|
|
308
|
+
orgSwitcher && React3.isValidElement(orgSwitcher) ? React3.cloneElement(orgSwitcher, { collapsed }) : orgSwitcher,
|
|
309
|
+
/* @__PURE__ */ jsx("div", { className: cn("p-2", !borderless && "border-t border-sidebar-border"), children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
310
|
+
"flex items-center rounded-md",
|
|
311
|
+
collapsed ? "flex-col gap-1" : "gap-1 px-1"
|
|
312
|
+
), children: [
|
|
313
|
+
userMenuSlot,
|
|
314
|
+
!collapsed && /* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
315
|
+
/* @__PURE__ */ jsx(
|
|
316
|
+
"button",
|
|
317
|
+
{
|
|
318
|
+
onClick: () => setCommandPaletteOpen(true),
|
|
319
|
+
className: "inline-flex shrink-0 items-center justify-center rounded-md p-2 text-sidebar-muted transition-colors hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground",
|
|
320
|
+
"aria-label": "Search",
|
|
321
|
+
children: /* @__PURE__ */ jsx(Search, { className: "h-4 w-4" })
|
|
322
|
+
}
|
|
323
|
+
),
|
|
324
|
+
notificationSlot ?? /* @__PURE__ */ jsxs(
|
|
325
|
+
"button",
|
|
326
|
+
{
|
|
327
|
+
className: "relative inline-flex shrink-0 items-center justify-center rounded-md p-2 text-sidebar-muted transition-colors hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground",
|
|
328
|
+
"aria-label": unreadCount > 0 ? `${unreadCount} unread notifications` : "Notifications",
|
|
329
|
+
children: [
|
|
330
|
+
/* @__PURE__ */ jsx(Bell, { className: "h-4 w-4" }),
|
|
331
|
+
unreadCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute right-1 top-1 h-2 w-2 rounded-full bg-destructive" })
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
)
|
|
335
|
+
] }) })
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
) });
|
|
339
|
+
}
|
|
340
|
+
function TopbarUserMenu({
|
|
341
|
+
user,
|
|
342
|
+
onSignOut,
|
|
343
|
+
onProfile,
|
|
344
|
+
onSettings,
|
|
345
|
+
onBilling,
|
|
346
|
+
userMenuExtras
|
|
347
|
+
}) {
|
|
348
|
+
const [open, setOpen] = React3.useState(false);
|
|
349
|
+
if (!user) return null;
|
|
350
|
+
const initial = (user.fullName?.trim()?.[0] ?? user.email?.[0] ?? "?").toUpperCase();
|
|
351
|
+
const item = (label, onClick, Icon) => onClick ? /* @__PURE__ */ jsxs(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
onClick: () => {
|
|
355
|
+
setOpen(false);
|
|
356
|
+
onClick();
|
|
357
|
+
},
|
|
358
|
+
className: "flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-popover-foreground transition-colors hover:bg-muted/70",
|
|
359
|
+
children: [
|
|
360
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground" }),
|
|
361
|
+
/* @__PURE__ */ jsx("span", { children: label })
|
|
362
|
+
]
|
|
363
|
+
},
|
|
364
|
+
label
|
|
365
|
+
) : null;
|
|
366
|
+
return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange: setOpen, children: [
|
|
367
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
368
|
+
"button",
|
|
369
|
+
{
|
|
370
|
+
"aria-label": "User menu",
|
|
371
|
+
className: "ml-1 flex h-9 w-9 items-center justify-center overflow-hidden rounded-full bg-primary text-xs font-semibold text-primary-foreground ring-2 ring-transparent transition hover:ring-sidebar-border",
|
|
372
|
+
children: user.avatarUrl ? (
|
|
373
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
374
|
+
/* @__PURE__ */ jsx("img", { src: user.avatarUrl, alt: "", className: "h-full w-full object-cover" })
|
|
375
|
+
) : initial
|
|
376
|
+
}
|
|
377
|
+
) }),
|
|
378
|
+
/* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(
|
|
379
|
+
Popover.Content,
|
|
380
|
+
{
|
|
381
|
+
align: "end",
|
|
382
|
+
sideOffset: 8,
|
|
383
|
+
className: "fayz-glass-surface z-50 min-w-[220px] rounded-xl border border-border bg-popover p-1.5 shadow-lg animate-in fade-in-0 zoom-in-95",
|
|
384
|
+
children: [
|
|
385
|
+
/* @__PURE__ */ jsxs("div", { className: "border-b border-border px-3 py-2", children: [
|
|
386
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-foreground", children: user.fullName || user.email }),
|
|
387
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: user.email })
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 space-y-0.5", children: [
|
|
390
|
+
item("Perfil", onProfile, UserCog),
|
|
391
|
+
item("Configura\xE7\xF5es", onSettings, Settings),
|
|
392
|
+
item("Cobran\xE7a", onBilling, CreditCard),
|
|
393
|
+
userMenuExtras?.map((e) => item(e.label, e.onClick)),
|
|
394
|
+
onSignOut && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
395
|
+
/* @__PURE__ */ jsx("div", { className: "my-1 border-t border-border" }),
|
|
396
|
+
item("Sair", onSignOut)
|
|
397
|
+
] })
|
|
398
|
+
] })
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
) })
|
|
402
|
+
] });
|
|
403
|
+
}
|
|
404
|
+
var ICON_MAP2 = {
|
|
405
|
+
Home: Home,
|
|
406
|
+
Users: Users,
|
|
407
|
+
Settings: Settings,
|
|
408
|
+
CreditCard: CreditCard,
|
|
409
|
+
Bell: Bell,
|
|
410
|
+
Calendar: Calendar,
|
|
411
|
+
Package: Package,
|
|
412
|
+
BarChart3: BarChart3,
|
|
413
|
+
FileText: FileText,
|
|
414
|
+
Mail: Mail,
|
|
415
|
+
DollarSign: DollarSign,
|
|
416
|
+
Megaphone: Megaphone,
|
|
417
|
+
ShoppingCart: ShoppingCart,
|
|
418
|
+
Target: Target,
|
|
419
|
+
Wrench: Wrench,
|
|
420
|
+
ClipboardList: ClipboardList,
|
|
421
|
+
Briefcase: Briefcase,
|
|
422
|
+
UserCog: UserCog,
|
|
423
|
+
BookOpen: BookOpen,
|
|
424
|
+
MessageCircle: MessageCircle,
|
|
425
|
+
Globe: Globe,
|
|
426
|
+
Percent: Percent,
|
|
427
|
+
Tag: Tag,
|
|
428
|
+
Camera: Camera,
|
|
429
|
+
UtensilsCrossed: UtensilsCrossed,
|
|
430
|
+
Search: Search,
|
|
431
|
+
MapPin: MapPin,
|
|
432
|
+
Handshake: Handshake,
|
|
433
|
+
Contact: Contact,
|
|
434
|
+
Building2: Building2,
|
|
435
|
+
ChevronDown: ChevronDown,
|
|
436
|
+
Filter: Filter,
|
|
437
|
+
Plus: Plus,
|
|
438
|
+
List: List,
|
|
439
|
+
Dog: Dog,
|
|
440
|
+
Cat: Cat,
|
|
441
|
+
PawPrint: PawPrint,
|
|
442
|
+
Heart: Heart,
|
|
443
|
+
LayoutTemplate: LayoutTemplate,
|
|
444
|
+
LeafyGreen: LeafyGreen,
|
|
445
|
+
Apple: Apple,
|
|
446
|
+
Egg: Egg,
|
|
447
|
+
Wheat: Wheat,
|
|
448
|
+
ArrowDownCircle,
|
|
449
|
+
ArrowUpCircle,
|
|
450
|
+
ArrowLeftRight,
|
|
451
|
+
Plug,
|
|
452
|
+
SlidersHorizontal,
|
|
453
|
+
TableProperties,
|
|
454
|
+
Landmark,
|
|
455
|
+
Receipt,
|
|
456
|
+
TrendingUp,
|
|
457
|
+
CircleDollarSign,
|
|
458
|
+
Clock,
|
|
459
|
+
AlertTriangle,
|
|
460
|
+
Sparkles,
|
|
461
|
+
Wallet,
|
|
462
|
+
Warehouse,
|
|
463
|
+
Ruler,
|
|
464
|
+
ArrowUpRight,
|
|
465
|
+
ArrowDownRight,
|
|
466
|
+
UserPlus,
|
|
467
|
+
TreePalm,
|
|
468
|
+
PartyPopper: PartyPopper,
|
|
469
|
+
Radio: Radio,
|
|
470
|
+
CalendarDays: CalendarDays,
|
|
471
|
+
Banknote: Banknote,
|
|
472
|
+
Layers: Layers,
|
|
473
|
+
Music: Music,
|
|
474
|
+
Eye: Eye,
|
|
475
|
+
ListMusic: ListMusic,
|
|
476
|
+
Disc3: Disc3,
|
|
477
|
+
UsersRound: UsersRound,
|
|
478
|
+
Mic: Mic
|
|
479
|
+
};
|
|
480
|
+
function getIcon2(name) {
|
|
481
|
+
return ICON_MAP2[name] ?? Home;
|
|
482
|
+
}
|
|
483
|
+
function NavDropdown({ item, currentPath, onNavigate }) {
|
|
484
|
+
const [open, setOpen] = React3.useState(false);
|
|
485
|
+
const Icon = getIcon2(item.icon);
|
|
486
|
+
const isChildActive = item.children?.some(
|
|
487
|
+
(child) => currentPath === child.route || currentPath.startsWith(child.route + "/")
|
|
488
|
+
);
|
|
489
|
+
return /* @__PURE__ */ jsxs(Popover.Root, { open, onOpenChange: setOpen, children: [
|
|
490
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
491
|
+
"button",
|
|
492
|
+
{
|
|
493
|
+
"data-nav-active": isChildActive || void 0,
|
|
494
|
+
className: cn(
|
|
495
|
+
"flex items-center gap-1.5 whitespace-nowrap border-b-2 px-3 py-2 text-sm transition-colors",
|
|
496
|
+
isChildActive ? "border-sidebar-accent-foreground font-semibold text-sidebar-foreground" : "border-transparent text-sidebar-muted hover:text-sidebar-foreground"
|
|
497
|
+
),
|
|
498
|
+
children: [
|
|
499
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
|
|
500
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
501
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: cn("h-3 w-3 transition-transform", open && "rotate-180") })
|
|
502
|
+
]
|
|
503
|
+
}
|
|
504
|
+
) }),
|
|
505
|
+
/* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
|
|
506
|
+
Popover.Content,
|
|
507
|
+
{
|
|
508
|
+
align: "start",
|
|
509
|
+
sideOffset: 4,
|
|
510
|
+
className: "fayz-glass-surface z-50 min-w-[200px] rounded-xl border border-border bg-popover p-1.5 shadow-lg animate-in fade-in-0 zoom-in-95",
|
|
511
|
+
children: item.children?.map((child) => {
|
|
512
|
+
const ChildIcon = getIcon2(child.icon);
|
|
513
|
+
const isActive = currentPath === child.route || currentPath.startsWith(child.route + "/");
|
|
514
|
+
return /* @__PURE__ */ jsxs(
|
|
515
|
+
"button",
|
|
516
|
+
{
|
|
517
|
+
onClick: () => {
|
|
518
|
+
onNavigate(child.route);
|
|
519
|
+
setOpen(false);
|
|
520
|
+
},
|
|
521
|
+
className: cn(
|
|
522
|
+
"flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-sm transition-colors",
|
|
523
|
+
isActive ? "bg-muted font-medium text-foreground" : "text-popover-foreground hover:bg-muted/70"
|
|
524
|
+
),
|
|
525
|
+
children: [
|
|
526
|
+
/* @__PURE__ */ jsx(ChildIcon, { className: "h-4 w-4 text-muted-foreground" }),
|
|
527
|
+
/* @__PURE__ */ jsx("span", { children: child.label })
|
|
528
|
+
]
|
|
529
|
+
},
|
|
530
|
+
child.id
|
|
531
|
+
);
|
|
532
|
+
})
|
|
533
|
+
}
|
|
534
|
+
) })
|
|
535
|
+
] });
|
|
536
|
+
}
|
|
537
|
+
function Topbar({
|
|
538
|
+
navigation,
|
|
539
|
+
logo,
|
|
540
|
+
user,
|
|
541
|
+
onMenuClick,
|
|
542
|
+
leftContent,
|
|
543
|
+
rightContent,
|
|
544
|
+
currentPath = "/",
|
|
545
|
+
onNavigate,
|
|
546
|
+
searchPlaceholder = "Search...",
|
|
547
|
+
onSignOut,
|
|
548
|
+
onProfile,
|
|
549
|
+
onSettings,
|
|
550
|
+
onBilling,
|
|
551
|
+
userMenuExtras
|
|
552
|
+
}) {
|
|
553
|
+
const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
|
|
554
|
+
const mainNav = navigation.filter((item) => item.section === "main");
|
|
555
|
+
const secondaryNav = navigation.filter((item) => item.section === "secondary");
|
|
556
|
+
const allNav = [...mainNav, ...secondaryNav];
|
|
557
|
+
const handleNavigate = (route) => {
|
|
558
|
+
onNavigate?.(route);
|
|
559
|
+
};
|
|
560
|
+
return /* @__PURE__ */ jsxs("header", { "data-print": "hide", className: "sticky top-0 z-50 w-full shrink-0", children: [
|
|
561
|
+
/* @__PURE__ */ jsx("div", { className: "border-b border-sidebar-border bg-sidebar text-sidebar-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex h-14 w-full items-center justify-between px-4 md:px-6", children: [
|
|
562
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
563
|
+
/* @__PURE__ */ jsx(
|
|
564
|
+
"button",
|
|
565
|
+
{
|
|
566
|
+
onClick: onMenuClick,
|
|
567
|
+
className: "inline-flex items-center justify-center rounded-md p-2 text-sidebar-foreground/70 hover:bg-sidebar/30 hover:text-sidebar-foreground md:hidden",
|
|
568
|
+
"aria-label": "Open menu",
|
|
569
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
|
|
570
|
+
}
|
|
571
|
+
),
|
|
572
|
+
/* @__PURE__ */ jsx("div", { className: "hidden shrink-0 items-center md:flex", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) })
|
|
573
|
+
] }),
|
|
574
|
+
/* @__PURE__ */ jsx("div", { className: "mx-8 hidden max-w-sm flex-1 md:flex", children: /* @__PURE__ */ jsxs(
|
|
575
|
+
"button",
|
|
576
|
+
{
|
|
577
|
+
onClick: () => setCommandPaletteOpen(true),
|
|
578
|
+
className: "relative flex h-8 w-full items-center rounded-md border border-sidebar-border bg-sidebar-accent px-3 pl-8 text-sm text-sidebar-muted shadow-sm transition-colors hover:bg-card",
|
|
579
|
+
children: [
|
|
580
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-sidebar-muted" }),
|
|
581
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: searchPlaceholder }),
|
|
582
|
+
/* @__PURE__ */ jsx("kbd", { className: "ml-auto hidden rounded border border-sidebar-border bg-sidebar-accent px-1.5 py-0.5 text-[10px] font-medium text-sidebar-muted sm:inline-block", children: "\u2318K" })
|
|
583
|
+
]
|
|
584
|
+
}
|
|
585
|
+
) }),
|
|
586
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
587
|
+
leftContent,
|
|
588
|
+
rightContent,
|
|
589
|
+
/* @__PURE__ */ jsx(
|
|
590
|
+
TopbarUserMenu,
|
|
591
|
+
{
|
|
592
|
+
user,
|
|
593
|
+
onSignOut,
|
|
594
|
+
onProfile,
|
|
595
|
+
onSettings,
|
|
596
|
+
onBilling,
|
|
597
|
+
userMenuExtras
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
] })
|
|
601
|
+
] }) }),
|
|
602
|
+
/* @__PURE__ */ jsx("div", { className: "hidden md:block bg-sidebar", children: /* @__PURE__ */ jsx("div", { className: "flex h-11 w-full items-center px-4 md:px-6", children: /* @__PURE__ */ jsx("nav", { ref: (el) => {
|
|
603
|
+
if (!el) return;
|
|
604
|
+
const active = el.querySelector('[data-nav-active="true"]');
|
|
605
|
+
if (active) {
|
|
606
|
+
const left = active.offsetLeft - el.offsetWidth / 2 + active.offsetWidth / 2;
|
|
607
|
+
el.scrollTo({ left: Math.max(0, left), behavior: "smooth" });
|
|
608
|
+
}
|
|
609
|
+
}, className: "flex items-center gap-0.5 overflow-x-auto scrollbar-hide", children: allNav.map((item) => {
|
|
610
|
+
if (item.children && item.children.length > 0) {
|
|
611
|
+
return /* @__PURE__ */ jsx(
|
|
612
|
+
NavDropdown,
|
|
613
|
+
{
|
|
614
|
+
item,
|
|
615
|
+
currentPath,
|
|
616
|
+
onNavigate: handleNavigate
|
|
617
|
+
},
|
|
618
|
+
item.id
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
const Icon = getIcon2(item.icon);
|
|
622
|
+
const isActive = item.route === "/" ? currentPath === "/" : currentPath === item.route || currentPath.startsWith(item.route + "/");
|
|
623
|
+
return /* @__PURE__ */ jsxs(
|
|
624
|
+
"button",
|
|
625
|
+
{
|
|
626
|
+
"data-nav-active": isActive || void 0,
|
|
627
|
+
onClick: () => handleNavigate(item.route),
|
|
628
|
+
className: cn(
|
|
629
|
+
"flex items-center gap-1.5 whitespace-nowrap border-b-2 px-3 py-2 text-sm transition-colors",
|
|
630
|
+
isActive ? "border-primary font-semibold text-sidebar-foreground" : "border-transparent text-sidebar-muted hover:text-sidebar-foreground"
|
|
631
|
+
),
|
|
632
|
+
children: [
|
|
633
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
|
|
634
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
635
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary px-1.5 py-0.5 text-[10px] font-semibold text-primary-foreground", children: item.badge })
|
|
636
|
+
]
|
|
637
|
+
},
|
|
638
|
+
item.id
|
|
639
|
+
);
|
|
640
|
+
}) }) }) })
|
|
641
|
+
] });
|
|
642
|
+
}
|
|
643
|
+
var ModuleHeaderSlotContext = React3.createContext(null);
|
|
644
|
+
function useModuleHeaderSlot() {
|
|
645
|
+
return React3.useContext(ModuleHeaderSlotContext);
|
|
646
|
+
}
|
|
647
|
+
var ModuleHeaderActionsSlotContext = React3.createContext(null);
|
|
648
|
+
function useModuleHeaderActionsSlot() {
|
|
649
|
+
return React3.useContext(ModuleHeaderActionsSlotContext);
|
|
650
|
+
}
|
|
651
|
+
function SidebarLayout({
|
|
652
|
+
navigation = [],
|
|
653
|
+
logo,
|
|
654
|
+
user,
|
|
655
|
+
children,
|
|
656
|
+
onNavigate,
|
|
657
|
+
onSignOut,
|
|
658
|
+
onProfile,
|
|
659
|
+
onSettings,
|
|
660
|
+
onBilling,
|
|
661
|
+
userMenuExtras: _userMenuExtras,
|
|
662
|
+
orgSwitcher,
|
|
663
|
+
sidebarTopContent,
|
|
664
|
+
sidebarFooterContent,
|
|
665
|
+
frame,
|
|
666
|
+
currentPath,
|
|
667
|
+
pageTitle,
|
|
668
|
+
topbarStart,
|
|
669
|
+
topbarEnd,
|
|
670
|
+
userMenuSlot,
|
|
671
|
+
notificationSlot,
|
|
672
|
+
unreadCount = 0
|
|
673
|
+
}) {
|
|
674
|
+
const sidebarCollapsed = useLayoutStore((s) => s.sidebarCollapsed);
|
|
675
|
+
const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
|
|
676
|
+
const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
|
|
677
|
+
const [headerSlot, setHeaderSlot] = React3.useState(null);
|
|
678
|
+
const [actionsSlot, setActionsSlot] = React3.useState(null);
|
|
679
|
+
return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsx(ModuleHeaderSlotContext.Provider, { value: headerSlot, children: /* @__PURE__ */ jsx(ModuleHeaderActionsSlotContext.Provider, { value: actionsSlot, children: /* @__PURE__ */ jsxs("div", { className: "flex h-screen overflow-hidden bg-background", children: [
|
|
680
|
+
/* @__PURE__ */ jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsx(
|
|
681
|
+
Sidebar,
|
|
682
|
+
{
|
|
683
|
+
navigation,
|
|
684
|
+
logo,
|
|
685
|
+
collapsed: sidebarCollapsed,
|
|
686
|
+
onToggle: () => setSidebarCollapsed(!sidebarCollapsed),
|
|
687
|
+
onNavigate,
|
|
688
|
+
currentPath,
|
|
689
|
+
user,
|
|
690
|
+
onSignOut,
|
|
691
|
+
onProfile,
|
|
692
|
+
onSettings,
|
|
693
|
+
onBilling,
|
|
694
|
+
orgSwitcher,
|
|
695
|
+
topContent: sidebarTopContent,
|
|
696
|
+
footerContent: sidebarFooterContent,
|
|
697
|
+
borderless: false,
|
|
698
|
+
userMenuSlot,
|
|
699
|
+
notificationSlot,
|
|
700
|
+
unreadCount
|
|
701
|
+
}
|
|
702
|
+
) }),
|
|
703
|
+
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
704
|
+
"relative flex flex-1 flex-col overflow-hidden",
|
|
705
|
+
frame && "md:m-2 md:rounded-xl md:border md:border-border md:bg-card"
|
|
706
|
+
), children: [
|
|
707
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-14 shrink-0 items-center justify-between gap-3 border-b border-border bg-card px-4 py-2", children: [
|
|
708
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
709
|
+
/* @__PURE__ */ jsx(
|
|
710
|
+
"button",
|
|
711
|
+
{
|
|
712
|
+
onClick: () => setMobileMenuOpen(true),
|
|
713
|
+
className: "inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-accent md:hidden",
|
|
714
|
+
"aria-label": "Open menu",
|
|
715
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
|
|
716
|
+
}
|
|
717
|
+
),
|
|
718
|
+
pageTitle && /* @__PURE__ */ jsx("h2", { className: "font-semibold text-lg", children: pageTitle }),
|
|
719
|
+
topbarStart,
|
|
720
|
+
/* @__PURE__ */ jsx("div", { ref: setHeaderSlot, className: "flex min-w-0 flex-1 items-center" })
|
|
721
|
+
] }),
|
|
722
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
723
|
+
/* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex items-center gap-2" }),
|
|
724
|
+
topbarEnd
|
|
725
|
+
] })
|
|
726
|
+
] }),
|
|
727
|
+
/* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto", children }),
|
|
728
|
+
/* @__PURE__ */ jsx(SaveBar, {})
|
|
729
|
+
] }),
|
|
730
|
+
mobileMenuOpen && /* @__PURE__ */ jsx(
|
|
731
|
+
MobileOverlay,
|
|
732
|
+
{
|
|
733
|
+
navigation,
|
|
734
|
+
logo,
|
|
735
|
+
user,
|
|
736
|
+
currentPath,
|
|
737
|
+
onNavigate,
|
|
738
|
+
onSignOut,
|
|
739
|
+
onProfile,
|
|
740
|
+
onSettings,
|
|
741
|
+
onBilling,
|
|
742
|
+
orgSwitcher,
|
|
743
|
+
topContent: sidebarTopContent,
|
|
744
|
+
footerContent: sidebarFooterContent,
|
|
745
|
+
userMenuSlot,
|
|
746
|
+
notificationSlot,
|
|
747
|
+
unreadCount,
|
|
748
|
+
onClose: () => setMobileMenuOpen(false)
|
|
749
|
+
}
|
|
750
|
+
)
|
|
751
|
+
] }) }) }) });
|
|
752
|
+
}
|
|
753
|
+
function TopbarLayout({
|
|
754
|
+
navigation = [],
|
|
755
|
+
logo,
|
|
756
|
+
user,
|
|
757
|
+
children,
|
|
758
|
+
onNavigate,
|
|
759
|
+
onSignOut,
|
|
760
|
+
onProfile,
|
|
761
|
+
onSettings,
|
|
762
|
+
onBilling,
|
|
763
|
+
userMenuExtras,
|
|
764
|
+
frame,
|
|
765
|
+
currentPath,
|
|
766
|
+
topbarStart,
|
|
767
|
+
topbarEnd
|
|
768
|
+
}) {
|
|
769
|
+
const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
|
|
770
|
+
return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsxs("div", { className: "relative flex h-screen flex-col overflow-hidden bg-background", children: [
|
|
771
|
+
/* @__PURE__ */ jsx(
|
|
772
|
+
Topbar,
|
|
773
|
+
{
|
|
774
|
+
navigation,
|
|
775
|
+
logo,
|
|
776
|
+
user,
|
|
777
|
+
currentPath,
|
|
778
|
+
onNavigate,
|
|
779
|
+
onSignOut,
|
|
780
|
+
onProfile,
|
|
781
|
+
onSettings,
|
|
782
|
+
onBilling,
|
|
783
|
+
userMenuExtras,
|
|
784
|
+
leftContent: topbarStart,
|
|
785
|
+
rightContent: topbarEnd,
|
|
786
|
+
onMenuClick: () => setMobileMenuOpen(true)
|
|
787
|
+
}
|
|
788
|
+
),
|
|
789
|
+
/* @__PURE__ */ jsx("main", { className: cn("flex-1 overflow-y-auto", frame && "md:p-2"), children: /* @__PURE__ */ jsx("div", { className: cn("min-h-full", frame && "md:rounded-xl md:border md:border-border md:bg-card"), children }) }),
|
|
790
|
+
/* @__PURE__ */ jsx(SaveBar, {}),
|
|
791
|
+
mobileMenuOpen && /* @__PURE__ */ jsx(
|
|
792
|
+
MobileOverlay,
|
|
793
|
+
{
|
|
794
|
+
navigation,
|
|
795
|
+
logo,
|
|
796
|
+
user,
|
|
797
|
+
currentPath,
|
|
798
|
+
onNavigate,
|
|
799
|
+
onSignOut,
|
|
800
|
+
onProfile,
|
|
801
|
+
onSettings,
|
|
802
|
+
onBilling,
|
|
803
|
+
userMenuSlot: user ? /* @__PURE__ */ jsx(DrawerUserRow, { user }) : void 0,
|
|
804
|
+
onClose: () => setMobileMenuOpen(false)
|
|
805
|
+
}
|
|
806
|
+
)
|
|
807
|
+
] }) });
|
|
808
|
+
}
|
|
809
|
+
function DrawerUserRow({ user }) {
|
|
810
|
+
const label = user.fullName || user.email;
|
|
811
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2 px-1", children: [
|
|
812
|
+
user.avatarUrl ? /* @__PURE__ */ jsx("img", { src: user.avatarUrl, alt: "", className: "h-7 w-7 shrink-0 rounded-full object-cover" }) : /* @__PURE__ */ jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: (label || "?").charAt(0).toUpperCase() }),
|
|
813
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-sidebar-foreground", children: label })
|
|
814
|
+
] });
|
|
815
|
+
}
|
|
816
|
+
function MinimalLayout({
|
|
817
|
+
logo,
|
|
818
|
+
user: _user,
|
|
819
|
+
children,
|
|
820
|
+
headerEnd
|
|
821
|
+
}) {
|
|
822
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-screen flex-col", children: [
|
|
823
|
+
/* @__PURE__ */ jsxs("header", { className: "flex h-14 shrink-0 items-center justify-between border-b border-border bg-card px-4 md:px-6", children: [
|
|
824
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) }),
|
|
825
|
+
headerEnd && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: headerEnd })
|
|
826
|
+
] }),
|
|
827
|
+
/* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto", children })
|
|
828
|
+
] });
|
|
829
|
+
}
|
|
830
|
+
function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
|
|
831
|
+
const [visible, setVisible] = React3.useState(false);
|
|
832
|
+
React3.useEffect(() => {
|
|
833
|
+
const id = requestAnimationFrame(() => setVisible(true));
|
|
834
|
+
return () => cancelAnimationFrame(id);
|
|
835
|
+
}, []);
|
|
836
|
+
const close = React3.useCallback(() => {
|
|
837
|
+
setVisible(false);
|
|
838
|
+
window.setTimeout(onClose, 250);
|
|
839
|
+
}, [onClose]);
|
|
840
|
+
React3.useEffect(() => {
|
|
841
|
+
const previous = document.body.style.overflow;
|
|
842
|
+
document.body.style.overflow = "hidden";
|
|
843
|
+
return () => {
|
|
844
|
+
document.body.style.overflow = previous;
|
|
845
|
+
};
|
|
846
|
+
}, []);
|
|
847
|
+
React3.useEffect(() => {
|
|
848
|
+
const onKey = (e) => {
|
|
849
|
+
if (e.key === "Escape") close();
|
|
850
|
+
};
|
|
851
|
+
window.addEventListener("keydown", onKey);
|
|
852
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
853
|
+
}, [close]);
|
|
854
|
+
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[60] md:hidden", children: [
|
|
855
|
+
/* @__PURE__ */ jsx(
|
|
856
|
+
"div",
|
|
857
|
+
{
|
|
858
|
+
className: cn(
|
|
859
|
+
"absolute inset-0 bg-black/50 transition-opacity duration-300 ease-out",
|
|
860
|
+
visible ? "opacity-100" : "opacity-0"
|
|
861
|
+
),
|
|
862
|
+
onClick: close
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsx(
|
|
866
|
+
"div",
|
|
867
|
+
{
|
|
868
|
+
className: cn(
|
|
869
|
+
"absolute inset-y-0 left-0 shadow-2xl transition-transform duration-300 ease-out will-change-transform",
|
|
870
|
+
visible ? "translate-x-0" : "-translate-x-full"
|
|
871
|
+
),
|
|
872
|
+
children: /* @__PURE__ */ jsx(
|
|
873
|
+
Sidebar,
|
|
874
|
+
{
|
|
875
|
+
...sidebarProps,
|
|
876
|
+
collapsed: false,
|
|
877
|
+
onToggle: close,
|
|
878
|
+
borderless: true,
|
|
879
|
+
onNavigate: (route) => {
|
|
880
|
+
onNavigate?.(route);
|
|
881
|
+
close();
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
)
|
|
885
|
+
}
|
|
886
|
+
)
|
|
887
|
+
] });
|
|
888
|
+
}
|
|
889
|
+
function AppShell({
|
|
890
|
+
variant,
|
|
891
|
+
contentFrame,
|
|
892
|
+
navigation = [],
|
|
893
|
+
logo,
|
|
894
|
+
user,
|
|
895
|
+
children,
|
|
896
|
+
onNavigate,
|
|
897
|
+
onSignOut,
|
|
898
|
+
onProfile,
|
|
899
|
+
onSettings,
|
|
900
|
+
onBilling,
|
|
901
|
+
pageTitle,
|
|
902
|
+
currentPath,
|
|
903
|
+
userMenuExtras,
|
|
904
|
+
orgSwitcher,
|
|
905
|
+
topbarStart,
|
|
906
|
+
topbarEnd,
|
|
907
|
+
sidebarTopContent,
|
|
908
|
+
sidebarFooterContent,
|
|
909
|
+
userMenuSlot,
|
|
910
|
+
notificationSlot,
|
|
911
|
+
unreadCount = 0
|
|
912
|
+
}) {
|
|
913
|
+
switch (variant) {
|
|
914
|
+
case "sidebar":
|
|
915
|
+
return /* @__PURE__ */ jsx(
|
|
916
|
+
SidebarLayout,
|
|
917
|
+
{
|
|
918
|
+
navigation,
|
|
919
|
+
logo,
|
|
920
|
+
user,
|
|
921
|
+
onNavigate,
|
|
922
|
+
onSignOut,
|
|
923
|
+
onProfile,
|
|
924
|
+
onSettings,
|
|
925
|
+
onBilling,
|
|
926
|
+
userMenuExtras,
|
|
927
|
+
orgSwitcher,
|
|
928
|
+
sidebarTopContent,
|
|
929
|
+
sidebarFooterContent,
|
|
930
|
+
frame: contentFrame,
|
|
931
|
+
currentPath,
|
|
932
|
+
pageTitle,
|
|
933
|
+
topbarStart,
|
|
934
|
+
topbarEnd,
|
|
935
|
+
userMenuSlot,
|
|
936
|
+
notificationSlot,
|
|
937
|
+
unreadCount,
|
|
938
|
+
children
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
case "topbar":
|
|
942
|
+
return /* @__PURE__ */ jsx(
|
|
943
|
+
TopbarLayout,
|
|
944
|
+
{
|
|
945
|
+
navigation,
|
|
946
|
+
logo,
|
|
947
|
+
user,
|
|
948
|
+
onNavigate,
|
|
949
|
+
onSignOut,
|
|
950
|
+
onProfile,
|
|
951
|
+
onSettings,
|
|
952
|
+
onBilling,
|
|
953
|
+
userMenuExtras,
|
|
954
|
+
frame: contentFrame,
|
|
955
|
+
currentPath,
|
|
956
|
+
topbarStart,
|
|
957
|
+
topbarEnd,
|
|
958
|
+
children
|
|
959
|
+
}
|
|
960
|
+
);
|
|
961
|
+
case "minimal":
|
|
962
|
+
return /* @__PURE__ */ jsx(MinimalLayout, { logo, user, headerEnd: topbarEnd, children });
|
|
963
|
+
default: {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
var NavTransitionContext = React3.createContext("slide");
|
|
969
|
+
function NavTransitionProvider({ value, children }) {
|
|
970
|
+
return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
|
|
971
|
+
}
|
|
972
|
+
function useNavTransition() {
|
|
973
|
+
return React3.useContext(NavTransitionContext);
|
|
974
|
+
}
|
|
975
|
+
function resolveTransitionClass(transition, direction) {
|
|
976
|
+
if (transition === "none") return "";
|
|
977
|
+
if (transition === "fade") return "saas-page-enter";
|
|
978
|
+
if (direction === "back") return "saas-nav-back";
|
|
979
|
+
if (direction === "forward") return "saas-nav-forward";
|
|
980
|
+
return "saas-page-enter";
|
|
981
|
+
}
|
|
982
|
+
function PageTransition({
|
|
983
|
+
transitionKey,
|
|
984
|
+
direction,
|
|
985
|
+
className,
|
|
986
|
+
children
|
|
987
|
+
}) {
|
|
988
|
+
const transition = useNavTransition();
|
|
989
|
+
const animClass = resolveTransitionClass(transition, direction);
|
|
990
|
+
return /* @__PURE__ */ jsx("div", { className: cn(animClass, className), children }, transitionKey);
|
|
991
|
+
}
|
|
992
|
+
function PageHeaderActions({ children }) {
|
|
993
|
+
const slot = useModuleHeaderActionsSlot();
|
|
994
|
+
if (slot) return createPortal(children, slot);
|
|
995
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
|
|
996
|
+
}
|
|
997
|
+
var ModuleLayoutContext = React3.createContext("rail");
|
|
998
|
+
function ModuleLayoutProvider({ variant, children }) {
|
|
999
|
+
return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
|
|
1000
|
+
}
|
|
1001
|
+
function useModuleLayout() {
|
|
1002
|
+
return React3.useContext(ModuleLayoutContext);
|
|
1003
|
+
}
|
|
1004
|
+
function NavItem2({ item }) {
|
|
1005
|
+
const [expanded, setExpanded] = React3.useState(true);
|
|
1006
|
+
const Icon = item.icon ? ICON_MAP2[item.icon] ?? null : null;
|
|
1007
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
1008
|
+
const hasActiveChild = hasChildren && item.children.some((c) => c.active);
|
|
1009
|
+
const isActive = item.active || hasActiveChild;
|
|
1010
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1011
|
+
/* @__PURE__ */ jsxs(
|
|
1012
|
+
"button",
|
|
1013
|
+
{
|
|
1014
|
+
type: "button",
|
|
1015
|
+
onClick: () => hasChildren ? setExpanded(!expanded) : item.onClick?.(),
|
|
1016
|
+
className: cn(
|
|
1017
|
+
"flex items-center gap-2 w-full rounded-md px-2.5 py-1.5 text-sm transition-colors",
|
|
1018
|
+
isActive ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
1019
|
+
),
|
|
1020
|
+
children: [
|
|
1021
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
1022
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: item.label }),
|
|
1023
|
+
hasChildren && (expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }))
|
|
1024
|
+
]
|
|
1025
|
+
}
|
|
1026
|
+
),
|
|
1027
|
+
hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2", children: item.children.map((child) => /* @__PURE__ */ jsx(
|
|
1028
|
+
"button",
|
|
1029
|
+
{
|
|
1030
|
+
type: "button",
|
|
1031
|
+
onClick: child.onClick,
|
|
1032
|
+
className: cn(
|
|
1033
|
+
"flex items-center w-full rounded-md px-2.5 py-1 text-xs transition-colors",
|
|
1034
|
+
child.active ? "text-primary font-medium bg-primary/5" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
1035
|
+
),
|
|
1036
|
+
children: child.label
|
|
1037
|
+
},
|
|
1038
|
+
child.id
|
|
1039
|
+
)) })
|
|
1040
|
+
] });
|
|
1041
|
+
}
|
|
1042
|
+
function MobileTabs({ nav }) {
|
|
1043
|
+
const scrollRef = React3.useRef(null);
|
|
1044
|
+
const [expandedId, setExpandedId] = React3.useState(null);
|
|
1045
|
+
React3.useEffect(() => {
|
|
1046
|
+
const container = scrollRef.current;
|
|
1047
|
+
if (!container) return;
|
|
1048
|
+
const activeEl = container.querySelector('[data-active="true"]');
|
|
1049
|
+
if (activeEl) {
|
|
1050
|
+
const left = activeEl.offsetLeft - container.offsetWidth / 2 + activeEl.offsetWidth / 2;
|
|
1051
|
+
container.scrollTo({ left: Math.max(0, left), behavior: "smooth" });
|
|
1052
|
+
}
|
|
1053
|
+
}, [nav]);
|
|
1054
|
+
return /* @__PURE__ */ jsxs("div", { className: "md:hidden -mx-1 mb-4 no-print", children: [
|
|
1055
|
+
/* @__PURE__ */ jsx("div", { ref: scrollRef, className: "flex gap-1 px-1 pb-2 overflow-x-auto scrollbar-hide", children: nav.map((item) => {
|
|
1056
|
+
const Icon = item.icon ? ICON_MAP2[item.icon] ?? null : null;
|
|
1057
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
1058
|
+
const isActive = item.active || item.children?.some((c) => c.active);
|
|
1059
|
+
const isExpanded = expandedId === item.id;
|
|
1060
|
+
return /* @__PURE__ */ jsxs(
|
|
1061
|
+
"button",
|
|
1062
|
+
{
|
|
1063
|
+
type: "button",
|
|
1064
|
+
"data-active": isActive || void 0,
|
|
1065
|
+
onClick: () => {
|
|
1066
|
+
if (hasChildren) {
|
|
1067
|
+
setExpandedId(isExpanded ? null : item.id);
|
|
1068
|
+
} else {
|
|
1069
|
+
item.onClick?.();
|
|
1070
|
+
setExpandedId(null);
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
className: cn(
|
|
1074
|
+
"flex items-center gap-1.5 whitespace-nowrap rounded-full px-3 py-1.5 text-xs font-medium transition-colors shrink-0",
|
|
1075
|
+
isActive ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"
|
|
1076
|
+
),
|
|
1077
|
+
children: [
|
|
1078
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3" }),
|
|
1079
|
+
item.label,
|
|
1080
|
+
hasChildren && /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-2.5 w-2.5 transition-transform", isExpanded && "rotate-180") })
|
|
1081
|
+
]
|
|
1082
|
+
},
|
|
1083
|
+
item.id
|
|
1084
|
+
);
|
|
1085
|
+
}) }),
|
|
1086
|
+
expandedId && (() => {
|
|
1087
|
+
const item = nav.find((n) => n.id === expandedId);
|
|
1088
|
+
if (!item?.children) return null;
|
|
1089
|
+
return /* @__PURE__ */ jsx("div", { className: "flex gap-1 px-2 pb-2 animate-in fade-in-0 slide-in-from-top-1", children: item.children.map((child) => /* @__PURE__ */ jsx(
|
|
1090
|
+
"button",
|
|
1091
|
+
{
|
|
1092
|
+
type: "button",
|
|
1093
|
+
onClick: () => {
|
|
1094
|
+
child.onClick?.();
|
|
1095
|
+
setExpandedId(null);
|
|
1096
|
+
},
|
|
1097
|
+
className: cn(
|
|
1098
|
+
"whitespace-nowrap rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors shrink-0",
|
|
1099
|
+
child.active ? "bg-foreground/10 text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
1100
|
+
),
|
|
1101
|
+
children: child.label
|
|
1102
|
+
},
|
|
1103
|
+
child.id
|
|
1104
|
+
)) });
|
|
1105
|
+
})()
|
|
1106
|
+
] });
|
|
1107
|
+
}
|
|
1108
|
+
var BackStyleContext = React3.createContext("link");
|
|
1109
|
+
function BackStyleProvider({ style, children }) {
|
|
1110
|
+
return /* @__PURE__ */ jsx(BackStyleContext.Provider, { value: style, children });
|
|
1111
|
+
}
|
|
1112
|
+
function useBackStyle() {
|
|
1113
|
+
return React3.useContext(BackStyleContext);
|
|
1114
|
+
}
|
|
1115
|
+
function SubpageHeader({ title, subtitle, icon, onBack, parentLabel, actions, backStyle }) {
|
|
1116
|
+
const t = useTranslation();
|
|
1117
|
+
const appStyle = useBackStyle();
|
|
1118
|
+
const { onBack: effectiveOnBack, parentLabel: effectiveParentLabel } = useCrossModuleBack(onBack, parentLabel);
|
|
1119
|
+
useBackHandler(effectiveOnBack);
|
|
1120
|
+
const Icon = icon ? ICON_MAP2[icon] ?? null : null;
|
|
1121
|
+
const style = !effectiveOnBack ? "icon" : backStyle ?? appStyle;
|
|
1122
|
+
const effectiveStyle = style !== "icon" && !effectiveParentLabel ? "icon" : style;
|
|
1123
|
+
const titleBlock = /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
1124
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1125
|
+
effectiveStyle === "icon" && effectiveOnBack && /* @__PURE__ */ jsx(
|
|
1126
|
+
"button",
|
|
1127
|
+
{
|
|
1128
|
+
onClick: effectiveOnBack,
|
|
1129
|
+
className: "flex h-8 w-8 items-center justify-center rounded-lg border hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors",
|
|
1130
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
Icon && /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-muted", children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-muted-foreground" }) }),
|
|
1134
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1135
|
+
/* @__PURE__ */ jsx("h2", { className: "text-xl font-bold", children: title }),
|
|
1136
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
1137
|
+
] })
|
|
1138
|
+
] }),
|
|
1139
|
+
actions && /* @__PURE__ */ jsx("div", { className: "no-print", children: actions })
|
|
1140
|
+
] });
|
|
1141
|
+
if (effectiveStyle === "breadcrumb") {
|
|
1142
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4 mb-6", children: [
|
|
1143
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
1144
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
1145
|
+
/* @__PURE__ */ jsx("button", { onClick: effectiveOnBack, className: "hover:text-foreground transition-colors", children: effectiveParentLabel }),
|
|
1146
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" }),
|
|
1147
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: title })
|
|
1148
|
+
] }),
|
|
1149
|
+
actions && /* @__PURE__ */ jsx("div", { className: "no-print", children: actions })
|
|
1150
|
+
] }),
|
|
1151
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground -mt-2", children: subtitle })
|
|
1152
|
+
] });
|
|
1153
|
+
}
|
|
1154
|
+
if (effectiveStyle === "link") {
|
|
1155
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3 mb-6", children: [
|
|
1156
|
+
/* @__PURE__ */ jsxs(
|
|
1157
|
+
"button",
|
|
1158
|
+
{
|
|
1159
|
+
onClick: effectiveOnBack,
|
|
1160
|
+
className: "inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors",
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }),
|
|
1163
|
+
t("crud.detail.backTo", { entities: effectiveParentLabel })
|
|
1164
|
+
]
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
titleBlock
|
|
1168
|
+
] });
|
|
1169
|
+
}
|
|
1170
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-4 mb-6", children: titleBlock });
|
|
1171
|
+
}
|
|
1172
|
+
function ModuleHeader({ nav }) {
|
|
1173
|
+
const slot = useModuleHeaderSlot();
|
|
1174
|
+
function defaultChild(item) {
|
|
1175
|
+
const kids = item.children ?? [];
|
|
1176
|
+
return kids.find((c) => /list/i.test(c.id) || /^list$/i.test(c.label)) ?? kids[kids.length - 1];
|
|
1177
|
+
}
|
|
1178
|
+
const content = /* @__PURE__ */ jsx("div", { className: "flex w-full min-w-0 items-center gap-4", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 items-center gap-0.5 overflow-x-auto scrollbar-hide", children: nav.map((item) => {
|
|
1179
|
+
const Icon = item.icon ? ICON_MAP2[item.icon] ?? null : null;
|
|
1180
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
1181
|
+
const isActive = item.active || item.children?.some((c) => c.active);
|
|
1182
|
+
return /* @__PURE__ */ jsxs(
|
|
1183
|
+
"button",
|
|
1184
|
+
{
|
|
1185
|
+
type: "button",
|
|
1186
|
+
onClick: () => hasChildren ? defaultChild(item)?.onClick?.() : item.onClick?.(),
|
|
1187
|
+
className: cn(
|
|
1188
|
+
"flex shrink-0 items-center gap-1.5 whitespace-nowrap border-b-2 px-2.5 py-1.5 text-sm font-medium transition-colors",
|
|
1189
|
+
isActive ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
|
|
1190
|
+
),
|
|
1191
|
+
children: [
|
|
1192
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
|
|
1193
|
+
item.label
|
|
1194
|
+
]
|
|
1195
|
+
},
|
|
1196
|
+
item.id
|
|
1197
|
+
);
|
|
1198
|
+
}) }) });
|
|
1199
|
+
if (slot) return createPortal(content, slot);
|
|
1200
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-5 border-b border-border pb-2", children: content });
|
|
1201
|
+
}
|
|
1202
|
+
function ModulePage({ title, subtitle, nav, children, className, headerAction, showHeader = true, sidebarFooter, navVariant, viewKey, direction }) {
|
|
1203
|
+
const ctxVariant = useModuleLayout();
|
|
1204
|
+
const variant = navVariant ?? ctxVariant;
|
|
1205
|
+
const transitionKey = viewKey ?? "view";
|
|
1206
|
+
if (variant === "tabs") {
|
|
1207
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1208
|
+
/* @__PURE__ */ jsx(ModuleHeader, { nav }),
|
|
1209
|
+
showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
|
|
1210
|
+
/* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, className: cn("min-w-0", className), children })
|
|
1211
|
+
] });
|
|
1212
|
+
}
|
|
1213
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-6 -mt-2", className), children: [
|
|
1214
|
+
/* @__PURE__ */ jsx("div", { className: "w-48 shrink-0 hidden md:block no-print", children: /* @__PURE__ */ jsxs("div", { className: cn(sidebarFooter && "sticky top-4 flex flex-col"), style: sidebarFooter ? { height: "calc(100vh - 8rem)" } : void 0, children: [
|
|
1215
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1216
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider px-2.5 mb-2", children: title }),
|
|
1217
|
+
/* @__PURE__ */ jsx("nav", { className: "space-y-0.5", children: nav.map((item) => /* @__PURE__ */ jsx(NavItem2, { item }, item.id)) })
|
|
1218
|
+
] }),
|
|
1219
|
+
sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto", children: sidebarFooter })
|
|
1220
|
+
] }) }),
|
|
1221
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1222
|
+
showHeader && /* @__PURE__ */ jsxs("div", { className: "mb-6 flex items-start justify-between gap-3", children: [
|
|
1223
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1224
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children: title }),
|
|
1225
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
1226
|
+
] }),
|
|
1227
|
+
headerAction
|
|
1228
|
+
] }),
|
|
1229
|
+
/* @__PURE__ */ jsx(MobileTabs, { nav }),
|
|
1230
|
+
/* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
|
|
1231
|
+
] })
|
|
1232
|
+
] });
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
export { AppShell, BackStyleProvider, ICON_MAP, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeaderActions, PageTransition, Sidebar, SubpageHeader, Topbar, useBackStyle, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition };
|
|
1236
|
+
//# sourceMappingURL=chunk-CZ6X6PZT.js.map
|
|
1237
|
+
//# sourceMappingURL=chunk-CZ6X6PZT.js.map
|