@fayz-ai/ui 0.6.0 → 0.7.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.
Files changed (88) hide show
  1. package/dist/chunk-75EFDLST.js +274 -0
  2. package/dist/chunk-75EFDLST.js.map +1 -0
  3. package/dist/{chunk-YB5ZJKNG.cjs → chunk-7PTRAWHO.cjs} +263 -225
  4. package/dist/chunk-7PTRAWHO.cjs.map +1 -0
  5. package/dist/{chunk-CZ6X6PZT.js → chunk-COC5DDFG.js} +313 -44
  6. package/dist/chunk-COC5DDFG.js.map +1 -0
  7. package/dist/{chunk-MYZT2OG7.js → chunk-FY7OZNKU.js} +24 -68
  8. package/dist/chunk-FY7OZNKU.js.map +1 -0
  9. package/dist/chunk-H6OULCHF.cjs +81 -0
  10. package/dist/chunk-H6OULCHF.cjs.map +1 -0
  11. package/dist/{chunk-GE6XUREM.cjs → chunk-HG5RH3B3.cjs} +339 -68
  12. package/dist/chunk-HG5RH3B3.cjs.map +1 -0
  13. package/dist/{chunk-7TBDPNLY.cjs → chunk-NWPMNPGR.cjs} +76 -47
  14. package/dist/chunk-NWPMNPGR.cjs.map +1 -0
  15. package/dist/{chunk-D6SXPF4F.cjs → chunk-ODY3GZ3Y.cjs} +41 -87
  16. package/dist/chunk-ODY3GZ3Y.cjs.map +1 -0
  17. package/dist/{chunk-22J2RTMN.js → chunk-OTUH4K4B.js} +196 -150
  18. package/dist/chunk-OTUH4K4B.js.map +1 -0
  19. package/dist/chunk-OW73RZOU.cjs +313 -0
  20. package/dist/chunk-OW73RZOU.cjs.map +1 -0
  21. package/dist/{chunk-GFH5HOCO.js → chunk-W5O2X277.js} +42 -14
  22. package/dist/chunk-W5O2X277.js.map +1 -0
  23. package/dist/chunk-YRVE4FOD.js +57 -0
  24. package/dist/chunk-YRVE4FOD.js.map +1 -0
  25. package/dist/dashboard/DashboardCanvas.d.ts +5 -1
  26. package/dist/dashboard/DashboardCanvas.d.ts.map +1 -1
  27. package/dist/dashboard/GoldCard.d.ts +19 -0
  28. package/dist/dashboard/GoldCard.d.ts.map +1 -0
  29. package/dist/dashboard/KpiCard.d.ts.map +1 -1
  30. package/dist/dashboard/index.cjs +30 -26
  31. package/dist/dashboard/index.d.ts +1 -0
  32. package/dist/dashboard/index.d.ts.map +1 -1
  33. package/dist/dashboard/index.js +3 -3
  34. package/dist/index.cjs +198 -174
  35. package/dist/index.d.ts +3 -3
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +7 -7
  38. package/dist/layout/AppShell.d.ts +27 -6
  39. package/dist/layout/AppShell.d.ts.map +1 -1
  40. package/dist/layout/ContentSplit.d.ts +32 -0
  41. package/dist/layout/ContentSplit.d.ts.map +1 -0
  42. package/dist/layout/Sidebar.d.ts.map +1 -1
  43. package/dist/layout/Topbar.d.ts.map +1 -1
  44. package/dist/layout/index.cjs +31 -23
  45. package/dist/layout/index.d.ts +2 -1
  46. package/dist/layout/index.d.ts.map +1 -1
  47. package/dist/layout/index.js +3 -3
  48. package/dist/primitives/index.cjs +126 -114
  49. package/dist/primitives/index.d.ts +2 -0
  50. package/dist/primitives/index.d.ts.map +1 -1
  51. package/dist/primitives/index.js +4 -4
  52. package/dist/primitives/markdown-editor.d.ts +23 -0
  53. package/dist/primitives/markdown-editor.d.ts.map +1 -0
  54. package/dist/primitives/markdown.d.ts +9 -0
  55. package/dist/primitives/markdown.d.ts.map +1 -0
  56. package/package.json +3 -3
  57. package/src/dashboard/DashboardCanvas.tsx +13 -2
  58. package/src/dashboard/GoldCard.tsx +38 -0
  59. package/src/dashboard/KpiCard.tsx +4 -2
  60. package/src/dashboard/index.ts +1 -0
  61. package/src/index.ts +15 -0
  62. package/src/layout/AppShell.tsx +240 -20
  63. package/src/layout/ContentSplit.tsx +153 -0
  64. package/src/layout/ModulePage.tsx +2 -2
  65. package/src/layout/Sidebar.tsx +71 -20
  66. package/src/layout/Topbar.tsx +47 -17
  67. package/src/layout/index.ts +15 -1
  68. package/src/primitives/dropdown.tsx +4 -4
  69. package/src/primitives/index.ts +2 -0
  70. package/src/primitives/markdown-editor.tsx +75 -0
  71. package/src/primitives/markdown.tsx +169 -0
  72. package/src/primitives/select.tsx +1 -1
  73. package/dist/chunk-22J2RTMN.js.map +0 -1
  74. package/dist/chunk-7TBDPNLY.cjs.map +0 -1
  75. package/dist/chunk-CZ6X6PZT.js.map +0 -1
  76. package/dist/chunk-D6SXPF4F.cjs.map +0 -1
  77. package/dist/chunk-DNYVEOAX.js +0 -11
  78. package/dist/chunk-DNYVEOAX.js.map +0 -1
  79. package/dist/chunk-E526FHZ4.js +0 -169
  80. package/dist/chunk-E526FHZ4.js.map +0 -1
  81. package/dist/chunk-GE6XUREM.cjs.map +0 -1
  82. package/dist/chunk-GFH5HOCO.js.map +0 -1
  83. package/dist/chunk-MYZT2OG7.js.map +0 -1
  84. package/dist/chunk-VVVZO2LE.cjs +0 -13
  85. package/dist/chunk-VVVZO2LE.cjs.map +0 -1
  86. package/dist/chunk-W4XXXJRW.cjs +0 -196
  87. package/dist/chunk-W4XXXJRW.cjs.map +0 -1
  88. package/dist/chunk-YB5ZJKNG.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
- import { useCrossModuleBack, useBackHandler, SaveBarProvider, SaveBar } from './chunk-E526FHZ4.js';
2
- import { cn } from './chunk-DNYVEOAX.js';
1
+ import { useCrossModuleBack, useBackHandler, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SaveBarProvider, SaveBar } from './chunk-75EFDLST.js';
2
+ import { cn, Button } from './chunk-YRVE4FOD.js';
3
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';
4
+ import { FileCheck2, Clock3, Boxes, Workflow, UserX, UserPlus, UserCheck, TrendingUp, Star, Inbox, MessageSquare, LayoutDashboard, Award, Zap, Mic, UsersRound, Disc3, ListMusic, Eye, Music, Layers, CircleDollarSign, Landmark, Banknote, BadgeDollarSign, CalendarX, CalendarCheck2, CalendarDays, Radio, PartyPopper, Wheat, Egg, Apple, LeafyGreen, LayoutTemplate, FolderOpen, Heart, PawPrint, Cat, Dog, Clock, Ban, Shield, Search, ListPlus, List, Plus, Filter, Building2, Contact, Handshake, Map, MapPin, UtensilsCrossed, Camera, Tags, Tag, Percent, Globe, MessageCircle, BookOpenCheck, BookOpen, UserCog, Briefcase, ListChecks, ClipboardList, ShoppingBag, Receipt, Wrench, Target, ShoppingCart, Megaphone, DollarSign, Mail, FileText, BarChart3, Activity, Package, CalendarClock, Calendar, Bell, CreditCard, Settings, Users, Home, PanelLeftClose, PanelLeft, Menu, ChevronRight, ChevronLeft, PanelRightOpen, PanelRightClose, PanelRight, Clapperboard, Box, TreePalm, ArrowDownRight, ArrowUpRight, Ruler, Warehouse, Wallet, Sparkles, AlertTriangle, TableProperties, SlidersHorizontal, Plug, ArrowLeftRight, ArrowUpCircle, ArrowDownCircle, ChevronDown, ClipboardCheck, PiggyBank } from 'lucide-react';
5
5
  import * as Tooltip from '@radix-ui/react-tooltip';
6
6
  import { create } from 'zustand';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -26,7 +26,9 @@ var ICON_MAP = {
26
26
  CreditCard,
27
27
  Bell,
28
28
  Calendar,
29
+ CalendarClock,
29
30
  Package,
31
+ Activity,
30
32
  BarChart3,
31
33
  FileText,
32
34
  Mail,
@@ -35,28 +37,39 @@ var ICON_MAP = {
35
37
  ShoppingCart,
36
38
  Target,
37
39
  Wrench,
40
+ Receipt,
41
+ ShoppingBag,
38
42
  ClipboardList,
43
+ ListChecks,
39
44
  Briefcase,
40
45
  UserCog,
41
46
  BookOpen,
47
+ BookOpenCheck,
42
48
  MessageCircle,
43
49
  Globe,
44
50
  Percent,
45
51
  Tag,
52
+ Tags,
46
53
  Camera,
47
54
  UtensilsCrossed,
48
55
  MapPin,
56
+ Map,
49
57
  Handshake,
50
58
  Contact,
51
59
  Building2,
52
60
  Filter,
53
61
  Plus,
54
62
  List,
63
+ ListPlus,
55
64
  Search,
65
+ Shield,
66
+ Ban,
67
+ Clock,
56
68
  Dog,
57
69
  Cat,
58
70
  PawPrint,
59
71
  Heart,
72
+ FolderOpen,
60
73
  LayoutTemplate,
61
74
  LeafyGreen,
62
75
  Apple,
@@ -65,7 +78,12 @@ var ICON_MAP = {
65
78
  PartyPopper,
66
79
  Radio,
67
80
  CalendarDays,
81
+ CalendarCheck2,
82
+ CalendarX,
83
+ BadgeDollarSign,
68
84
  Banknote,
85
+ Landmark,
86
+ CircleDollarSign,
69
87
  Layers,
70
88
  Music,
71
89
  Eye,
@@ -77,8 +95,16 @@ var ICON_MAP = {
77
95
  Award,
78
96
  LayoutDashboard,
79
97
  MessageSquare,
98
+ Inbox,
80
99
  Star,
81
- Workflow
100
+ TrendingUp,
101
+ UserCheck,
102
+ UserPlus,
103
+ UserX,
104
+ Workflow,
105
+ Boxes,
106
+ Clock3,
107
+ FileCheck2
82
108
  };
83
109
  function getIcon(name) {
84
110
  return ICON_MAP[name] ?? Home;
@@ -129,19 +155,37 @@ function NavItem({
129
155
  }
130
156
  return content;
131
157
  }
158
+ function routeMatchScore(route, path) {
159
+ if (path === route) return route.length + 1;
160
+ if (route !== "/" && path.startsWith(route + "/")) return route.length;
161
+ return -1;
162
+ }
163
+ function resolveActiveRoute(navigation, path) {
164
+ let best = null;
165
+ let bestScore = 0;
166
+ const consider = (route) => {
167
+ if (!route) return;
168
+ const score = routeMatchScore(route, path);
169
+ if (score > bestScore) {
170
+ bestScore = score;
171
+ best = route;
172
+ }
173
+ };
174
+ for (const item of navigation) {
175
+ consider(item.route);
176
+ for (const child of item.children ?? []) consider(child.route);
177
+ }
178
+ return best;
179
+ }
132
180
  function NavGroup({
133
181
  item,
134
182
  collapsed,
135
- currentPath,
183
+ activeRoute,
136
184
  onNavigate
137
185
  }) {
138
- const [open, setOpen] = React3.useState(
139
- () => item.children?.some((c) => currentPath === c.route || currentPath.startsWith(c.route + "/")) ?? false
140
- );
186
+ const isChildActive = item.children?.some((c) => c.route === activeRoute);
187
+ const [open, setOpen] = React3.useState(() => isChildActive ?? false);
141
188
  const Icon = getIcon(item.icon);
142
- const isChildActive = item.children?.some(
143
- (c) => currentPath === c.route || currentPath.startsWith(c.route + "/")
144
- );
145
189
  if (collapsed) {
146
190
  return /* @__PURE__ */ jsxs(Tooltip.Root, { delayDuration: 0, children: [
147
191
  /* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -181,7 +225,7 @@ function NavGroup({
181
225
  ),
182
226
  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
227
  const ChildIcon = getIcon(child.icon);
184
- const isActive = currentPath === child.route || currentPath.startsWith(child.route + "/");
228
+ const isActive = child.route === activeRoute;
185
229
  return /* @__PURE__ */ jsxs(
186
230
  "button",
187
231
  {
@@ -218,6 +262,7 @@ function Sidebar({
218
262
  }) {
219
263
  const currentPath = currentPathProp;
220
264
  const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
265
+ const activeRoute = resolveActiveRoute(navigation, currentPath);
221
266
  const mainItems = navigation.filter((item) => item.section === "main");
222
267
  const secondaryItems = navigation.filter((item) => item.section === "secondary");
223
268
  const settingsItems = navigation.filter((item) => item.section === "settings");
@@ -270,24 +315,24 @@ function Sidebar({
270
315
  /* @__PURE__ */ jsxs("nav", { className: "flex-1 space-y-1 overflow-y-auto p-2", children: [
271
316
  topContent && /* @__PURE__ */ jsx("div", { className: "mb-4 space-y-2", children: topContent }),
272
317
  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(
318
+ (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, activeRoute, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
274
319
  NavItem,
275
320
  {
276
321
  item,
277
322
  collapsed,
278
- isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
323
+ isActive: item.route === activeRoute,
279
324
  onNavigate: handleNavigate
280
325
  },
281
326
  item.id
282
327
  )
283
328
  ) }),
284
329
  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(
330
+ (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, activeRoute, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
286
331
  NavItem,
287
332
  {
288
333
  item,
289
334
  collapsed,
290
- isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
335
+ isActive: item.route === activeRoute,
291
336
  onNavigate: handleNavigate
292
337
  },
293
338
  item.id
@@ -299,7 +344,7 @@ function Sidebar({
299
344
  {
300
345
  item,
301
346
  collapsed,
302
- isActive: currentPath === item.route || currentPath.startsWith(item.route + "/"),
347
+ isActive: item.route === activeRoute,
303
348
  onNavigate: handleNavigate
304
349
  },
305
350
  item.id
@@ -408,23 +453,29 @@ var ICON_MAP2 = {
408
453
  CreditCard: CreditCard,
409
454
  Bell: Bell,
410
455
  Calendar: Calendar,
456
+ CalendarClock: CalendarClock,
411
457
  Package: Package,
458
+ Activity: Activity,
412
459
  BarChart3: BarChart3,
413
460
  FileText: FileText,
414
461
  Mail: Mail,
415
462
  DollarSign: DollarSign,
416
463
  Megaphone: Megaphone,
417
464
  ShoppingCart: ShoppingCart,
465
+ ShoppingBag: ShoppingBag,
418
466
  Target: Target,
419
467
  Wrench: Wrench,
420
468
  ClipboardList: ClipboardList,
469
+ ClipboardCheck,
421
470
  Briefcase: Briefcase,
422
471
  UserCog: UserCog,
423
472
  BookOpen: BookOpen,
424
473
  MessageCircle: MessageCircle,
425
474
  Globe: Globe,
475
+ BookOpenCheck: BookOpenCheck,
426
476
  Percent: Percent,
427
477
  Tag: Tag,
478
+ Tags: Tags,
428
479
  Camera: Camera,
429
480
  UtensilsCrossed: UtensilsCrossed,
430
481
  Search: Search,
@@ -435,7 +486,10 @@ var ICON_MAP2 = {
435
486
  ChevronDown: ChevronDown,
436
487
  Filter: Filter,
437
488
  Plus: Plus,
489
+ Shield: Shield,
438
490
  List: List,
491
+ ListChecks: ListChecks,
492
+ FolderOpen: FolderOpen,
439
493
  Dog: Dog,
440
494
  Cat: Cat,
441
495
  PawPrint: PawPrint,
@@ -451,11 +505,11 @@ var ICON_MAP2 = {
451
505
  Plug,
452
506
  SlidersHorizontal,
453
507
  TableProperties,
454
- Landmark,
455
- Receipt,
456
- TrendingUp,
457
- CircleDollarSign,
458
- Clock,
508
+ Landmark: Landmark,
509
+ Receipt: Receipt,
510
+ TrendingUp: TrendingUp,
511
+ CircleDollarSign: CircleDollarSign,
512
+ Clock: Clock,
459
513
  AlertTriangle,
460
514
  Sparkles,
461
515
  Wallet,
@@ -463,11 +517,16 @@ var ICON_MAP2 = {
463
517
  Ruler,
464
518
  ArrowUpRight,
465
519
  ArrowDownRight,
466
- UserPlus,
520
+ UserPlus: UserPlus,
521
+ UserX: UserX,
467
522
  TreePalm,
523
+ Boxes: Boxes,
524
+ Box,
525
+ FileCheck2: FileCheck2,
468
526
  PartyPopper: PartyPopper,
469
527
  Radio: Radio,
470
528
  CalendarDays: CalendarDays,
529
+ BadgeDollarSign: BadgeDollarSign,
471
530
  Banknote: Banknote,
472
531
  Layers: Layers,
473
532
  Music: Music,
@@ -475,7 +534,18 @@ var ICON_MAP2 = {
475
534
  ListMusic: ListMusic,
476
535
  Disc3: Disc3,
477
536
  UsersRound: UsersRound,
478
- Mic: Mic
537
+ Mic: Mic,
538
+ CalendarCheck2: CalendarCheck2,
539
+ CalendarX: CalendarX,
540
+ ListPlus: ListPlus,
541
+ Map: Map,
542
+ Ban: Ban,
543
+ Clock3: Clock3,
544
+ Inbox: Inbox,
545
+ UserCheck: UserCheck,
546
+ Star: Star,
547
+ Zap: Zap,
548
+ Clapperboard
479
549
  };
480
550
  function getIcon2(name) {
481
551
  return ICON_MAP2[name] ?? Home;
@@ -560,7 +630,7 @@ function Topbar({
560
630
  return /* @__PURE__ */ jsxs("header", { "data-print": "hide", className: "sticky top-0 z-50 w-full shrink-0", children: [
561
631
  /* @__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
632
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
563
- /* @__PURE__ */ jsx(
633
+ onMenuClick && /* @__PURE__ */ jsx(
564
634
  "button",
565
635
  {
566
636
  onClick: onMenuClick,
@@ -575,7 +645,7 @@ function Topbar({
575
645
  "button",
576
646
  {
577
647
  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",
648
+ 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:border-sidebar-foreground/25 hover:bg-sidebar-foreground/10 hover:text-sidebar-foreground",
579
649
  children: [
580
650
  /* @__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
651
  /* @__PURE__ */ jsx("span", { className: "text-xs", children: searchPlaceholder }),
@@ -606,7 +676,7 @@ function Topbar({
606
676
  const left = active.offsetLeft - el.offsetWidth / 2 + active.offsetWidth / 2;
607
677
  el.scrollTo({ left: Math.max(0, left), behavior: "smooth" });
608
678
  }
609
- }, className: "flex items-center gap-0.5 overflow-x-auto scrollbar-hide", children: allNav.map((item) => {
679
+ }, className: "flex items-center gap-0.5 overflow-x-auto scrollbar-none", children: allNav.map((item) => {
610
680
  if (item.children && item.children.length > 0) {
611
681
  return /* @__PURE__ */ jsx(
612
682
  NavDropdown,
@@ -669,14 +739,22 @@ function SidebarLayout({
669
739
  topbarEnd,
670
740
  userMenuSlot,
671
741
  notificationSlot,
672
- unreadCount = 0
742
+ unreadCount = 0,
743
+ hasBottomNav = false,
744
+ mobileHeader = "minimal"
673
745
  }) {
674
746
  const sidebarCollapsed = useLayoutStore((s) => s.sidebarCollapsed);
675
747
  const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
676
748
  const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
677
749
  const [headerSlot, setHeaderSlot] = React3.useState(null);
678
750
  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: [
751
+ return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsx(ModuleHeaderSlotContext.Provider, { value: headerSlot, children: /* @__PURE__ */ jsx(ModuleHeaderActionsSlotContext.Provider, { value: actionsSlot, children: /* @__PURE__ */ jsxs("div", { className: cn(
752
+ "flex h-screen overflow-hidden bg-background",
753
+ // Frame mode: the inset gap around the framed card takes the sidebar (menu)
754
+ // color, so the white card reads as a panel floating on the same tone as the
755
+ // left menu. The card's own md:m-2 margin reveals this behind it.
756
+ frame && "md:bg-sidebar"
757
+ ), children: [
680
758
  /* @__PURE__ */ jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsx(
681
759
  Sidebar,
682
760
  {
@@ -704,9 +782,12 @@ function SidebarLayout({
704
782
  "relative flex flex-1 flex-col overflow-hidden",
705
783
  frame && "md:m-2 md:rounded-xl md:border md:border-border md:bg-card"
706
784
  ), 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: [
785
+ /* @__PURE__ */ jsxs("div", { className: cn(
786
+ "flex min-h-14 shrink-0 items-center justify-between gap-3 border-b border-border bg-card px-4 py-2",
787
+ mobileHeader !== "minimal" && "hidden md:flex"
788
+ ), children: [
708
789
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
709
- /* @__PURE__ */ jsx(
790
+ !hasBottomNav && /* @__PURE__ */ jsx(
710
791
  "button",
711
792
  {
712
793
  onClick: () => setMobileMenuOpen(true),
@@ -724,7 +805,7 @@ function SidebarLayout({
724
805
  topbarEnd
725
806
  ] })
726
807
  ] }),
727
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto", children }),
808
+ /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto pb-16 md:pb-0", children }),
728
809
  /* @__PURE__ */ jsx(SaveBar, {})
729
810
  ] }),
730
811
  mobileMenuOpen && /* @__PURE__ */ jsx(
@@ -764,7 +845,8 @@ function TopbarLayout({
764
845
  frame,
765
846
  currentPath,
766
847
  topbarStart,
767
- topbarEnd
848
+ topbarEnd,
849
+ hasBottomNav = false
768
850
  }) {
769
851
  const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
770
852
  return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsxs("div", { className: "relative flex h-screen flex-col overflow-hidden bg-background", children: [
@@ -783,10 +865,10 @@ function TopbarLayout({
783
865
  userMenuExtras,
784
866
  leftContent: topbarStart,
785
867
  rightContent: topbarEnd,
786
- onMenuClick: () => setMobileMenuOpen(true)
868
+ onMenuClick: hasBottomNav ? void 0 : () => setMobileMenuOpen(true)
787
869
  }
788
870
  ),
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 }) }),
871
+ /* @__PURE__ */ jsx("main", { className: cn("flex-1 overflow-y-auto pb-16 md:pb-0", frame && "md:bg-sidebar 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
872
  /* @__PURE__ */ jsx(SaveBar, {}),
791
873
  mobileMenuOpen && /* @__PURE__ */ jsx(
792
874
  MobileOverlay,
@@ -824,7 +906,7 @@ function MinimalLayout({
824
906
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) }),
825
907
  headerEnd && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: headerEnd })
826
908
  ] }),
827
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto", children })
909
+ /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto pb-16 md:pb-0", children })
828
910
  ] });
829
911
  }
830
912
  function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
@@ -886,6 +968,82 @@ function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
886
968
  )
887
969
  ] });
888
970
  }
971
+ var BOTTOM_NAV_ICONS = {
972
+ Home: Home,
973
+ Receipt: Receipt,
974
+ ArrowLeftRight: ArrowLeftRight,
975
+ Calendar: Calendar,
976
+ CreditCard: CreditCard,
977
+ Settings: Settings,
978
+ Menu: Menu,
979
+ MessageCircle: MessageCircle,
980
+ Wallet: Wallet,
981
+ PiggyBank,
982
+ Plus: Plus
983
+ };
984
+ function FloatingProfileAvatar({ user, onClick }) {
985
+ if (!user) return null;
986
+ const label = user.fullName || user.email;
987
+ return /* @__PURE__ */ jsx(
988
+ "button",
989
+ {
990
+ type: "button",
991
+ onClick,
992
+ "aria-label": "Profile",
993
+ className: "fixed right-3 top-3 z-40 md:hidden",
994
+ children: user.avatarUrl ? /* @__PURE__ */ jsx(
995
+ "img",
996
+ {
997
+ src: user.avatarUrl,
998
+ alt: "",
999
+ className: "h-9 w-9 rounded-full object-cover shadow-md ring-2 ring-background"
1000
+ }
1001
+ ) : /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-full bg-primary text-sm font-semibold text-primary-foreground shadow-md ring-2 ring-background", children: (label || "?").charAt(0).toUpperCase() })
1002
+ }
1003
+ );
1004
+ }
1005
+ function MobileBottomNav({
1006
+ items,
1007
+ currentPath,
1008
+ onNavigate,
1009
+ onAction
1010
+ }) {
1011
+ const path = currentPath ?? "";
1012
+ return /* @__PURE__ */ jsx("nav", { className: "fixed inset-x-0 bottom-0 z-50 flex h-16 items-center justify-around border-t border-border bg-background md:hidden", children: items.map((item) => {
1013
+ if (item.kind === "action") {
1014
+ const ActionIcon = BOTTOM_NAV_ICONS[item.icon] ?? Plus;
1015
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-start justify-center", children: /* @__PURE__ */ jsx(
1016
+ "button",
1017
+ {
1018
+ type: "button",
1019
+ onClick: () => onAction?.(item.id),
1020
+ "aria-label": item.label ?? "Add",
1021
+ className: "-mt-6 flex h-14 w-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg shadow-primary/30 ring-4 ring-background transition-transform active:scale-95",
1022
+ children: /* @__PURE__ */ jsx(ActionIcon, { className: "h-6 w-6" })
1023
+ }
1024
+ ) }, item.id);
1025
+ }
1026
+ const isActive = item.route === "/" ? path === "/" || path === "" : path === item.route || path.startsWith(item.route + "/");
1027
+ const Icon = BOTTOM_NAV_ICONS[item.icon] ?? Home;
1028
+ return /* @__PURE__ */ jsxs(
1029
+ "button",
1030
+ {
1031
+ type: "button",
1032
+ onClick: () => onNavigate?.(item.route),
1033
+ className: cn(
1034
+ "flex flex-1 flex-col items-center justify-center gap-0.5 px-1 py-1 transition-colors",
1035
+ isActive ? "text-primary" : "text-muted-foreground"
1036
+ ),
1037
+ "aria-current": isActive ? "page" : void 0,
1038
+ children: [
1039
+ /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" }),
1040
+ /* @__PURE__ */ jsx("span", { className: "text-xs", children: item.label })
1041
+ ]
1042
+ },
1043
+ item.route
1044
+ );
1045
+ }) });
1046
+ }
889
1047
  function AppShell({
890
1048
  variant,
891
1049
  contentFrame,
@@ -906,13 +1064,28 @@ function AppShell({
906
1064
  topbarEnd,
907
1065
  sidebarTopContent,
908
1066
  sidebarFooterContent,
1067
+ bottomNav,
1068
+ onBottomNavAction,
1069
+ mobileHeader = "minimal",
909
1070
  userMenuSlot,
910
1071
  notificationSlot,
911
1072
  unreadCount = 0
912
1073
  }) {
1074
+ const hasBottomNav = !!bottomNav?.length;
1075
+ const bottomBar = hasBottomNav ? /* @__PURE__ */ jsx(
1076
+ MobileBottomNav,
1077
+ {
1078
+ items: bottomNav,
1079
+ currentPath,
1080
+ onNavigate,
1081
+ onAction: onBottomNavAction
1082
+ }
1083
+ ) : null;
1084
+ const floatingAvatar = mobileHeader === "transparent" && user ? /* @__PURE__ */ jsx(FloatingProfileAvatar, { user, onClick: onProfile }) : null;
1085
+ let layoutElement;
913
1086
  switch (variant) {
914
1087
  case "sidebar":
915
- return /* @__PURE__ */ jsx(
1088
+ layoutElement = /* @__PURE__ */ jsx(
916
1089
  SidebarLayout,
917
1090
  {
918
1091
  navigation,
@@ -935,11 +1108,14 @@ function AppShell({
935
1108
  userMenuSlot,
936
1109
  notificationSlot,
937
1110
  unreadCount,
1111
+ hasBottomNav,
1112
+ mobileHeader,
938
1113
  children
939
1114
  }
940
1115
  );
1116
+ break;
941
1117
  case "topbar":
942
- return /* @__PURE__ */ jsx(
1118
+ layoutElement = /* @__PURE__ */ jsx(
943
1119
  TopbarLayout,
944
1120
  {
945
1121
  navigation,
@@ -955,15 +1131,23 @@ function AppShell({
955
1131
  currentPath,
956
1132
  topbarStart,
957
1133
  topbarEnd,
1134
+ hasBottomNav,
958
1135
  children
959
1136
  }
960
1137
  );
1138
+ break;
961
1139
  case "minimal":
962
- return /* @__PURE__ */ jsx(MinimalLayout, { logo, user, headerEnd: topbarEnd, children });
1140
+ layoutElement = /* @__PURE__ */ jsx(MinimalLayout, { logo, user, headerEnd: topbarEnd, children });
1141
+ break;
963
1142
  default: {
964
1143
  return null;
965
1144
  }
966
1145
  }
1146
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1147
+ layoutElement,
1148
+ floatingAvatar,
1149
+ bottomBar
1150
+ ] });
967
1151
  }
968
1152
  var NavTransitionContext = React3.createContext("slide");
969
1153
  function NavTransitionProvider({ value, children }) {
@@ -1052,7 +1236,7 @@ function MobileTabs({ nav }) {
1052
1236
  }
1053
1237
  }, [nav]);
1054
1238
  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) => {
1239
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, className: "flex gap-1 px-1 pb-2 overflow-x-auto scrollbar-none", children: nav.map((item) => {
1056
1240
  const Icon = item.icon ? ICON_MAP2[item.icon] ?? null : null;
1057
1241
  const hasChildren = item.children && item.children.length > 0;
1058
1242
  const isActive = item.active || item.children?.some((c) => c.active);
@@ -1175,7 +1359,7 @@ function ModuleHeader({ nav }) {
1175
1359
  const kids = item.children ?? [];
1176
1360
  return kids.find((c) => /list/i.test(c.id) || /^list$/i.test(c.label)) ?? kids[kids.length - 1];
1177
1361
  }
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) => {
1362
+ 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-none", children: nav.map((item) => {
1179
1363
  const Icon = item.icon ? ICON_MAP2[item.icon] ?? null : null;
1180
1364
  const hasChildren = item.children && item.children.length > 0;
1181
1365
  const isActive = item.active || item.children?.some((c) => c.active);
@@ -1231,7 +1415,92 @@ function ModulePage({ title, subtitle, nav, children, className, headerAction, s
1231
1415
  ] })
1232
1416
  ] });
1233
1417
  }
1418
+ var ContentSplitContext = React3.createContext(null);
1419
+ function ContentSplit({
1420
+ children,
1421
+ aside,
1422
+ asideTitle,
1423
+ asideDescription,
1424
+ asideWidth = "20rem",
1425
+ asideOpen,
1426
+ onAsideOpenChange,
1427
+ collapsible = false,
1428
+ defaultCollapsed = false,
1429
+ className
1430
+ }) {
1431
+ const [internalOpen, setInternalOpen] = React3.useState(false);
1432
+ const open = asideOpen ?? internalOpen;
1433
+ const setOpen = onAsideOpenChange ?? setInternalOpen;
1434
+ const [collapsed, setCollapsed] = React3.useState(collapsible && defaultCollapsed);
1435
+ return /* @__PURE__ */ jsxs(ContentSplitContext.Provider, { value: { open, setOpen }, children: [
1436
+ /* @__PURE__ */ jsxs(
1437
+ "div",
1438
+ {
1439
+ className: cn("lg:grid lg:items-start lg:gap-6", className),
1440
+ style: { gridTemplateColumns: `minmax(0, 1fr) ${collapsed ? "auto" : asideWidth}` },
1441
+ children: [
1442
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children }),
1443
+ /* @__PURE__ */ jsx("aside", { className: "hidden lg:block lg:sticky lg:top-4", children: collapsed ? /* @__PURE__ */ jsx(
1444
+ Button,
1445
+ {
1446
+ variant: "outline",
1447
+ size: "sm",
1448
+ onClick: () => setCollapsed(false),
1449
+ className: "h-9 w-9 p-0",
1450
+ "aria-label": typeof asideTitle === "string" ? asideTitle : void 0,
1451
+ title: typeof asideTitle === "string" ? asideTitle : void 0,
1452
+ children: /* @__PURE__ */ jsx(PanelRightOpen, { className: "h-4 w-4" })
1453
+ }
1454
+ ) : /* @__PURE__ */ jsxs("div", { className: "rounded-card border border-border bg-card", children: [
1455
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2 border-b border-border px-4 py-3", children: [
1456
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
1457
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: asideTitle }),
1458
+ asideDescription && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: asideDescription })
1459
+ ] }),
1460
+ collapsible && /* @__PURE__ */ jsx(
1461
+ "button",
1462
+ {
1463
+ type: "button",
1464
+ onClick: () => setCollapsed(true),
1465
+ className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground",
1466
+ "aria-label": "collapse",
1467
+ children: /* @__PURE__ */ jsx(PanelRightClose, { className: "h-4 w-4" })
1468
+ }
1469
+ )
1470
+ ] }),
1471
+ /* @__PURE__ */ jsx("div", { className: "p-4", children: aside })
1472
+ ] }) })
1473
+ ]
1474
+ }
1475
+ ),
1476
+ /* @__PURE__ */ jsx("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx(Sheet, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(SheetContent, { width: "max-w-sm", children: [
1477
+ /* @__PURE__ */ jsxs(SheetHeader, { children: [
1478
+ /* @__PURE__ */ jsx(SheetTitle, { children: asideTitle }),
1479
+ asideDescription && /* @__PURE__ */ jsx(SheetDescription, { children: asideDescription })
1480
+ ] }),
1481
+ /* @__PURE__ */ jsx(SheetBody, { children: aside })
1482
+ ] }) }) })
1483
+ ] });
1484
+ }
1485
+ function ContentSplitTrigger({ label, iconOnly, className }) {
1486
+ const ctx = React3.useContext(ContentSplitContext);
1487
+ if (!ctx) return null;
1488
+ return /* @__PURE__ */ jsxs(
1489
+ Button,
1490
+ {
1491
+ variant: "outline",
1492
+ size: "sm",
1493
+ onClick: () => ctx.setOpen(true),
1494
+ className: cn("lg:hidden", className),
1495
+ "aria-label": typeof label === "string" ? label : void 0,
1496
+ children: [
1497
+ /* @__PURE__ */ jsx(PanelRight, { className: cn("h-4 w-4", !iconOnly && "mr-1.5") }),
1498
+ !iconOnly && label
1499
+ ]
1500
+ }
1501
+ );
1502
+ }
1234
1503
 
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
1504
+ export { AppShell, BackStyleProvider, ContentSplit, ContentSplitTrigger, ICON_MAP, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeaderActions, PageTransition, Sidebar, SubpageHeader, Topbar, useBackStyle, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition };
1505
+ //# sourceMappingURL=chunk-COC5DDFG.js.map
1506
+ //# sourceMappingURL=chunk-COC5DDFG.js.map