@classytic/fluid 0.2.4 → 0.3.2

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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -62
  3. package/dist/api-pagination-CJ0vR_w6.d.mts +34 -0
  4. package/dist/api-pagination-DBTE0yk4.mjs +190 -0
  5. package/dist/chunk-DQk6qfdC.mjs +18 -0
  6. package/dist/client/calendar.d.mts +105 -0
  7. package/dist/client/calendar.mjs +202 -0
  8. package/dist/client/core.d.mts +1614 -0
  9. package/dist/client/core.mjs +2779 -0
  10. package/dist/client/error.d.mts +125 -0
  11. package/dist/client/error.mjs +166 -0
  12. package/dist/client/hooks.d.mts +162 -0
  13. package/dist/client/hooks.mjs +447 -0
  14. package/dist/client/table.d.mts +84 -0
  15. package/dist/client/table.mjs +373 -0
  16. package/dist/client/theme.d.mts +6 -0
  17. package/dist/client/theme.mjs +65 -0
  18. package/dist/command.d.mts +134 -0
  19. package/dist/command.mjs +132 -0
  20. package/dist/compact.d.mts +359 -0
  21. package/dist/compact.mjs +892 -0
  22. package/dist/dashboard.d.mts +778 -0
  23. package/dist/dashboard.mjs +1617 -0
  24. package/dist/filter-utils-DqMmy_v-.mjs +72 -0
  25. package/dist/filter-utils-IZ0GtuPo.d.mts +40 -0
  26. package/dist/forms.d.mts +1549 -0
  27. package/dist/forms.mjs +3740 -0
  28. package/dist/index.d.mts +296 -0
  29. package/dist/index.mjs +432 -0
  30. package/dist/layouts.d.mts +215 -0
  31. package/dist/layouts.mjs +460 -0
  32. package/dist/search-context-DR7DBs7S.mjs +19 -0
  33. package/dist/search.d.mts +254 -0
  34. package/dist/search.mjs +523 -0
  35. package/dist/sheet-wrapper-CWNCvYMD.mjs +211 -0
  36. package/dist/use-base-search-BGgWnWaF.d.mts +35 -0
  37. package/dist/use-debounce-xmZucz5e.mjs +53 -0
  38. package/dist/use-keyboard-shortcut-Bl6YM5Q7.mjs +82 -0
  39. package/dist/use-keyboard-shortcut-_mRCh3QO.d.mts +24 -0
  40. package/dist/use-media-query-BnVNIKT4.mjs +17 -0
  41. package/dist/use-mobile-BX3SQVo2.mjs +20 -0
  42. package/dist/use-scroll-detection-CsgsQYvy.mjs +43 -0
  43. package/dist/utils-CDue7cEt.d.mts +6 -0
  44. package/dist/utils-DQ5SCVoW.mjs +10 -0
  45. package/package.json +85 -45
  46. package/styles.css +2 -2
  47. package/dist/chunk-GUHK2DTW.js +0 -15
  48. package/dist/chunk-GUHK2DTW.js.map +0 -1
  49. package/dist/chunk-H3NFL3GJ.js +0 -57
  50. package/dist/chunk-H3NFL3GJ.js.map +0 -1
  51. package/dist/chunk-J2YRTQE4.js +0 -293
  52. package/dist/chunk-J2YRTQE4.js.map +0 -1
  53. package/dist/compact.d.ts +0 -217
  54. package/dist/compact.js +0 -986
  55. package/dist/compact.js.map +0 -1
  56. package/dist/dashboard.d.ts +0 -387
  57. package/dist/dashboard.js +0 -1032
  58. package/dist/dashboard.js.map +0 -1
  59. package/dist/index.d.ts +0 -2140
  60. package/dist/index.js +0 -6422
  61. package/dist/index.js.map +0 -1
  62. package/dist/layout.d.ts +0 -25
  63. package/dist/layout.js +0 -4
  64. package/dist/layout.js.map +0 -1
  65. package/dist/search.d.ts +0 -172
  66. package/dist/search.js +0 -341
  67. package/dist/search.js.map +0 -1
  68. package/dist/use-base-search-AS5Z3SAy.d.ts +0 -64
  69. package/dist/utils-Cbsgs0XP.d.ts +0 -5
@@ -0,0 +1,1617 @@
1
+ "use client";
2
+
3
+ import { t as cn } from "./utils-DQ5SCVoW.mjs";
4
+ import { t as useIsMobile } from "./use-mobile-BX3SQVo2.mjs";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { Skeleton } from "@/components/ui/skeleton";
7
+ import * as React$1 from "react";
8
+ import React, { Suspense, useState } from "react";
9
+ import { Building2, Check, ChevronLeft, ChevronRight, ChevronsUpDown, CircleUserRound, LogOut, Menu } from "lucide-react";
10
+ import { Button } from "@/components/ui/button";
11
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
12
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
13
+ import { Badge } from "@/components/ui/badge";
14
+ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
15
+ import { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
16
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
17
+ import { Separator } from "@/components/ui/separator";
18
+ import Link from "next/link";
19
+ import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb";
20
+ import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarRail, SidebarTrigger, useSidebar } from "@/components/ui/sidebar";
21
+
22
+ //#region src/dashboard/nav-utils.ts
23
+ /** Check hidden flag, then canAccess(ctx) */
24
+ function isItemVisible(item, ctx) {
25
+ if (item.hidden) return false;
26
+ if (item.canAccess && !item.canAccess(ctx)) return false;
27
+ return true;
28
+ }
29
+ /** Resolve badgeCount(ctx), falling back to static badge */
30
+ function resolveBadge(item, ctx) {
31
+ if (item.badgeCount) {
32
+ const value = item.badgeCount(ctx);
33
+ if (value !== void 0) return {
34
+ ...item,
35
+ badge: value
36
+ };
37
+ }
38
+ return item;
39
+ }
40
+ /**
41
+ * resolveNavigation — Filter NavGroup[] by permissions and resolve dynamic badges.
42
+ * For InsetSidebar, FloatingSidebar, and any component using NavGroup[].
43
+ *
44
+ * When `ctx` is omitted, only `hidden` checks apply (backwards-compat).
45
+ */
46
+ function resolveNavigation(groups, ctx) {
47
+ const result = [];
48
+ for (const group of groups) {
49
+ const filteredItems = [];
50
+ for (const item of group.items) {
51
+ if (ctx !== void 0 && !isItemVisible(item, ctx)) continue;
52
+ if (ctx === void 0 && item.hidden) continue;
53
+ let resolved = ctx !== void 0 ? resolveBadge(item, ctx) : item;
54
+ if (resolved.items && resolved.items.length > 0) {
55
+ const filteredSubs = resolved.items.filter((sub) => {
56
+ if (ctx !== void 0) return isItemVisible(sub, ctx);
57
+ return !sub.hidden;
58
+ }).map((sub) => ctx !== void 0 ? resolveBadge(sub, ctx) : sub);
59
+ resolved = {
60
+ ...resolved,
61
+ items: filteredSubs
62
+ };
63
+ }
64
+ filteredItems.push(resolved);
65
+ }
66
+ if (filteredItems.length > 0) result.push({
67
+ ...group,
68
+ items: filteredItems
69
+ });
70
+ }
71
+ return result;
72
+ }
73
+ /**
74
+ * resolveMiniNavigation — Filter MiniSidebarGroup[] by permissions.
75
+ */
76
+ function resolveMiniNavigation(groups, ctx) {
77
+ const result = [];
78
+ for (const group of groups) {
79
+ const filteredItems = group.items.filter((item) => {
80
+ if (ctx !== void 0) return isItemVisible(item, ctx);
81
+ return !item.hidden;
82
+ }).map((item) => ctx !== void 0 ? resolveBadge(item, ctx) : item);
83
+ if (filteredItems.length > 0) result.push({
84
+ ...group,
85
+ items: filteredItems
86
+ });
87
+ }
88
+ return result;
89
+ }
90
+ /**
91
+ * resolveCategories — Filter category arrays by permissions.
92
+ * Works with DualSidebarCategory[] and TopbarRailCategory[].
93
+ */
94
+ function resolveCategories(categories, ctx) {
95
+ const result = [];
96
+ for (const category of categories) {
97
+ if (ctx !== void 0 && !isItemVisible(category, ctx)) continue;
98
+ if (ctx === void 0 && category.hidden) continue;
99
+ const filteredItems = category.items.filter((item) => {
100
+ if (ctx !== void 0) return isItemVisible(item, ctx);
101
+ return !item.hidden;
102
+ }).map((item) => ctx !== void 0 ? resolveBadge(item, ctx) : item);
103
+ if (filteredItems.length > 0) result.push({
104
+ ...category,
105
+ items: filteredItems
106
+ });
107
+ }
108
+ return result;
109
+ }
110
+
111
+ //#endregion
112
+ //#region src/dashboard/header-section.tsx
113
+ const variants = {
114
+ default: {
115
+ wrapper: "px-6 py-5 rounded-xl shadow-sm border bg-background hover:shadow-md",
116
+ title: "text-2xl font-semibold tracking-tight",
117
+ description: "text-sm text-muted-foreground",
118
+ iconSize: "size-10",
119
+ iconInner: "size-5",
120
+ spacing: "space-y-1"
121
+ },
122
+ compact: {
123
+ wrapper: "px-4 py-3 rounded-lg border bg-background/50",
124
+ title: "text-lg font-semibold",
125
+ description: "text-xs text-muted-foreground",
126
+ iconSize: "size-8",
127
+ iconInner: "size-4",
128
+ spacing: "space-y-0.5"
129
+ },
130
+ hero: {
131
+ wrapper: "px-8 py-8 rounded-2xl shadow-lg border bg-gradient-to-br from-background to-muted/20",
132
+ title: "text-3xl font-bold tracking-tight bg-gradient-to-r from-foreground to-foreground/70 bg-clip-text text-transparent",
133
+ description: "text-base text-muted-foreground mt-2",
134
+ iconSize: "size-14",
135
+ iconInner: "size-7",
136
+ spacing: "space-y-2"
137
+ },
138
+ minimal: {
139
+ wrapper: "px-0 py-2",
140
+ title: "text-xl font-medium",
141
+ description: "text-sm text-muted-foreground",
142
+ iconSize: "size-8",
143
+ iconInner: "size-4",
144
+ spacing: "space-y-0.5"
145
+ }
146
+ };
147
+ function HeaderSection({ title, description, actions = null, icon: Icon = null, iconClassName, loading = false, variant = "default", className, badge, breadcrumbs, metadata, children }) {
148
+ const currentVariant = variants[variant] || variants.default;
149
+ const isBadgeObject = (badge) => {
150
+ return typeof badge === "object" && badge !== null && "text" in badge;
151
+ };
152
+ if (loading && !title) return /* @__PURE__ */ jsx("div", {
153
+ className: cn(currentVariant.wrapper, "transition-all duration-300", className),
154
+ children: /* @__PURE__ */ jsxs("div", {
155
+ className: "flex flex-col sm:flex-row sm:items-center sm:justify-between",
156
+ children: [/* @__PURE__ */ jsxs("div", {
157
+ className: "flex items-center gap-4",
158
+ children: [Icon && /* @__PURE__ */ jsx(Skeleton, { className: cn(currentVariant.iconSize, "rounded-lg") }), /* @__PURE__ */ jsxs("div", {
159
+ className: currentVariant.spacing,
160
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-48" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-64 mt-1" })]
161
+ })]
162
+ }), actions && /* @__PURE__ */ jsxs("div", {
163
+ className: "flex gap-2 mt-4 sm:mt-0",
164
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-24" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-24" })]
165
+ })]
166
+ })
167
+ });
168
+ return /* @__PURE__ */ jsxs("div", {
169
+ className: cn("transition-all duration-300", currentVariant.wrapper, className),
170
+ children: [
171
+ breadcrumbs && /* @__PURE__ */ jsx("nav", {
172
+ className: "mb-3 text-sm text-muted-foreground",
173
+ children: breadcrumbs
174
+ }),
175
+ /* @__PURE__ */ jsxs("div", {
176
+ className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4",
177
+ children: [/* @__PURE__ */ jsxs("div", {
178
+ className: "flex items-start sm:items-center gap-4",
179
+ children: [Icon && /* @__PURE__ */ jsx("div", {
180
+ className: cn("flex aspect-square items-center justify-center rounded-lg flex-shrink-0", "bg-primary/10 text-primary", currentVariant.iconSize, iconClassName),
181
+ children: /* @__PURE__ */ jsx(Icon, { className: currentVariant.iconInner })
182
+ }), /* @__PURE__ */ jsxs("div", {
183
+ className: cn("flex-1", currentVariant.spacing),
184
+ children: [
185
+ /* @__PURE__ */ jsxs("div", {
186
+ className: "flex items-center gap-2 flex-wrap",
187
+ children: [/* @__PURE__ */ jsx("h1", {
188
+ className: cn("leading-none", currentVariant.title),
189
+ children: title
190
+ }), badge && (isBadgeObject(badge) ? /* @__PURE__ */ jsx(Badge, {
191
+ variant: badge.variant || "secondary",
192
+ className: cn("ml-2", badge.className),
193
+ children: badge.text
194
+ }) : badge)]
195
+ }),
196
+ description && /* @__PURE__ */ jsx("p", {
197
+ className: currentVariant.description,
198
+ children: description
199
+ }),
200
+ metadata && /* @__PURE__ */ jsx("div", {
201
+ className: "flex items-center gap-4 mt-2 text-xs text-muted-foreground",
202
+ children: metadata.map((item, index) => /* @__PURE__ */ jsxs("div", {
203
+ className: "flex items-center gap-1",
204
+ children: [item.icon && /* @__PURE__ */ jsx(item.icon, { className: "size-3" }), /* @__PURE__ */ jsx("span", { children: item.text })]
205
+ }, index))
206
+ })
207
+ ]
208
+ })]
209
+ }), actions && /* @__PURE__ */ jsx("div", {
210
+ className: "flex flex-wrap gap-2 mt-4 sm:mt-0",
211
+ children: actions.map((action, index) => {
212
+ const isActionLoading = action.loading ?? false;
213
+ const isDisabled = loading || action.disabled || isActionLoading;
214
+ const displayText = isActionLoading ? action.loadingText || action.text : action.text;
215
+ return /* @__PURE__ */ jsxs(Button, {
216
+ onClick: action.onClick,
217
+ disabled: isDisabled,
218
+ variant: action.variant || "default",
219
+ size: action.size || (variant === "compact" ? "sm" : "default"),
220
+ className: cn(variant === "hero" && "shadow-md hover:shadow-lg", action.className),
221
+ children: [
222
+ action.icon && action.iconPosition !== "right" && /* @__PURE__ */ jsx(action.icon, { className: "size-4 mr-2" }),
223
+ /* @__PURE__ */ jsx("span", { children: displayText }),
224
+ action.icon && action.iconPosition === "right" && /* @__PURE__ */ jsx(action.icon, { className: "size-4 ml-2" })
225
+ ]
226
+ }, index);
227
+ })
228
+ })]
229
+ }),
230
+ children && /* @__PURE__ */ jsx("div", {
231
+ className: cn("mt-4 pt-4 border-t", variant === "minimal" && "border-0 pt-2"),
232
+ children
233
+ })
234
+ ]
235
+ });
236
+ }
237
+
238
+ //#endregion
239
+ //#region src/dashboard/page-header.tsx
240
+ function PageHeader({ items, className, actions }) {
241
+ return /* @__PURE__ */ jsxs("header", {
242
+ className: cn("flex h-12 shrink-0 items-center justify-between gap-2", className),
243
+ children: [/* @__PURE__ */ jsxs("div", {
244
+ className: "flex items-center gap-2",
245
+ children: [
246
+ /* @__PURE__ */ jsx(SidebarTrigger, { className: "-ml-1" }),
247
+ /* @__PURE__ */ jsx(Separator, {
248
+ orientation: "vertical",
249
+ className: "!self-center h-4"
250
+ }),
251
+ /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, { children: items.map((item, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbItem, {
252
+ className: item.current ? "" : "hidden md:block",
253
+ children: item.current ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
254
+ render: /* @__PURE__ */ jsx(Link, { href: item.href || "#" }),
255
+ children: item.label
256
+ })
257
+ }), index < items.length - 1 && /* @__PURE__ */ jsx(BreadcrumbSeparator, { className: "hidden md:block" })] }, `breadcrumb-${index}`)) }) })
258
+ ]
259
+ }), actions]
260
+ });
261
+ }
262
+
263
+ //#endregion
264
+ //#region src/dashboard/dashboard-content.tsx
265
+ const PADDING = {
266
+ none: "",
267
+ sm: "px-2",
268
+ md: "px-4",
269
+ lg: "px-6 lg:px-8"
270
+ };
271
+ /**
272
+ * DashboardContent — Safe content wrapper for sidebar layouts.
273
+ *
274
+ * Prevents the classic flexbox overflow bug where children with
275
+ * `max-w-*` or grid layouts extend beyond the available space
276
+ * (behind the sidebar) by propagating `min-w-0` through the
277
+ * flex chain.
278
+ *
279
+ * **Important**: `SidebarInset` also needs `min-w-0` for the
280
+ * width constraint to propagate correctly from the flex parent.
281
+ * Pass `className="min-w-0"` to `SidebarInset`.
282
+ *
283
+ * @example
284
+ * ```tsx
285
+ * <SidebarProvider>
286
+ * <AppSidebar />
287
+ * <SidebarInset className="min-w-0">
288
+ * <DashboardContent>
289
+ * <PageHeader items={breadcrumbs} />
290
+ * <MyPageContent />
291
+ * </DashboardContent>
292
+ * </SidebarInset>
293
+ * </SidebarProvider>
294
+ * ```
295
+ */
296
+ function DashboardContent({ children, className, container = true, padding = "md" }) {
297
+ const containerClass = container === true ? "@container/main" : typeof container === "string" ? `@container/${container}` : "";
298
+ return /* @__PURE__ */ jsx("div", {
299
+ className: cn("flex flex-1 flex-col min-w-0", className),
300
+ children: /* @__PURE__ */ jsx("div", {
301
+ className: cn("flex flex-1 flex-col gap-2 min-w-0", containerClass, PADDING[padding]),
302
+ children
303
+ })
304
+ });
305
+ }
306
+
307
+ //#endregion
308
+ //#region src/dashboard/dashboard-page-layout.tsx
309
+ const defaultFallback = /* @__PURE__ */ jsx("div", {
310
+ className: "flex items-center justify-center py-12",
311
+ children: /* @__PURE__ */ jsx("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" })
312
+ });
313
+ /**
314
+ * DashboardPageLayout — Standard page shell for dashboard pages.
315
+ * Combines PageHeader (breadcrumbs + actions) with optional Suspense boundary.
316
+ *
317
+ * @example
318
+ * ```tsx
319
+ * <DashboardPageLayout
320
+ * breadcrumbs={[
321
+ * { label: "Dashboard", href: "/dashboard" },
322
+ * { label: "Posts", current: true },
323
+ * ]}
324
+ * actions={<Button>New Post</Button>}
325
+ * fallback={<SkeletonTable rows={5} />}
326
+ * >
327
+ * <PostsList />
328
+ * </DashboardPageLayout>
329
+ * ```
330
+ */
331
+ function DashboardPageLayout({ breadcrumbs, actions, suspense = true, fallback = defaultFallback, className, children }) {
332
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PageHeader, {
333
+ items: breadcrumbs,
334
+ actions
335
+ }), /* @__PURE__ */ jsx("div", {
336
+ className: cn("flex-1", className),
337
+ children: suspense ? /* @__PURE__ */ jsx(Suspense, {
338
+ fallback,
339
+ children
340
+ }) : children
341
+ })] });
342
+ }
343
+
344
+ //#endregion
345
+ //#region src/dashboard/sidebar-brand.tsx
346
+ /**
347
+ * SidebarBrand - Logo and title section for dashboard sidebar.
348
+ * Automatically handles collapsed state styling.
349
+ */
350
+ function SidebarBrand({ title, icon, href = "/", className, tooltip }) {
351
+ const { isMobile, state } = useSidebar();
352
+ const isCollapsed = state === "collapsed";
353
+ return /* @__PURE__ */ jsx(SidebarMenu, {
354
+ className,
355
+ children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
356
+ size: "lg",
357
+ className: "group-data-[collapsible=icon]:p-0!",
358
+ tooltip: isCollapsed ? tooltip || title : void 0,
359
+ render: /* @__PURE__ */ jsx(Link, {
360
+ href,
361
+ className: cn("flex items-center text-sidebar-foreground", isCollapsed && !isMobile && "justify-center")
362
+ }),
363
+ children: [/* @__PURE__ */ jsx("div", {
364
+ className: cn("rounded-lg flex items-center justify-center bg-sidebar-primary text-sidebar-primary-foreground shadow-sm flex-shrink-0 transition-[width,height]", isCollapsed && !isMobile ? "h-6 w-6" : "h-8 w-8"),
365
+ children: icon
366
+ }), /* @__PURE__ */ jsx("span", {
367
+ className: cn("ml-2 font-semibold tracking-tight truncate", !isMobile && isCollapsed && "hidden"),
368
+ children: title
369
+ })]
370
+ }) })
371
+ });
372
+ }
373
+
374
+ //#endregion
375
+ //#region src/dashboard/sidebar-nav.tsx
376
+ /**
377
+ * SidebarNavItem - Single navigation item with optional sub-items.
378
+ */
379
+ function SidebarNavItem({ item, onClick }) {
380
+ const hasSubItems = item.items && item.items.length > 0;
381
+ const Icon = item.icon;
382
+ const [open, setOpen] = useState(item.isActive ?? false);
383
+ if (hasSubItems) return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Collapsible, {
384
+ open,
385
+ onOpenChange: setOpen,
386
+ className: "group/collapsible",
387
+ children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
388
+ render: /* @__PURE__ */ jsx(SidebarMenuButton, {}),
389
+ children: [
390
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
391
+ /* @__PURE__ */ jsx("span", { children: item.title }),
392
+ item.badge && /* @__PURE__ */ jsx("span", {
393
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded",
394
+ children: item.badge
395
+ }),
396
+ /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto h-4 w-4 transition-transform duration-200 group-data-open/collapsible:rotate-90" })
397
+ ]
398
+ }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(SidebarMenuSub, { children: item.items.map((subItem, idx) => /* @__PURE__ */ jsx(SidebarMenuSubItem, { children: /* @__PURE__ */ jsxs(SidebarMenuSubButton, {
399
+ render: /* @__PURE__ */ jsx(Link, { href: subItem.url }),
400
+ isActive: subItem.isActive,
401
+ children: [/* @__PURE__ */ jsx("span", { children: subItem.title }), subItem.badge && /* @__PURE__ */ jsx("span", {
402
+ className: "ml-auto text-xs opacity-60",
403
+ children: subItem.badge
404
+ })]
405
+ }) }, `${item.title}-${subItem.title}-${idx}`)) }) })]
406
+ }) });
407
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(Link, {
408
+ href: item.url,
409
+ className: "w-full",
410
+ children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
411
+ isActive: item.isActive,
412
+ onClick,
413
+ children: [
414
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
415
+ /* @__PURE__ */ jsx("span", { children: item.title }),
416
+ item.badge && /* @__PURE__ */ jsx("span", {
417
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded",
418
+ children: item.badge
419
+ })
420
+ ]
421
+ })
422
+ }) });
423
+ }
424
+ /**
425
+ * SidebarNavGroup - A group of navigation items with optional title.
426
+ */
427
+ function SidebarNavGroup({ title, items, className, onItemClick }) {
428
+ return /* @__PURE__ */ jsxs(SidebarGroup, {
429
+ className,
430
+ children: [title && /* @__PURE__ */ jsx(SidebarGroupLabel, { children: title }), /* @__PURE__ */ jsx(SidebarMenu, { children: items.map((item, idx) => /* @__PURE__ */ jsx(SidebarNavItem, {
431
+ item,
432
+ onClick: () => onItemClick?.(item)
433
+ }, `${item.title}-${idx}`)) })]
434
+ });
435
+ }
436
+ /**
437
+ * SidebarNav - Complete navigation section with multiple groups.
438
+ */
439
+ function SidebarNav({ groups, className, onItemClick }) {
440
+ return /* @__PURE__ */ jsx("div", {
441
+ className: cn("flex flex-col gap-2", className),
442
+ children: groups.map((group, index) => /* @__PURE__ */ jsx(SidebarNavGroup, {
443
+ title: group.title,
444
+ items: group.items,
445
+ onItemClick
446
+ }, group.title || `nav-group-${index}`))
447
+ });
448
+ }
449
+
450
+ //#endregion
451
+ //#region src/dashboard/sidebar-user-menu.tsx
452
+ function getUserInitials$1(name) {
453
+ if (!name) return "?";
454
+ const names = name.trim().split(" ");
455
+ if (names.length === 1) return names[0].slice(0, 2).toUpperCase();
456
+ return (names[0][0] + names[names.length - 1][0]).toUpperCase();
457
+ }
458
+ function UserAvatar({ user, className }) {
459
+ return /* @__PURE__ */ jsxs(Avatar, {
460
+ className: cn("h-8 w-8 rounded-lg", className),
461
+ children: [/* @__PURE__ */ jsx(AvatarImage, {
462
+ src: user.avatar,
463
+ alt: user.name
464
+ }), /* @__PURE__ */ jsx(AvatarFallback, {
465
+ className: "rounded-lg bg-sidebar-primary text-sidebar-primary-foreground",
466
+ children: getUserInitials$1(user.name)
467
+ })]
468
+ });
469
+ }
470
+ function UserInfo({ user }) {
471
+ return /* @__PURE__ */ jsxs("div", {
472
+ className: "grid flex-1 text-left text-sm leading-tight",
473
+ children: [/* @__PURE__ */ jsx("span", {
474
+ className: "truncate font-semibold",
475
+ children: user.name
476
+ }), /* @__PURE__ */ jsx("span", {
477
+ className: "truncate text-xs text-muted-foreground",
478
+ children: user.email
479
+ })]
480
+ });
481
+ }
482
+ /**
483
+ * SidebarUserMenu - User avatar and dropdown menu for sidebar footer.
484
+ * Accepts handlers for logout and custom menu items.
485
+ */
486
+ function SidebarUserMenu({ user, menuItems = [], onLogout, className }) {
487
+ const { isMobile, state } = useSidebar();
488
+ const isCollapsed = state === "collapsed";
489
+ const defaultItems = [{
490
+ label: "Account",
491
+ icon: CircleUserRound,
492
+ href: "/dashboard/profile"
493
+ }];
494
+ const items = menuItems.length > 0 ? menuItems : defaultItems;
495
+ return /* @__PURE__ */ jsx(SidebarMenu, {
496
+ className,
497
+ children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
498
+ render: /* @__PURE__ */ jsx(SidebarMenuButton, {
499
+ size: "lg",
500
+ tooltip: isCollapsed ? user.name : void 0,
501
+ className: cn("data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground", isCollapsed && !isMobile && "justify-center")
502
+ }),
503
+ children: [/* @__PURE__ */ jsx(UserAvatar, { user }), (!isCollapsed || isMobile) && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(UserInfo, { user }), /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-auto size-4" })] })]
504
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
505
+ className: "w-(--anchor-width) min-w-56 rounded-lg",
506
+ side: isMobile ? "bottom" : "right",
507
+ align: "end",
508
+ sideOffset: 4,
509
+ children: [
510
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, {
511
+ className: "p-0 font-normal",
512
+ children: /* @__PURE__ */ jsxs("div", {
513
+ className: "flex items-center gap-2 px-1 py-1.5 text-left text-sm",
514
+ children: [/* @__PURE__ */ jsx(UserAvatar, { user }), /* @__PURE__ */ jsx(UserInfo, { user })]
515
+ })
516
+ }) }),
517
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
518
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: items.map((item, index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [item.separator && index > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), item.href ? /* @__PURE__ */ jsxs(DropdownMenuItem, {
519
+ render: /* @__PURE__ */ jsx(Link, { href: item.href }),
520
+ className: "w-full flex items-center",
521
+ children: [item.icon && /* @__PURE__ */ jsx(item.icon, { className: "mr-2 h-4 w-4" }), item.label]
522
+ }) : /* @__PURE__ */ jsxs(DropdownMenuItem, {
523
+ onClick: item.onClick,
524
+ className: "w-full flex items-center",
525
+ children: [item.icon && /* @__PURE__ */ jsx(item.icon, { className: "mr-2 h-4 w-4" }), item.label]
526
+ })] }, item.label)) }),
527
+ onLogout && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DropdownMenuSeparator, {}), /* @__PURE__ */ jsxs(DropdownMenuItem, {
528
+ onClick: onLogout,
529
+ className: "w-full flex items-center",
530
+ children: [/* @__PURE__ */ jsx(LogOut, { className: "mr-2 h-4 w-4" }), "Log out"]
531
+ })] })
532
+ ]
533
+ })] }) })
534
+ });
535
+ }
536
+
537
+ //#endregion
538
+ //#region src/dashboard/project-switcher.tsx
539
+ function DropdownContent({ items, selected, onSelect, label, renderItem, isMobile = false }) {
540
+ return /* @__PURE__ */ jsx(DropdownMenuContent, {
541
+ className: "w-64 rounded-lg",
542
+ side: isMobile ? "bottom" : "right",
543
+ align: "start",
544
+ sideOffset: 4,
545
+ children: /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [/* @__PURE__ */ jsx(DropdownMenuLabel, {
546
+ className: "text-xs text-muted-foreground font-normal",
547
+ children: label
548
+ }), items.map((item) => {
549
+ const isSelected = selected.id === item.id;
550
+ if (renderItem) return /* @__PURE__ */ jsx(DropdownMenuItem, {
551
+ onClick: () => onSelect(item),
552
+ className: "cursor-pointer",
553
+ children: renderItem(item, isSelected)
554
+ }, item.id);
555
+ return /* @__PURE__ */ jsx(DropdownMenuItem, {
556
+ onClick: () => onSelect(item),
557
+ className: "gap-2 cursor-pointer",
558
+ children: /* @__PURE__ */ jsxs("div", {
559
+ className: "flex-1 min-w-0",
560
+ children: [
561
+ /* @__PURE__ */ jsxs("div", {
562
+ className: "flex items-center justify-between gap-2",
563
+ children: [/* @__PURE__ */ jsx("span", {
564
+ className: "font-medium text-sm truncate",
565
+ children: item.name
566
+ }), isSelected && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary shrink-0" })]
567
+ }),
568
+ /* @__PURE__ */ jsxs("div", {
569
+ className: "flex items-center gap-1.5 mt-0.5",
570
+ children: [
571
+ item.code && /* @__PURE__ */ jsx("span", {
572
+ className: "text-xs text-muted-foreground",
573
+ children: item.code
574
+ }),
575
+ item.type && /* @__PURE__ */ jsxs(Fragment, { children: [item.code && /* @__PURE__ */ jsx("span", {
576
+ className: "text-xs text-muted-foreground",
577
+ children: "•"
578
+ }), /* @__PURE__ */ jsx(Badge, {
579
+ variant: "outline",
580
+ className: "text-[10px] h-4 px-1",
581
+ children: item.type
582
+ })] }),
583
+ item.isDefault && /* @__PURE__ */ jsx(Badge, {
584
+ variant: "secondary",
585
+ className: "text-[10px] h-4 px-1",
586
+ children: "Default"
587
+ }),
588
+ item.isActive === false && /* @__PURE__ */ jsx(Badge, {
589
+ variant: "destructive",
590
+ className: "text-[10px] h-4 px-1",
591
+ children: "Inactive"
592
+ })
593
+ ]
594
+ }),
595
+ item.subtitle && /* @__PURE__ */ jsx("p", {
596
+ className: "text-[10px] text-muted-foreground mt-0.5 truncate",
597
+ children: item.subtitle
598
+ })
599
+ ]
600
+ })
601
+ }, item.id);
602
+ })] })
603
+ });
604
+ }
605
+ function SidebarLoadingSkeleton({ isCollapsed, isMobile }) {
606
+ return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
607
+ className: cn("h-10 py-1.5 bg-sidebar-accent/50", isCollapsed && !isMobile && "justify-center"),
608
+ disabled: true,
609
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded-sm shrink-0" }), (!isCollapsed || isMobile) && /* @__PURE__ */ jsxs("div", {
610
+ className: "flex-1 min-w-0 space-y-1",
611
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-14" })]
612
+ })]
613
+ }) }) });
614
+ }
615
+ function SidebarProjectDisplay({ project, Icon, isCollapsed, isMobile }) {
616
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 text-muted-foreground shrink-0" }), (!isCollapsed || isMobile) && /* @__PURE__ */ jsxs("div", {
617
+ className: "flex-1 min-w-0 leading-tight text-left",
618
+ children: [/* @__PURE__ */ jsx("p", {
619
+ className: "text-xs font-medium truncate",
620
+ children: project.name
621
+ }), project.code && /* @__PURE__ */ jsx("p", {
622
+ className: "text-[10px] text-muted-foreground truncate",
623
+ children: project.code
624
+ })]
625
+ })] });
626
+ }
627
+ function StandaloneLoadingSkeleton({ size }) {
628
+ return /* @__PURE__ */ jsxs(Button, {
629
+ variant: "outline",
630
+ size,
631
+ className: cn("gap-2", size === "sm" ? "h-8" : "h-9"),
632
+ disabled: true,
633
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded-sm" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })]
634
+ });
635
+ }
636
+ function StandaloneProjectDisplay({ project, Icon, size }) {
637
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
638
+ /* @__PURE__ */ jsx(Icon, { className: cn("text-muted-foreground shrink-0", size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4") }),
639
+ /* @__PURE__ */ jsx("span", {
640
+ className: cn("font-medium truncate max-w-[120px]", size === "sm" ? "text-xs" : "text-sm"),
641
+ children: project.name
642
+ }),
643
+ project.code && /* @__PURE__ */ jsxs("span", {
644
+ className: cn("text-muted-foreground truncate", size === "sm" ? "text-[10px]" : "text-xs"),
645
+ children: [
646
+ "(",
647
+ project.code,
648
+ ")"
649
+ ]
650
+ })
651
+ ] });
652
+ }
653
+ /**
654
+ * ProjectSwitcher - Generic project/workspace/branch switcher.
655
+ * Works for any entity that needs switching functionality.
656
+ *
657
+ * @example Sidebar usage (inside SidebarProvider)
658
+ * ```tsx
659
+ * <ProjectSwitcher
660
+ * items={projects}
661
+ * selected={selectedProject}
662
+ * onSelect={setSelectedProject}
663
+ * />
664
+ * ```
665
+ *
666
+ * @example Header/Standalone usage (no SidebarProvider needed)
667
+ * ```tsx
668
+ * <ProjectSwitcher
669
+ * variant="standalone"
670
+ * items={projects}
671
+ * selected={selectedProject}
672
+ * onSelect={setSelectedProject}
673
+ * size="sm"
674
+ * />
675
+ * ```
676
+ */
677
+ function ProjectSwitcher({ items, selected, onSelect, isLoading = false, label = "Switch Project", icon: Icon = Building2, className, disabled = false, variant = "sidebar", size = "default", renderItem }) {
678
+ const hasMultipleItems = items.length > 1;
679
+ if (variant === "standalone") {
680
+ if (isLoading) return /* @__PURE__ */ jsx(StandaloneLoadingSkeleton, { size });
681
+ if (!selected) return null;
682
+ if (!hasMultipleItems || disabled) return /* @__PURE__ */ jsx(Button, {
683
+ variant: "outline",
684
+ size,
685
+ className: cn("gap-2 cursor-default", size === "sm" ? "h-8" : "h-9", className),
686
+ disabled: true,
687
+ children: /* @__PURE__ */ jsx(StandaloneProjectDisplay, {
688
+ project: selected,
689
+ Icon,
690
+ size
691
+ })
692
+ });
693
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
694
+ render: /* @__PURE__ */ jsx(Button, {
695
+ variant: "outline",
696
+ size,
697
+ className: cn("gap-2", size === "sm" ? "h-8" : "h-9", className)
698
+ }),
699
+ children: [/* @__PURE__ */ jsx(StandaloneProjectDisplay, {
700
+ project: selected,
701
+ Icon,
702
+ size
703
+ }), /* @__PURE__ */ jsx(ChevronsUpDown, { className: cn("text-muted-foreground shrink-0", size === "sm" ? "h-3 w-3" : "h-3.5 w-3.5") })]
704
+ }), /* @__PURE__ */ jsx(DropdownContent, {
705
+ items,
706
+ selected,
707
+ onSelect,
708
+ label,
709
+ renderItem
710
+ })] });
711
+ }
712
+ const { isMobile, state } = useSidebar();
713
+ const isCollapsed = state === "collapsed";
714
+ if (isLoading) return /* @__PURE__ */ jsx(SidebarLoadingSkeleton, {
715
+ isCollapsed,
716
+ isMobile
717
+ });
718
+ if (!selected) return null;
719
+ if (!hasMultipleItems || disabled) return /* @__PURE__ */ jsx(SidebarMenu, {
720
+ className,
721
+ children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(SidebarMenuButton, {
722
+ className: cn("h-10 py-1.5 bg-sidebar-accent/50", isCollapsed && !isMobile && "justify-center"),
723
+ tooltip: isCollapsed ? selected.name : void 0,
724
+ disabled: true,
725
+ children: /* @__PURE__ */ jsx(SidebarProjectDisplay, {
726
+ project: selected,
727
+ Icon,
728
+ isCollapsed,
729
+ isMobile
730
+ })
731
+ }) })
732
+ });
733
+ return /* @__PURE__ */ jsx(SidebarMenu, {
734
+ className,
735
+ children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
736
+ render: /* @__PURE__ */ jsx(SidebarMenuButton, {
737
+ className: cn("h-10 py-1.5 bg-sidebar-accent/50 hover:bg-sidebar-accent transition-colors", isCollapsed && !isMobile && "justify-center"),
738
+ tooltip: isCollapsed ? selected.name : void 0
739
+ }),
740
+ children: [/* @__PURE__ */ jsx(SidebarProjectDisplay, {
741
+ project: selected,
742
+ Icon,
743
+ isCollapsed,
744
+ isMobile
745
+ }), (!isCollapsed || isMobile) && /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-3 w-3 text-muted-foreground shrink-0" })]
746
+ }), /* @__PURE__ */ jsx(DropdownContent, {
747
+ items,
748
+ selected,
749
+ onSelect,
750
+ label,
751
+ renderItem,
752
+ isMobile
753
+ })] }) })
754
+ });
755
+ }
756
+
757
+ //#endregion
758
+ //#region src/dashboard/dashboard-header.tsx
759
+ function BreadcrumbNav({ items }) {
760
+ return /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, { children: items.map((item, index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbItem, {
761
+ className: item.current ? "" : "hidden md:block",
762
+ children: item.current ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
763
+ render: /* @__PURE__ */ jsx(Link, { href: item.href || "#" }),
764
+ children: item.label
765
+ })
766
+ }), index < items.length - 1 && /* @__PURE__ */ jsx(BreadcrumbSeparator, { className: "hidden md:block" })] }, `breadcrumb-${index}`)) }) });
767
+ }
768
+ /**
769
+ * DashboardHeader - Top header bar for dashboard pages.
770
+ * Includes sidebar trigger, breadcrumbs, and action slots.
771
+ */
772
+ function DashboardHeader({ breadcrumbs, leftContent, rightContent, showSidebarTrigger = true, customTrigger, className, children }) {
773
+ return /* @__PURE__ */ jsxs("header", {
774
+ className: cn("flex h-12 shrink-0 items-center justify-between gap-2 px-4", className),
775
+ children: [/* @__PURE__ */ jsxs("div", {
776
+ className: "flex items-center gap-2",
777
+ children: [
778
+ showSidebarTrigger && !customTrigger && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarTrigger, { className: "-ml-1" }), /* @__PURE__ */ jsx(Separator, {
779
+ orientation: "vertical",
780
+ className: "mx-2 !h-4 !self-auto"
781
+ })] }),
782
+ customTrigger,
783
+ children ? children : /* @__PURE__ */ jsxs(Fragment, { children: [breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx(BreadcrumbNav, { items: breadcrumbs }), leftContent] })
784
+ ]
785
+ }), rightContent && /* @__PURE__ */ jsx("div", {
786
+ className: "flex items-center gap-2",
787
+ children: rightContent
788
+ })]
789
+ });
790
+ }
791
+
792
+ //#endregion
793
+ //#region src/dashboard/presets/inset-sidebar.tsx
794
+ /**
795
+ * InsetSidebar - Complete sidebar preset with inset variant.
796
+ * The standard dashboard sidebar with collapsible to icons.
797
+ */
798
+ function InsetSidebar({ brand, navigation, secondaryNavigation, project, user, headerContent, ariaLabel = "Navigation Menu", className, children }) {
799
+ const { isMobile } = useSidebar();
800
+ return /* @__PURE__ */ jsxs(Sidebar, {
801
+ variant: "inset",
802
+ collapsible: "icon",
803
+ className,
804
+ children: [
805
+ isMobile && /* @__PURE__ */ jsxs("span", {
806
+ className: "sr-only",
807
+ children: [/* @__PURE__ */ jsx(SheetTitle, { children: ariaLabel }), /* @__PURE__ */ jsx(SheetDescription, { children: "Application navigation menu containing links to different sections" })]
808
+ }),
809
+ /* @__PURE__ */ jsxs(SidebarHeader, {
810
+ className: "gap-1",
811
+ children: [
812
+ /* @__PURE__ */ jsx(SidebarBrand, {
813
+ title: brand.title,
814
+ icon: brand.icon,
815
+ href: brand.href
816
+ }),
817
+ project && /* @__PURE__ */ jsx(ProjectSwitcher, {
818
+ items: project.items,
819
+ selected: project.selected,
820
+ onSelect: project.onSelect,
821
+ isLoading: project.isLoading,
822
+ label: project.label,
823
+ icon: project.icon
824
+ }),
825
+ headerContent
826
+ ]
827
+ }),
828
+ /* @__PURE__ */ jsx(SidebarContent, { children: children || /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarNav, { groups: navigation }), secondaryNavigation && /* @__PURE__ */ jsx(SidebarNav, {
829
+ groups: secondaryNavigation,
830
+ className: "mt-auto"
831
+ })] }) }),
832
+ user && /* @__PURE__ */ jsx(SidebarFooter, { children: /* @__PURE__ */ jsx(SidebarUserMenu, {
833
+ user: user.data,
834
+ menuItems: user.menuItems,
835
+ onLogout: user.onLogout
836
+ }) })
837
+ ]
838
+ });
839
+ }
840
+
841
+ //#endregion
842
+ //#region src/dashboard/presets/dual-sidebar.tsx
843
+ const SIDEBAR_RAIL_WIDTH = "3.5rem";
844
+ const SIDEBAR_PANEL_WIDTH = "13rem";
845
+ const SIDEBAR_WIDTH_EXPANDED = "16.5rem";
846
+ const SIDEBAR_WIDTH_COLLAPSED = "3.5rem";
847
+ const SIDEBAR_PADDING = "0.5rem";
848
+ const railVariants$1 = {
849
+ default: "bg-sidebar",
850
+ dark: "bg-zinc-900 dark:bg-zinc-950",
851
+ primary: "bg-primary",
852
+ muted: "bg-muted"
853
+ };
854
+ const railTextVariants$1 = {
855
+ default: "text-sidebar-foreground",
856
+ dark: "text-zinc-100",
857
+ primary: "text-primary-foreground",
858
+ muted: "text-muted-foreground"
859
+ };
860
+ /**
861
+ * DualSidebar - A sidebar with icon rail and collapsible expanded panel.
862
+ * Mimics the inset sidebar variant structure for consistent styling.
863
+ */
864
+ function DualSidebar({ brand, categories, user, defaultCategoryId, onCategoryChange, defaultCollapsed = false, mobileOpen: controlledMobileOpen, onMobileOpenChange, railVariant = "default", ariaLabel = "Navigation Menu", className }) {
865
+ const [activeCategory, setActiveCategory] = React$1.useState(defaultCategoryId || (categories.length > 0 ? categories[0].id : null));
866
+ const [isExpanded, setIsExpanded] = React$1.useState(!defaultCollapsed);
867
+ const [internalMobileOpen, setInternalMobileOpen] = React$1.useState(false);
868
+ const { isMobile } = useSidebar();
869
+ const isControlledMobile = controlledMobileOpen !== void 0;
870
+ const mobileOpen = isControlledMobile ? controlledMobileOpen : internalMobileOpen;
871
+ const setMobileOpen = React$1.useCallback((open) => {
872
+ if (isControlledMobile) onMobileOpenChange?.(open);
873
+ else setInternalMobileOpen(open);
874
+ }, [isControlledMobile, onMobileOpenChange]);
875
+ const handleCategorySelect = (id) => {
876
+ setActiveCategory(id);
877
+ onCategoryChange?.(id);
878
+ if (!isExpanded) setIsExpanded(true);
879
+ };
880
+ const handleMobileCategorySelect = (id) => {
881
+ setActiveCategory(id);
882
+ onCategoryChange?.(id);
883
+ };
884
+ const toggleExpanded = () => {
885
+ setIsExpanded(!isExpanded);
886
+ };
887
+ const activeCategoryData = categories.find((c) => c.id === activeCategory) || null;
888
+ const totalWidth = `calc(${isExpanded ? SIDEBAR_WIDTH_EXPANDED : SIDEBAR_WIDTH_COLLAPSED} + ${SIDEBAR_PADDING} * 2)`;
889
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Sheet, {
890
+ open: mobileOpen,
891
+ onOpenChange: setMobileOpen,
892
+ children: [!isControlledMobile && /* @__PURE__ */ jsx(SheetTrigger, {
893
+ render: /* @__PURE__ */ jsx(Button, {
894
+ variant: "outline",
895
+ size: "icon",
896
+ className: "md:hidden fixed top-2 left-2 z-40 h-9 w-9 bg-background/80 backdrop-blur-sm shadow-sm",
897
+ "aria-label": "Open navigation"
898
+ }),
899
+ children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
900
+ }), /* @__PURE__ */ jsxs(SheetContent, {
901
+ side: "left",
902
+ className: "w-72 p-0",
903
+ children: [
904
+ /* @__PURE__ */ jsx(SheetTitle, {
905
+ className: "sr-only",
906
+ children: ariaLabel
907
+ }),
908
+ /* @__PURE__ */ jsx(SheetDescription, {
909
+ className: "sr-only",
910
+ children: "Navigation menu with category icons and expanded content"
911
+ }),
912
+ /* @__PURE__ */ jsxs("div", {
913
+ className: "flex h-full flex-row",
914
+ children: [/* @__PURE__ */ jsxs("div", {
915
+ className: cn("flex flex-col shrink-0", railVariants$1[railVariant], railTextVariants$1[railVariant], "border-r border-sidebar-border"),
916
+ style: {
917
+ width: SIDEBAR_RAIL_WIDTH,
918
+ minWidth: SIDEBAR_RAIL_WIDTH
919
+ },
920
+ children: [/* @__PURE__ */ jsx("div", {
921
+ className: "flex items-center justify-center p-2 h-14",
922
+ children: /* @__PURE__ */ jsx(Link, {
923
+ href: brand.href || "/",
924
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg shadow-sm transition-colors", railVariant === "dark" || railVariant === "primary" ? "bg-white/10 hover:bg-white/20 text-inherit" : "bg-sidebar-primary text-sidebar-primary-foreground"),
925
+ onClick: () => setMobileOpen(false),
926
+ children: brand.icon
927
+ })
928
+ }), /* @__PURE__ */ jsx("div", {
929
+ className: "flex-1 flex flex-col gap-1 p-2",
930
+ children: categories.map((category) => {
931
+ const Icon = category.icon;
932
+ return /* @__PURE__ */ jsx("button", {
933
+ onClick: () => handleMobileCategorySelect(category.id),
934
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg transition-colors", activeCategory === category.id ? railVariant === "dark" || railVariant === "primary" ? "bg-white/20" : "bg-sidebar-accent text-sidebar-accent-foreground" : railVariant === "dark" || railVariant === "primary" ? "hover:bg-white/10" : "hover:bg-sidebar-accent/50"),
935
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
936
+ }, category.id);
937
+ })
938
+ })]
939
+ }), /* @__PURE__ */ jsx("div", {
940
+ className: "flex-1 flex flex-col bg-sidebar overflow-hidden",
941
+ children: activeCategoryData ? /* @__PURE__ */ jsxs(Fragment, { children: [
942
+ /* @__PURE__ */ jsx(SidebarHeader, {
943
+ className: "h-14 border-b border-sidebar-border px-4 flex items-center shrink-0",
944
+ children: /* @__PURE__ */ jsxs("div", {
945
+ className: "flex items-center gap-2",
946
+ children: [/* @__PURE__ */ jsx(activeCategoryData.icon, { className: "h-5 w-5 text-sidebar-foreground" }), /* @__PURE__ */ jsx("span", {
947
+ className: "font-semibold text-sidebar-foreground truncate",
948
+ children: activeCategoryData.name
949
+ })]
950
+ })
951
+ }),
952
+ /* @__PURE__ */ jsx(SidebarContent, {
953
+ className: "flex-1 overflow-y-auto",
954
+ children: /* @__PURE__ */ jsx(SidebarGroup, {
955
+ className: "p-2",
956
+ children: /* @__PURE__ */ jsx(SidebarMenu, { children: activeCategoryData.items.map((item, idx) => {
957
+ const Icon = item.icon;
958
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
959
+ isActive: item.isActive,
960
+ render: /* @__PURE__ */ jsx(Link, {
961
+ href: item.url,
962
+ onClick: () => setMobileOpen(false)
963
+ }),
964
+ children: [
965
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
966
+ /* @__PURE__ */ jsx("span", {
967
+ className: "truncate",
968
+ children: item.title
969
+ }),
970
+ item.badge && /* @__PURE__ */ jsx("span", {
971
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded shrink-0",
972
+ children: item.badge
973
+ })
974
+ ]
975
+ }) }, `mobile-${activeCategoryData.id}-${item.title}-${idx}`);
976
+ }) })
977
+ })
978
+ }),
979
+ user && /* @__PURE__ */ jsx(SidebarFooter, {
980
+ className: "border-t border-sidebar-border shrink-0",
981
+ children: /* @__PURE__ */ jsx(SidebarUserMenu, {
982
+ user: user.data,
983
+ menuItems: user.menuItems,
984
+ onLogout: user.onLogout
985
+ })
986
+ })
987
+ ] }) : /* @__PURE__ */ jsx("div", {
988
+ className: "flex-1 flex items-center justify-center text-sidebar-foreground/60 text-sm",
989
+ children: "Select a category"
990
+ })
991
+ })]
992
+ })
993
+ ]
994
+ })]
995
+ }), /* @__PURE__ */ jsxs("div", {
996
+ className: "group peer text-sidebar-foreground hidden md:block",
997
+ "data-state": "expanded",
998
+ "data-collapsible": "",
999
+ "data-variant": "inset",
1000
+ "data-side": "left",
1001
+ "data-slot": "sidebar",
1002
+ children: [/* @__PURE__ */ jsx("div", {
1003
+ "data-slot": "sidebar-gap",
1004
+ className: "relative bg-transparent transition-[width] duration-200 ease-linear",
1005
+ style: { width: totalWidth }
1006
+ }), /* @__PURE__ */ jsx("div", {
1007
+ "data-slot": "sidebar-container",
1008
+ className: cn("fixed inset-y-0 left-0 z-10 hidden h-svh transition-[width] duration-200 ease-linear md:flex", className),
1009
+ style: {
1010
+ width: totalWidth,
1011
+ padding: SIDEBAR_PADDING
1012
+ },
1013
+ children: /* @__PURE__ */ jsxs("div", {
1014
+ "data-sidebar": "sidebar",
1015
+ "data-slot": "sidebar-inner",
1016
+ className: "bg-sidebar flex h-full w-full flex-row overflow-hidden rounded-lg border border-sidebar-border shadow-sm",
1017
+ children: [/* @__PURE__ */ jsxs("div", {
1018
+ className: cn("flex flex-col shrink-0 transition-colors", railVariants$1[railVariant], railTextVariants$1[railVariant], isExpanded && "border-r border-sidebar-border"),
1019
+ style: {
1020
+ width: SIDEBAR_RAIL_WIDTH,
1021
+ minWidth: SIDEBAR_RAIL_WIDTH
1022
+ },
1023
+ children: [
1024
+ /* @__PURE__ */ jsx("div", {
1025
+ className: "flex items-center justify-center p-2 h-14",
1026
+ children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
1027
+ render: /* @__PURE__ */ jsx(Link, {
1028
+ href: brand.href || "/",
1029
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg shadow-sm transition-colors", railVariant === "dark" || railVariant === "primary" ? "bg-white/10 hover:bg-white/20 text-inherit" : "bg-sidebar-primary text-sidebar-primary-foreground")
1030
+ }),
1031
+ children: brand.icon
1032
+ }), /* @__PURE__ */ jsx(TooltipContent, {
1033
+ side: "right",
1034
+ children: brand.title
1035
+ })] })
1036
+ }),
1037
+ /* @__PURE__ */ jsx("div", {
1038
+ className: "flex-1 flex flex-col gap-1 p-2",
1039
+ children: categories.map((category) => {
1040
+ const Icon = category.icon;
1041
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
1042
+ render: /* @__PURE__ */ jsx("button", {
1043
+ onClick: () => handleCategorySelect(category.id),
1044
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg transition-colors", activeCategory === category.id ? railVariant === "dark" || railVariant === "primary" ? "bg-white/20" : "bg-sidebar-accent text-sidebar-accent-foreground" : railVariant === "dark" || railVariant === "primary" ? "hover:bg-white/10" : "hover:bg-sidebar-accent/50")
1045
+ }),
1046
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
1047
+ }), /* @__PURE__ */ jsx(TooltipContent, {
1048
+ side: "right",
1049
+ children: category.name
1050
+ })] }, category.id);
1051
+ })
1052
+ }),
1053
+ /* @__PURE__ */ jsx("div", {
1054
+ className: "p-2",
1055
+ children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
1056
+ render: /* @__PURE__ */ jsx("button", {
1057
+ onClick: toggleExpanded,
1058
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg transition-colors", railVariant === "dark" || railVariant === "primary" ? "hover:bg-white/10" : "hover:bg-sidebar-accent/50")
1059
+ }),
1060
+ children: isExpanded ? /* @__PURE__ */ jsx(ChevronLeft, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-5 w-5" })
1061
+ }), /* @__PURE__ */ jsx(TooltipContent, {
1062
+ side: "right",
1063
+ children: isExpanded ? "Collapse sidebar" : "Expand sidebar"
1064
+ })] })
1065
+ })
1066
+ ]
1067
+ }), /* @__PURE__ */ jsx("div", {
1068
+ className: cn("flex flex-col bg-sidebar overflow-hidden transition-[width,opacity] duration-200 ease-linear", isExpanded ? "opacity-100" : "opacity-0 w-0"),
1069
+ style: { width: isExpanded ? SIDEBAR_PANEL_WIDTH : 0 },
1070
+ children: activeCategoryData ? /* @__PURE__ */ jsxs(Fragment, { children: [
1071
+ /* @__PURE__ */ jsx(SidebarHeader, {
1072
+ className: "h-14 border-b border-sidebar-border px-4 flex items-center shrink-0",
1073
+ children: /* @__PURE__ */ jsxs("div", {
1074
+ className: "flex items-center gap-2",
1075
+ children: [/* @__PURE__ */ jsx(activeCategoryData.icon, { className: "h-5 w-5 text-sidebar-foreground" }), /* @__PURE__ */ jsx("span", {
1076
+ className: "font-semibold text-sidebar-foreground truncate",
1077
+ children: activeCategoryData.name
1078
+ })]
1079
+ })
1080
+ }),
1081
+ /* @__PURE__ */ jsx(SidebarContent, {
1082
+ className: "flex-1 overflow-y-auto",
1083
+ children: /* @__PURE__ */ jsxs(SidebarGroup, {
1084
+ className: "p-2",
1085
+ children: [/* @__PURE__ */ jsxs(SidebarGroupLabel, {
1086
+ className: "px-2 text-xs text-sidebar-foreground/60",
1087
+ children: [activeCategoryData.name, " Menu"]
1088
+ }), /* @__PURE__ */ jsx(SidebarMenu, { children: activeCategoryData.items.map((item, idx) => {
1089
+ const Icon = item.icon;
1090
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
1091
+ isActive: item.isActive,
1092
+ render: /* @__PURE__ */ jsx(Link, { href: item.url }),
1093
+ children: [
1094
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
1095
+ /* @__PURE__ */ jsx("span", {
1096
+ className: "truncate",
1097
+ children: item.title
1098
+ }),
1099
+ item.badge && /* @__PURE__ */ jsx("span", {
1100
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded shrink-0",
1101
+ children: item.badge
1102
+ })
1103
+ ]
1104
+ }) }, `${activeCategoryData.id}-${item.title}-${idx}`);
1105
+ }) })]
1106
+ })
1107
+ }),
1108
+ user && /* @__PURE__ */ jsx(SidebarFooter, {
1109
+ className: "border-t border-sidebar-border shrink-0",
1110
+ children: /* @__PURE__ */ jsx(SidebarUserMenu, {
1111
+ user: user.data,
1112
+ menuItems: user.menuItems,
1113
+ onLogout: user.onLogout
1114
+ })
1115
+ })
1116
+ ] }) : /* @__PURE__ */ jsx("div", {
1117
+ className: "flex-1 flex items-center justify-center text-sidebar-foreground/60 text-sm",
1118
+ children: "Select a category"
1119
+ })
1120
+ })]
1121
+ })
1122
+ })]
1123
+ })] });
1124
+ }
1125
+
1126
+ //#endregion
1127
+ //#region src/dashboard/presets/floating-sidebar.tsx
1128
+ /**
1129
+ * FloatingSidebar - Floating variant sidebar with rounded corners and shadow.
1130
+ * Hovers above the content area like Linear / Notion style.
1131
+ * Collapses to icon-only rail on desktop.
1132
+ */
1133
+ function FloatingSidebar({ brand, navigation, secondaryNavigation, project, user, headerContent, side = "left", ariaLabel = "Navigation Menu", className, children }) {
1134
+ const { isMobile } = useSidebar();
1135
+ return /* @__PURE__ */ jsxs(Sidebar, {
1136
+ variant: "floating",
1137
+ collapsible: "icon",
1138
+ side,
1139
+ className,
1140
+ children: [
1141
+ isMobile && /* @__PURE__ */ jsxs("span", {
1142
+ className: "sr-only",
1143
+ children: [/* @__PURE__ */ jsx(SheetTitle, { children: ariaLabel }), /* @__PURE__ */ jsx(SheetDescription, { children: "Application navigation menu containing links to different sections" })]
1144
+ }),
1145
+ /* @__PURE__ */ jsxs(SidebarHeader, {
1146
+ className: "gap-1",
1147
+ children: [
1148
+ /* @__PURE__ */ jsx(SidebarBrand, {
1149
+ title: brand.title,
1150
+ icon: brand.icon,
1151
+ href: brand.href
1152
+ }),
1153
+ project && /* @__PURE__ */ jsx(ProjectSwitcher, {
1154
+ items: project.items,
1155
+ selected: project.selected,
1156
+ onSelect: project.onSelect,
1157
+ isLoading: project.isLoading,
1158
+ label: project.label,
1159
+ icon: project.icon
1160
+ }),
1161
+ headerContent
1162
+ ]
1163
+ }),
1164
+ /* @__PURE__ */ jsx(SidebarContent, { children: children || /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarNav, { groups: navigation }), secondaryNavigation && /* @__PURE__ */ jsx(SidebarNav, {
1165
+ groups: secondaryNavigation,
1166
+ className: "mt-auto"
1167
+ })] }) }),
1168
+ user && /* @__PURE__ */ jsx(SidebarFooter, { children: /* @__PURE__ */ jsx(SidebarUserMenu, {
1169
+ user: user.data,
1170
+ menuItems: user.menuItems,
1171
+ onLogout: user.onLogout
1172
+ }) })
1173
+ ]
1174
+ });
1175
+ }
1176
+
1177
+ //#endregion
1178
+ //#region src/dashboard/presets/mini-sidebar.tsx
1179
+ /**
1180
+ * MiniSidebar - Collapsible sidebar that shrinks to icon-only rail.
1181
+ * Think VS Code, GitHub, or Figma-style navigation.
1182
+ * Uses the standard shadcn sidebar with `collapsible="icon"`.
1183
+ */
1184
+ function MiniSidebar({ brand, navigation, secondaryNavigation, user, headerContent, side = "left", showRail = true, ariaLabel = "Navigation Menu", className, children }) {
1185
+ const { isMobile } = useSidebar();
1186
+ return /* @__PURE__ */ jsxs(Sidebar, {
1187
+ collapsible: "icon",
1188
+ side,
1189
+ className,
1190
+ children: [
1191
+ isMobile && /* @__PURE__ */ jsxs("span", {
1192
+ className: "sr-only",
1193
+ children: [/* @__PURE__ */ jsx(SheetTitle, { children: ariaLabel }), /* @__PURE__ */ jsx(SheetDescription, { children: "Application navigation menu" })]
1194
+ }),
1195
+ /* @__PURE__ */ jsxs(SidebarHeader, { children: [/* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
1196
+ size: "lg",
1197
+ tooltip: brand.title,
1198
+ render: /* @__PURE__ */ jsx(Link, { href: brand.href || "/" }),
1199
+ children: [/* @__PURE__ */ jsx("div", {
1200
+ className: "flex items-center justify-center h-8 w-8 rounded-lg bg-sidebar-primary text-sidebar-primary-foreground shadow-sm shrink-0",
1201
+ children: brand.icon
1202
+ }), /* @__PURE__ */ jsx("span", {
1203
+ className: "font-semibold tracking-tight truncate",
1204
+ children: brand.title
1205
+ })]
1206
+ }) }) }), headerContent] }),
1207
+ /* @__PURE__ */ jsx(SidebarContent, { children: children || /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(NavGroups, { groups: navigation }), secondaryNavigation && /* @__PURE__ */ jsx(NavGroups, {
1208
+ groups: secondaryNavigation,
1209
+ className: "mt-auto"
1210
+ })] }) }),
1211
+ user && /* @__PURE__ */ jsx(SidebarFooter, { children: /* @__PURE__ */ jsx(SidebarUserMenu, {
1212
+ user: user.data,
1213
+ menuItems: user.menuItems,
1214
+ onLogout: user.onLogout
1215
+ }) }),
1216
+ showRail && /* @__PURE__ */ jsx(SidebarRail, {})
1217
+ ]
1218
+ });
1219
+ }
1220
+ function NavGroups({ groups, className }) {
1221
+ return /* @__PURE__ */ jsx(Fragment, { children: groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(SidebarGroup, {
1222
+ className: cn(groupIndex === groups.length - 1 && className),
1223
+ children: [group.title && /* @__PURE__ */ jsx(SidebarGroupLabel, { children: group.title }), /* @__PURE__ */ jsx(SidebarMenu, { children: group.items.map((item, itemIndex) => {
1224
+ const Icon = item.icon;
1225
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
1226
+ isActive: item.isActive,
1227
+ tooltip: item.title,
1228
+ render: /* @__PURE__ */ jsx(Link, { href: item.url }),
1229
+ children: [
1230
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
1231
+ /* @__PURE__ */ jsx("span", {
1232
+ className: "truncate",
1233
+ children: item.title
1234
+ }),
1235
+ item.badge != null && /* @__PURE__ */ jsx("span", {
1236
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded shrink-0",
1237
+ children: item.badge
1238
+ })
1239
+ ]
1240
+ }) }, `${groupIndex}-${itemIndex}`);
1241
+ }) })]
1242
+ }, groupIndex)) });
1243
+ }
1244
+
1245
+ //#endregion
1246
+ //#region src/dashboard/presets/topbar-rail.tsx
1247
+ const TOPBAR_HEIGHT = "3rem";
1248
+ const RAIL_WIDTH = "3.5rem";
1249
+ const DRAWER_WIDTH = "14rem";
1250
+ const railVariants = {
1251
+ default: "bg-sidebar",
1252
+ dark: "bg-zinc-900 dark:bg-zinc-950",
1253
+ primary: "bg-primary",
1254
+ muted: "bg-muted"
1255
+ };
1256
+ const railTextVariants = {
1257
+ default: "text-sidebar-foreground",
1258
+ dark: "text-zinc-100",
1259
+ primary: "text-primary-foreground",
1260
+ muted: "text-muted-foreground"
1261
+ };
1262
+ function getUserInitials(name) {
1263
+ if (!name) return "?";
1264
+ const names = name.trim().split(" ");
1265
+ if (names.length === 1) return names[0].slice(0, 2).toUpperCase();
1266
+ return (names[0][0] + names[names.length - 1][0]).toUpperCase();
1267
+ }
1268
+ function TopbarBreadcrumbs({ items }) {
1269
+ return /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, { children: items.map((item, index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbItem, {
1270
+ className: item.current ? "" : "hidden md:block",
1271
+ children: item.current ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: item.label }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
1272
+ render: /* @__PURE__ */ jsx(Link, { href: item.href || "#" }),
1273
+ children: item.label
1274
+ })
1275
+ }), index < items.length - 1 && /* @__PURE__ */ jsx(BreadcrumbSeparator, { className: "hidden md:block" })] }, `breadcrumb-${index}`)) }) });
1276
+ }
1277
+ function TopbarUserMenu({ user, menuItems = [], onLogout }) {
1278
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
1279
+ render: /* @__PURE__ */ jsx(Button, {
1280
+ variant: "ghost",
1281
+ size: "icon",
1282
+ className: "h-8 w-8 rounded-full"
1283
+ }),
1284
+ children: /* @__PURE__ */ jsxs(Avatar, {
1285
+ className: "h-8 w-8",
1286
+ children: [/* @__PURE__ */ jsx(AvatarImage, {
1287
+ src: user.avatar,
1288
+ alt: user.name
1289
+ }), /* @__PURE__ */ jsx(AvatarFallback, {
1290
+ className: "text-xs",
1291
+ children: getUserInitials(user.name)
1292
+ })]
1293
+ })
1294
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1295
+ className: "w-56",
1296
+ align: "end",
1297
+ sideOffset: 4,
1298
+ children: [
1299
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, {
1300
+ className: "p-0 font-normal",
1301
+ children: /* @__PURE__ */ jsxs("div", {
1302
+ className: "flex items-center gap-2 px-2 py-1.5 text-left text-sm",
1303
+ children: [/* @__PURE__ */ jsxs(Avatar, {
1304
+ className: "h-8 w-8",
1305
+ children: [/* @__PURE__ */ jsx(AvatarImage, {
1306
+ src: user.avatar,
1307
+ alt: user.name
1308
+ }), /* @__PURE__ */ jsx(AvatarFallback, {
1309
+ className: "text-xs",
1310
+ children: getUserInitials(user.name)
1311
+ })]
1312
+ }), /* @__PURE__ */ jsxs("div", {
1313
+ className: "grid flex-1 text-left text-sm leading-tight",
1314
+ children: [/* @__PURE__ */ jsx("span", {
1315
+ className: "truncate font-semibold",
1316
+ children: user.name
1317
+ }), /* @__PURE__ */ jsx("span", {
1318
+ className: "truncate text-xs text-muted-foreground",
1319
+ children: user.email
1320
+ })]
1321
+ })]
1322
+ })
1323
+ }) }),
1324
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1325
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: menuItems.map((item, index) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [item.separator && index > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), item.href ? /* @__PURE__ */ jsxs(DropdownMenuItem, {
1326
+ render: /* @__PURE__ */ jsx(Link, { href: item.href }),
1327
+ className: "w-full flex items-center",
1328
+ children: [item.icon && /* @__PURE__ */ jsx(item.icon, { className: "mr-2 h-4 w-4" }), item.label]
1329
+ }) : /* @__PURE__ */ jsxs(DropdownMenuItem, {
1330
+ onClick: item.onClick,
1331
+ className: "w-full flex items-center",
1332
+ children: [item.icon && /* @__PURE__ */ jsx(item.icon, { className: "mr-2 h-4 w-4" }), item.label]
1333
+ })] }, item.label)) }),
1334
+ onLogout && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DropdownMenuSeparator, {}), /* @__PURE__ */ jsx(DropdownMenuItem, {
1335
+ onClick: onLogout,
1336
+ className: "w-full flex items-center",
1337
+ children: "Log out"
1338
+ })] })
1339
+ ]
1340
+ })] });
1341
+ }
1342
+ /**
1343
+ * TopbarRail - Fixed topbar + icon rail + secondary drawer layout.
1344
+ * Common in Linear, Figma, Jira-style SaaS applications.
1345
+ * Does NOT use SidebarProvider — fully custom layout.
1346
+ */
1347
+ function TopbarRail({ brand, categories, user, breadcrumbs, actions, defaultCategoryId, onCategoryChange, defaultDrawerOpen = false, railVariant = "default", ariaLabel = "Navigation Menu", className, children }) {
1348
+ const [activeCategory, setActiveCategory] = React$1.useState(defaultCategoryId || (categories.length > 0 ? categories[0].id : null));
1349
+ const [isDrawerOpen, setIsDrawerOpen] = React$1.useState(defaultDrawerOpen);
1350
+ const [mobileOpen, setMobileOpen] = React$1.useState(false);
1351
+ useIsMobile();
1352
+ const handleCategorySelect = (id) => {
1353
+ if (activeCategory === id && isDrawerOpen) setIsDrawerOpen(false);
1354
+ else {
1355
+ setActiveCategory(id);
1356
+ onCategoryChange?.(id);
1357
+ setIsDrawerOpen(true);
1358
+ }
1359
+ };
1360
+ const handleMobileCategorySelect = (id) => {
1361
+ setActiveCategory(id);
1362
+ onCategoryChange?.(id);
1363
+ };
1364
+ const activeCategoryData = categories.find((c) => c.id === activeCategory) || null;
1365
+ return /* @__PURE__ */ jsxs("div", {
1366
+ "data-slot": "topbar-rail-layout",
1367
+ className: cn("flex flex-col h-svh", className),
1368
+ children: [/* @__PURE__ */ jsxs("header", {
1369
+ className: "flex shrink-0 items-center border-b bg-background px-4 gap-2",
1370
+ style: { height: TOPBAR_HEIGHT },
1371
+ children: [
1372
+ /* @__PURE__ */ jsxs(Sheet, {
1373
+ open: mobileOpen,
1374
+ onOpenChange: setMobileOpen,
1375
+ children: [/* @__PURE__ */ jsx(SheetTrigger, {
1376
+ render: /* @__PURE__ */ jsx(Button, {
1377
+ variant: "ghost",
1378
+ size: "icon",
1379
+ className: "md:hidden h-8 w-8",
1380
+ "aria-label": "Open navigation"
1381
+ }),
1382
+ children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
1383
+ }), /* @__PURE__ */ jsxs(SheetContent, {
1384
+ side: "left",
1385
+ className: "w-72 p-0",
1386
+ children: [
1387
+ /* @__PURE__ */ jsx(SheetTitle, {
1388
+ className: "sr-only",
1389
+ children: ariaLabel
1390
+ }),
1391
+ /* @__PURE__ */ jsx(SheetDescription, {
1392
+ className: "sr-only",
1393
+ children: "Navigation menu with category icons and expanded content"
1394
+ }),
1395
+ /* @__PURE__ */ jsx(MobileNav, {
1396
+ brand,
1397
+ categories,
1398
+ user,
1399
+ activeCategory,
1400
+ onCategorySelect: handleMobileCategorySelect,
1401
+ onClose: () => setMobileOpen(false),
1402
+ railVariant
1403
+ })
1404
+ ]
1405
+ })]
1406
+ }),
1407
+ /* @__PURE__ */ jsxs(Link, {
1408
+ href: brand.href || "/",
1409
+ className: "hidden md:flex items-center gap-2 shrink-0",
1410
+ children: [/* @__PURE__ */ jsx("div", {
1411
+ className: "flex items-center justify-center h-7 w-7",
1412
+ children: brand.icon
1413
+ }), /* @__PURE__ */ jsx("span", {
1414
+ className: "font-semibold text-sm",
1415
+ children: brand.title
1416
+ })]
1417
+ }),
1418
+ /* @__PURE__ */ jsx(Link, {
1419
+ href: brand.href || "/",
1420
+ className: "md:hidden flex items-center gap-2 shrink-0",
1421
+ children: /* @__PURE__ */ jsx("div", {
1422
+ className: "flex items-center justify-center h-7 w-7",
1423
+ children: brand.icon
1424
+ })
1425
+ }),
1426
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Separator, {
1427
+ orientation: "vertical",
1428
+ className: "mx-2 !h-4 !self-auto hidden md:block"
1429
+ }), /* @__PURE__ */ jsx(TopbarBreadcrumbs, { items: breadcrumbs })] }),
1430
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
1431
+ actions && /* @__PURE__ */ jsx("div", {
1432
+ className: "flex items-center gap-2",
1433
+ children: actions
1434
+ }),
1435
+ user && /* @__PURE__ */ jsx(TopbarUserMenu, {
1436
+ user: user.data,
1437
+ menuItems: user.menuItems,
1438
+ onLogout: user.onLogout
1439
+ })
1440
+ ]
1441
+ }), /* @__PURE__ */ jsxs("div", {
1442
+ className: "flex flex-1 overflow-hidden",
1443
+ children: [
1444
+ /* @__PURE__ */ jsx("nav", {
1445
+ className: cn("hidden md:flex flex-col shrink-0 border-r", railVariants[railVariant], railTextVariants[railVariant]),
1446
+ style: {
1447
+ width: RAIL_WIDTH,
1448
+ minWidth: RAIL_WIDTH
1449
+ },
1450
+ "aria-label": ariaLabel,
1451
+ children: /* @__PURE__ */ jsx("div", {
1452
+ className: "flex-1 flex flex-col gap-1 p-2 pt-3",
1453
+ children: categories.map((category) => {
1454
+ const Icon = category.icon;
1455
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
1456
+ render: /* @__PURE__ */ jsx("button", {
1457
+ onClick: () => handleCategorySelect(category.id),
1458
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg transition-colors", activeCategory === category.id ? railVariant === "dark" || railVariant === "primary" ? "bg-white/20" : "bg-sidebar-accent text-sidebar-accent-foreground" : railVariant === "dark" || railVariant === "primary" ? "hover:bg-white/10" : "hover:bg-sidebar-accent/50")
1459
+ }),
1460
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
1461
+ }), /* @__PURE__ */ jsx(TooltipContent, {
1462
+ side: "right",
1463
+ children: category.name
1464
+ })] }, category.id);
1465
+ })
1466
+ })
1467
+ }),
1468
+ /* @__PURE__ */ jsx("aside", {
1469
+ className: cn("hidden md:flex flex-col border-r bg-sidebar overflow-hidden transition-[width,opacity] duration-200 ease-linear", isDrawerOpen ? "opacity-100" : "opacity-0 w-0"),
1470
+ style: { width: isDrawerOpen ? DRAWER_WIDTH : 0 },
1471
+ children: activeCategoryData && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarHeader, {
1472
+ className: "h-12 border-b border-sidebar-border px-4 flex items-center shrink-0",
1473
+ children: /* @__PURE__ */ jsxs("div", {
1474
+ className: "flex items-center gap-2",
1475
+ children: [/* @__PURE__ */ jsx(activeCategoryData.icon, { className: "h-5 w-5 text-sidebar-foreground" }), /* @__PURE__ */ jsx("span", {
1476
+ className: "font-semibold text-sidebar-foreground text-sm truncate",
1477
+ children: activeCategoryData.name
1478
+ })]
1479
+ })
1480
+ }), /* @__PURE__ */ jsx(SidebarContent, {
1481
+ className: "flex-1 overflow-y-auto",
1482
+ children: /* @__PURE__ */ jsxs(SidebarGroup, {
1483
+ className: "p-2",
1484
+ children: [/* @__PURE__ */ jsx(SidebarGroupLabel, {
1485
+ className: "px-2 text-xs text-sidebar-foreground/60",
1486
+ children: activeCategoryData.name
1487
+ }), /* @__PURE__ */ jsx(SidebarMenu, { children: activeCategoryData.items.map((item, idx) => {
1488
+ const Icon = item.icon;
1489
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Link, {
1490
+ href: item.url,
1491
+ className: cn("flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors w-full", "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", item.isActive && "bg-sidebar-accent text-sidebar-accent-foreground font-medium"),
1492
+ children: [
1493
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
1494
+ /* @__PURE__ */ jsx("span", {
1495
+ className: "truncate",
1496
+ children: item.title
1497
+ }),
1498
+ item.badge != null && /* @__PURE__ */ jsx("span", {
1499
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded shrink-0",
1500
+ children: item.badge
1501
+ })
1502
+ ]
1503
+ }) }, `${activeCategoryData.id}-${item.title}-${idx}`);
1504
+ }) })]
1505
+ })
1506
+ })] })
1507
+ }),
1508
+ /* @__PURE__ */ jsx("main", {
1509
+ className: "flex-1 overflow-auto min-w-0",
1510
+ children
1511
+ })
1512
+ ]
1513
+ })]
1514
+ });
1515
+ }
1516
+ function MobileNav({ brand, categories, user, activeCategory, onCategorySelect, onClose, railVariant }) {
1517
+ const activeCategoryData = categories.find((c) => c.id === activeCategory) || null;
1518
+ return /* @__PURE__ */ jsxs("div", {
1519
+ className: "flex h-full flex-row",
1520
+ children: [/* @__PURE__ */ jsxs("div", {
1521
+ className: cn("flex flex-col shrink-0", railVariants[railVariant], railTextVariants[railVariant], "border-r border-sidebar-border"),
1522
+ style: {
1523
+ width: RAIL_WIDTH,
1524
+ minWidth: RAIL_WIDTH
1525
+ },
1526
+ children: [/* @__PURE__ */ jsx("div", {
1527
+ className: "flex items-center justify-center p-2 h-14",
1528
+ children: /* @__PURE__ */ jsx(Link, {
1529
+ href: brand.href || "/",
1530
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg shadow-sm transition-colors", railVariant === "dark" || railVariant === "primary" ? "bg-white/10 hover:bg-white/20 text-inherit" : "bg-sidebar-primary text-sidebar-primary-foreground"),
1531
+ onClick: onClose,
1532
+ children: brand.icon
1533
+ })
1534
+ }), /* @__PURE__ */ jsx("div", {
1535
+ className: "flex-1 flex flex-col gap-1 p-2",
1536
+ children: categories.map((category) => {
1537
+ const Icon = category.icon;
1538
+ return /* @__PURE__ */ jsx("button", {
1539
+ onClick: () => onCategorySelect(category.id),
1540
+ className: cn("flex items-center justify-center h-10 w-10 rounded-lg transition-colors", activeCategory === category.id ? railVariant === "dark" || railVariant === "primary" ? "bg-white/20" : "bg-sidebar-accent text-sidebar-accent-foreground" : railVariant === "dark" || railVariant === "primary" ? "hover:bg-white/10" : "hover:bg-sidebar-accent/50"),
1541
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
1542
+ }, category.id);
1543
+ })
1544
+ })]
1545
+ }), /* @__PURE__ */ jsx("div", {
1546
+ className: "flex-1 flex flex-col bg-sidebar overflow-hidden",
1547
+ children: activeCategoryData ? /* @__PURE__ */ jsxs(Fragment, { children: [
1548
+ /* @__PURE__ */ jsx(SidebarHeader, {
1549
+ className: "h-14 border-b border-sidebar-border px-4 flex items-center shrink-0",
1550
+ children: /* @__PURE__ */ jsxs("div", {
1551
+ className: "flex items-center gap-2",
1552
+ children: [/* @__PURE__ */ jsx(activeCategoryData.icon, { className: "h-5 w-5 text-sidebar-foreground" }), /* @__PURE__ */ jsx("span", {
1553
+ className: "font-semibold text-sidebar-foreground truncate",
1554
+ children: activeCategoryData.name
1555
+ })]
1556
+ })
1557
+ }),
1558
+ /* @__PURE__ */ jsx(SidebarContent, {
1559
+ className: "flex-1 overflow-y-auto",
1560
+ children: /* @__PURE__ */ jsx(SidebarGroup, {
1561
+ className: "p-2",
1562
+ children: /* @__PURE__ */ jsx(SidebarMenu, { children: activeCategoryData.items.map((item, idx) => {
1563
+ const Icon = item.icon;
1564
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Link, {
1565
+ href: item.url,
1566
+ onClick: onClose,
1567
+ className: cn("flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors w-full", "text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", item.isActive && "bg-sidebar-accent text-sidebar-accent-foreground font-medium"),
1568
+ children: [
1569
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
1570
+ /* @__PURE__ */ jsx("span", {
1571
+ className: "truncate",
1572
+ children: item.title
1573
+ }),
1574
+ item.badge != null && /* @__PURE__ */ jsx("span", {
1575
+ className: "ml-auto text-xs bg-sidebar-accent text-sidebar-accent-foreground px-1.5 py-0.5 rounded shrink-0",
1576
+ children: item.badge
1577
+ })
1578
+ ]
1579
+ }) }, `mobile-${activeCategoryData.id}-${item.title}-${idx}`);
1580
+ }) })
1581
+ })
1582
+ }),
1583
+ user && /* @__PURE__ */ jsx("div", {
1584
+ className: "border-t border-sidebar-border p-3 shrink-0",
1585
+ children: /* @__PURE__ */ jsxs("div", {
1586
+ className: "flex items-center gap-2",
1587
+ children: [/* @__PURE__ */ jsxs(Avatar, {
1588
+ className: "h-8 w-8",
1589
+ children: [/* @__PURE__ */ jsx(AvatarImage, {
1590
+ src: user.data.avatar,
1591
+ alt: user.data.name
1592
+ }), /* @__PURE__ */ jsx(AvatarFallback, {
1593
+ className: "text-xs",
1594
+ children: getUserInitials(user.data.name)
1595
+ })]
1596
+ }), /* @__PURE__ */ jsxs("div", {
1597
+ className: "grid flex-1 text-left text-sm leading-tight",
1598
+ children: [/* @__PURE__ */ jsx("span", {
1599
+ className: "truncate font-semibold text-sm",
1600
+ children: user.data.name
1601
+ }), /* @__PURE__ */ jsx("span", {
1602
+ className: "truncate text-xs text-muted-foreground",
1603
+ children: user.data.email
1604
+ })]
1605
+ })]
1606
+ })
1607
+ })
1608
+ ] }) : /* @__PURE__ */ jsx("div", {
1609
+ className: "flex-1 flex items-center justify-center text-sidebar-foreground/60 text-sm",
1610
+ children: "Select a category"
1611
+ })
1612
+ })]
1613
+ });
1614
+ }
1615
+
1616
+ //#endregion
1617
+ export { DashboardContent, DashboardHeader, DashboardPageLayout, DualSidebar, FloatingSidebar, HeaderSection, InsetSidebar, MiniSidebar, PageHeader, ProjectSwitcher, SidebarBrand, SidebarNav, SidebarNavGroup, SidebarNavItem, SidebarUserMenu, TopbarRail, cn, resolveCategories, resolveMiniNavigation, resolveNavigation };