@fayz-ai/ui 0.8.2 → 0.8.4

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 (63) hide show
  1. package/dist/{chunk-XAOGMWLC.cjs → chunk-7ZQQZD4Q.cjs} +354 -80
  2. package/dist/chunk-7ZQQZD4Q.cjs.map +1 -0
  3. package/dist/{chunk-IEYCOJTY.cjs → chunk-B3BTZDTA.cjs} +10 -42
  4. package/dist/chunk-B3BTZDTA.cjs.map +1 -0
  5. package/dist/{chunk-O5F4LLSL.js → chunk-DYMBFHD7.js} +8 -7
  6. package/dist/chunk-DYMBFHD7.js.map +1 -0
  7. package/dist/{chunk-FY7OZNKU.js → chunk-G6OKZ7WL.js} +35 -8
  8. package/dist/chunk-G6OKZ7WL.js.map +1 -0
  9. package/dist/{chunk-W5O2X277.js → chunk-M34ACV5E.js} +27 -4
  10. package/dist/chunk-M34ACV5E.js.map +1 -0
  11. package/dist/{chunk-NWPMNPGR.cjs → chunk-MUGRP5DD.cjs} +57 -34
  12. package/dist/chunk-MUGRP5DD.cjs.map +1 -0
  13. package/dist/{chunk-ODY3GZ3Y.cjs → chunk-NZV47HWO.cjs} +36 -7
  14. package/dist/chunk-NZV47HWO.cjs.map +1 -0
  15. package/dist/{chunk-J3IUFUNR.js → chunk-R4LPSXTT.js} +8 -38
  16. package/dist/chunk-R4LPSXTT.js.map +1 -0
  17. package/dist/{chunk-TDGSY5W6.cjs → chunk-R4SQ2GVD.cjs} +8 -7
  18. package/dist/chunk-R4SQ2GVD.cjs.map +1 -0
  19. package/dist/{chunk-MZZMZYSE.js → chunk-VVQ45ZDZ.js} +357 -83
  20. package/dist/chunk-VVQ45ZDZ.js.map +1 -0
  21. package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
  22. package/dist/dashboard/index.cjs +26 -26
  23. package/dist/dashboard/index.js +2 -2
  24. package/dist/index.cjs +137 -137
  25. package/dist/index.js +5 -5
  26. package/dist/layout/AppShell.d.ts +41 -1
  27. package/dist/layout/AppShell.d.ts.map +1 -1
  28. package/dist/layout/ModulePage.d.ts +9 -6
  29. package/dist/layout/ModulePage.d.ts.map +1 -1
  30. package/dist/layout/Sidebar.d.ts +24 -1
  31. package/dist/layout/Sidebar.d.ts.map +1 -1
  32. package/dist/layout/Topbar.d.ts +13 -1
  33. package/dist/layout/Topbar.d.ts.map +1 -1
  34. package/dist/layout/index.cjs +19 -19
  35. package/dist/layout/index.js +1 -1
  36. package/dist/primitives/data-table.d.ts.map +1 -1
  37. package/dist/primitives/index.cjs +83 -83
  38. package/dist/primitives/index.js +2 -2
  39. package/dist/primitives/search-select.d.ts +3 -1
  40. package/dist/primitives/search-select.d.ts.map +1 -1
  41. package/dist/theme/index.cjs +8 -8
  42. package/dist/theme/index.d.ts.map +1 -1
  43. package/dist/theme/index.js +1 -1
  44. package/package.json +3 -3
  45. package/src/dashboard/OnboardingWidget.tsx +41 -1
  46. package/src/layout/AppShell.tsx +255 -7
  47. package/src/layout/ModulePage.tsx +32 -3
  48. package/src/layout/Sidebar.tsx +198 -61
  49. package/src/layout/Topbar.tsx +51 -4
  50. package/src/primitives/data-table.tsx +10 -1
  51. package/src/primitives/search-select.tsx +12 -4
  52. package/src/styles.css +34 -0
  53. package/src/theme/index.ts +9 -6
  54. package/dist/chunk-FY7OZNKU.js.map +0 -1
  55. package/dist/chunk-IEYCOJTY.cjs.map +0 -1
  56. package/dist/chunk-J3IUFUNR.js.map +0 -1
  57. package/dist/chunk-MZZMZYSE.js.map +0 -1
  58. package/dist/chunk-NWPMNPGR.cjs.map +0 -1
  59. package/dist/chunk-O5F4LLSL.js.map +0 -1
  60. package/dist/chunk-ODY3GZ3Y.cjs.map +0 -1
  61. package/dist/chunk-TDGSY5W6.cjs.map +0 -1
  62. package/dist/chunk-W5O2X277.js.map +0 -1
  63. package/dist/chunk-XAOGMWLC.cjs.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { useCrossModuleBack, useBackHandler, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetBody, SaveBarProvider, SaveBar } from './chunk-75EFDLST.js';
2
2
  import { cn, Button } from './chunk-YRVE4FOD.js';
3
3
  import * as React3 from '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, Newspaper, Clapperboard, Box, TreePalm, ArrowDownRight, ArrowUpRight, Ruler, Warehouse, Wallet, Sparkles, AlertTriangle, TableProperties, SlidersHorizontal, Plug, ArrowLeftRight, ArrowUpCircle, ArrowDownCircle, ChevronDown, ClipboardCheck, PiggyBank } from 'lucide-react';
4
+ import { Puzzle, SlidersHorizontal, ShieldCheck, Palette, User, Repeat, GraduationCap, 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, Truck, Wrench, Target, ShoppingCart, Megaphone, DollarSign, Mail, FileText, BarChart3, Activity, Package, CalendarClock, Calendar, Bell, CreditCard, Settings, Users, Home, PanelLeftClose, PanelLeft, Menu, Crown, ChevronRight, ChevronLeft, PanelRightOpen, PanelRightClose, PanelRight, Newspaper, Clapperboard, Box, TreePalm, ArrowDownRight, ArrowUpRight, Ruler, Warehouse, Wallet, Sparkles, AlertTriangle, TableProperties, Plug, ArrowLeftRight, ArrowUpCircle, ArrowDownCircle, ChevronDown, ClipboardCheck, ExternalLink, PiggyBank, LogOut } from 'lucide-react';
5
5
  import * as Tooltip from '@radix-ui/react-tooltip';
6
6
  import { create } from 'zustand';
7
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
8
  import * as Popover from '@radix-ui/react-popover';
9
9
  import { createPortal } from 'react-dom';
10
10
  import { useTranslation } from '@fayz-ai/core';
@@ -37,6 +37,7 @@ var ICON_MAP = {
37
37
  ShoppingCart,
38
38
  Target,
39
39
  Wrench,
40
+ Truck,
40
41
  Receipt,
41
42
  ShoppingBag,
42
43
  ClipboardList,
@@ -104,8 +105,17 @@ var ICON_MAP = {
104
105
  Workflow,
105
106
  Boxes,
106
107
  Clock3,
107
- FileCheck2
108
+ FileCheck2,
109
+ GraduationCap,
110
+ Repeat,
111
+ User,
112
+ Palette,
113
+ ShieldCheck,
114
+ SlidersHorizontal,
115
+ Puzzle
108
116
  };
117
+ var RAIL_PUSH_MS = 260;
118
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React3.useLayoutEffect : React3.useEffect;
109
119
  function getIcon(name) {
110
120
  return ICON_MAP[name] ?? Home;
111
121
  }
@@ -116,25 +126,23 @@ function NavItem({
116
126
  onNavigate
117
127
  }) {
118
128
  const Icon = getIcon(item.icon);
119
- const content = /* @__PURE__ */ jsxs(
120
- "button",
121
- {
122
- onClick: () => onNavigate(item.route),
123
- className: cn(
124
- "flex w-full items-center gap-3 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors",
125
- "hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
126
- isActive ? "bg-sidebar-accent font-semibold text-sidebar-accent-foreground shadow-sm" : "text-sidebar-foreground/80",
127
- collapsed && "justify-center px-2"
128
- ),
129
- children: [
130
- /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
131
- !collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
132
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
133
- item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-auto rounded-full bg-primary px-2 py-0.5 text-xs font-semibold text-primary-foreground", children: item.badge })
134
- ] })
135
- ]
136
- }
129
+ const isExternal = !!item.href;
130
+ const className = cn(
131
+ "flex w-full items-center gap-3 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors",
132
+ "hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
133
+ isActive ? "bg-sidebar-accent font-semibold text-sidebar-accent-foreground shadow-sm" : "text-sidebar-foreground/80",
134
+ collapsed && "justify-center px-2"
137
135
  );
136
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
137
+ /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
138
+ !collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
139
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
140
+ isExternal && /* @__PURE__ */ jsx(ExternalLink, { className: "ml-auto h-3.5 w-3.5 shrink-0 opacity-50", "aria-hidden": true }),
141
+ item.premium && /* @__PURE__ */ jsx(Crown, { className: cn("h-3.5 w-3.5 shrink-0 text-amber-500", !isExternal && "ml-auto"), "aria-hidden": true }),
142
+ item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-primary px-2 py-0.5 text-xs font-semibold text-primary-foreground", !isExternal && !item.premium && "ml-auto"), children: item.badge })
143
+ ] })
144
+ ] });
145
+ const content = isExternal ? /* @__PURE__ */ jsx("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className, children: inner }) : /* @__PURE__ */ jsx("button", { onClick: () => onNavigate(item.route), className, children: inner });
138
146
  if (collapsed) {
139
147
  return /* @__PURE__ */ jsxs(Tooltip.Root, { delayDuration: 0, children: [
140
148
  /* @__PURE__ */ jsx(Tooltip.Trigger, { asChild: true, children: content }),
@@ -146,6 +154,7 @@ function NavItem({
146
154
  className: "fayz-glass-surface z-50 rounded-md bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md",
147
155
  children: [
148
156
  item.label,
157
+ item.premium && /* @__PURE__ */ jsx(Crown, { className: "ml-1.5 inline h-3 w-3 text-amber-500", "aria-hidden": true }),
149
158
  item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-2 rounded-full bg-primary px-1.5 py-0.5 text-xs text-primary-foreground", children: item.badge }),
150
159
  /* @__PURE__ */ jsx(Tooltip.Arrow, { className: "fill-popover" })
151
160
  ]
@@ -226,21 +235,18 @@ function NavGroup({
226
235
  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) => {
227
236
  const ChildIcon = getIcon(child.icon);
228
237
  const isActive = child.route === activeRoute;
229
- return /* @__PURE__ */ jsxs(
230
- "button",
231
- {
232
- onClick: () => onNavigate(child.route),
233
- className: cn(
234
- "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
235
- isActive ? "font-medium text-sidebar-accent-foreground" : "text-sidebar-muted hover:text-sidebar-accent-foreground"
236
- ),
237
- children: [
238
- /* @__PURE__ */ jsx(ChildIcon, { className: "h-3.5 w-3.5 shrink-0" }),
239
- /* @__PURE__ */ jsx("span", { className: "truncate", children: child.label })
240
- ]
241
- },
242
- child.id
238
+ const childExternal = !!child.href;
239
+ const childClass = cn(
240
+ "flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
241
+ isActive ? "font-medium text-sidebar-accent-foreground" : "text-sidebar-muted hover:text-sidebar-accent-foreground"
243
242
  );
243
+ const childInner = /* @__PURE__ */ jsxs(Fragment, { children: [
244
+ /* @__PURE__ */ jsx(ChildIcon, { className: "h-3.5 w-3.5 shrink-0" }),
245
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: child.label }),
246
+ childExternal && /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 shrink-0 opacity-50", "aria-hidden": true }),
247
+ child.premium && /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3 shrink-0 text-amber-500", "aria-hidden": true })
248
+ ] });
249
+ return childExternal ? /* @__PURE__ */ jsx("a", { href: child.href, target: "_blank", rel: "noopener noreferrer", className: childClass, children: childInner }, child.id) : /* @__PURE__ */ jsx("button", { onClick: () => onNavigate(child.route), className: childClass, children: childInner }, child.id);
244
250
  }) })
245
251
  ] });
246
252
  }
@@ -258,7 +264,10 @@ function Sidebar({
258
264
  borderless,
259
265
  userMenuSlot,
260
266
  notificationSlot,
261
- unreadCount = 0
267
+ unreadCount = 0,
268
+ sectionLabels,
269
+ navKey,
270
+ navDirection = "forward"
262
271
  }) {
263
272
  const currentPath = currentPathProp;
264
273
  const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
@@ -269,6 +278,47 @@ function Sidebar({
269
278
  const handleNavigate = (route) => {
270
279
  onNavigate?.(route);
271
280
  };
281
+ const sectionHeading = (label) => label && !collapsed ? /* @__PURE__ */ jsx("p", { className: "px-2.5 pb-1 pt-1 text-[10px] font-semibold uppercase tracking-wider text-sidebar-muted", children: label }) : null;
282
+ const renderItem = (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, activeRoute, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
283
+ NavItem,
284
+ {
285
+ item,
286
+ collapsed,
287
+ isActive: item.route === activeRoute,
288
+ onNavigate: handleNavigate
289
+ },
290
+ item.id
291
+ );
292
+ const navBody = /* @__PURE__ */ jsxs(Fragment, { children: [
293
+ topContent && /* @__PURE__ */ jsx("div", { className: "mb-4 space-y-2", children: React3.isValidElement(topContent) ? React3.cloneElement(topContent, { collapsed }) : topContent }),
294
+ mainItems.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
295
+ sectionHeading(sectionLabels?.main),
296
+ mainItems.map(renderItem)
297
+ ] }),
298
+ secondaryItems.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-1", children: [
299
+ sectionHeading(sectionLabels?.secondary),
300
+ secondaryItems.map(renderItem)
301
+ ] })
302
+ ] });
303
+ const [outgoing, setOutgoing] = React3.useState(null);
304
+ const lastBodyRef = React3.useRef(null);
305
+ const lastKeyRef = React3.useRef(navKey);
306
+ const timerRef = React3.useRef(null);
307
+ useIsomorphicLayoutEffect(() => {
308
+ if (lastKeyRef.current !== navKey) {
309
+ const previousBody = lastBodyRef.current;
310
+ lastKeyRef.current = navKey;
311
+ if (previousBody) {
312
+ setOutgoing({ body: previousBody, direction: navDirection });
313
+ if (timerRef.current) clearTimeout(timerRef.current);
314
+ timerRef.current = setTimeout(() => setOutgoing(null), RAIL_PUSH_MS);
315
+ }
316
+ }
317
+ lastBodyRef.current = navBody;
318
+ });
319
+ React3.useEffect(() => () => {
320
+ if (timerRef.current) clearTimeout(timerRef.current);
321
+ }, []);
272
322
  return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsxs(
273
323
  "aside",
274
324
  {
@@ -312,33 +362,41 @@ function Sidebar({
312
362
  ]
313
363
  }
314
364
  ),
315
- /* @__PURE__ */ jsxs("nav", { className: "flex-1 space-y-1 overflow-y-auto p-2", children: [
316
- topContent && /* @__PURE__ */ jsx("div", { className: "mb-4 space-y-2", children: topContent }),
317
- mainItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-1", children: mainItems.map(
318
- (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, activeRoute, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
319
- NavItem,
320
- {
321
- item,
322
- collapsed,
323
- isActive: item.route === activeRoute,
324
- onNavigate: handleNavigate
325
- },
326
- item.id
327
- )
328
- ) }),
329
- secondaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6 space-y-1", children: secondaryItems.map(
330
- (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(NavGroup, { item, collapsed, activeRoute, onNavigate: handleNavigate }, item.id) : /* @__PURE__ */ jsx(
331
- NavItem,
332
- {
333
- item,
334
- collapsed,
335
- isActive: item.route === activeRoute,
336
- onNavigate: handleNavigate
337
- },
338
- item.id
339
- )
340
- ) })
341
- ] }),
365
+ /* @__PURE__ */ jsxs(
366
+ "nav",
367
+ {
368
+ className: cn(
369
+ "relative flex-1 p-2",
370
+ // scrollbar-none: the rail still scrolls, but without the native
371
+ // scrollbar gutter eating into the nav items.
372
+ outgoing ? "overflow-hidden" : "overflow-y-auto scrollbar-none"
373
+ ),
374
+ children: [
375
+ outgoing && /* @__PURE__ */ jsx(
376
+ "div",
377
+ {
378
+ "aria-hidden": true,
379
+ className: cn(
380
+ "pointer-events-none absolute inset-x-2 top-2 space-y-1",
381
+ outgoing.direction === "back" ? "saas-rail-out-back" : "saas-rail-out-forward"
382
+ ),
383
+ children: outgoing.body
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsx(
387
+ "div",
388
+ {
389
+ className: cn(
390
+ "space-y-1",
391
+ outgoing && (outgoing.direction === "back" ? "saas-rail-in-back" : "saas-rail-in-forward")
392
+ ),
393
+ children: navBody
394
+ },
395
+ navKey
396
+ )
397
+ ]
398
+ }
399
+ ),
342
400
  settingsItems.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("p-2 space-y-1", !borderless && "border-t border-sidebar-border"), children: settingsItems.map((item) => /* @__PURE__ */ jsx(
343
401
  NavItem,
344
402
  {
@@ -384,6 +442,8 @@ function Sidebar({
384
442
  }
385
443
  function TopbarUserMenu({
386
444
  user,
445
+ userPlan,
446
+ billingLabel = "Subscription",
387
447
  onSignOut,
388
448
  onProfile,
389
449
  onSettings,
@@ -434,11 +494,35 @@ function TopbarUserMenu({
434
494
  /* @__PURE__ */ jsxs("div", { className: "mt-1 space-y-0.5", children: [
435
495
  item("Perfil", onProfile, UserCog),
436
496
  item("Configura\xE7\xF5es", onSettings, Settings),
437
- item("Cobran\xE7a", onBilling, CreditCard),
497
+ onBilling && /* @__PURE__ */ jsxs(
498
+ "button",
499
+ {
500
+ onClick: () => {
501
+ setOpen(false);
502
+ onBilling();
503
+ },
504
+ className: "flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-sm text-popover-foreground transition-colors hover:bg-muted/70",
505
+ children: [
506
+ /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" }),
507
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: billingLabel }),
508
+ userPlan && /* @__PURE__ */ jsxs(
509
+ "span",
510
+ {
511
+ className: userPlan.paid ? "inline-flex items-center gap-1 rounded-full border border-amber-400/40 bg-amber-400/15 px-2 py-0.5 text-[10px] font-semibold text-amber-600 dark:text-amber-300" : "inline-flex items-center gap-1 rounded-full border border-border bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
512
+ children: [
513
+ userPlan.paid ? /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" }),
514
+ userPlan.label
515
+ ]
516
+ }
517
+ )
518
+ ]
519
+ },
520
+ "billing"
521
+ ),
438
522
  userMenuExtras?.map((e) => item(e.label, e.onClick)),
439
523
  onSignOut && /* @__PURE__ */ jsxs(Fragment, { children: [
440
524
  /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-border" }),
441
- item("Sair", onSignOut)
525
+ item("Sair", onSignOut, LogOut)
442
526
  ] })
443
527
  ] })
444
528
  ]
@@ -503,7 +587,7 @@ var ICON_MAP2 = {
503
587
  ArrowUpCircle,
504
588
  ArrowLeftRight,
505
589
  Plug,
506
- SlidersHorizontal,
590
+ SlidersHorizontal: SlidersHorizontal,
507
591
  TableProperties,
508
592
  Landmark: Landmark,
509
593
  Receipt: Receipt,
@@ -546,7 +630,9 @@ var ICON_MAP2 = {
546
630
  Star: Star,
547
631
  Zap: Zap,
548
632
  Clapperboard,
549
- Newspaper
633
+ Newspaper,
634
+ GraduationCap: GraduationCap,
635
+ Repeat: Repeat
550
636
  };
551
637
  function getIcon2(name) {
552
638
  return ICON_MAP2[name] ?? Home;
@@ -610,6 +696,7 @@ function Topbar({
610
696
  logo,
611
697
  user,
612
698
  onMenuClick,
699
+ orgSwitcher,
613
700
  leftContent,
614
701
  rightContent,
615
702
  currentPath = "/",
@@ -619,6 +706,8 @@ function Topbar({
619
706
  onProfile,
620
707
  onSettings,
621
708
  onBilling,
709
+ userPlan,
710
+ billingLabel,
622
711
  userMenuExtras
623
712
  }) {
624
713
  const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
@@ -640,7 +729,8 @@ function Topbar({
640
729
  children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
641
730
  }
642
731
  ),
643
- /* @__PURE__ */ jsx("div", { className: "hidden shrink-0 items-center md:flex", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) })
732
+ /* @__PURE__ */ jsx("div", { className: "hidden shrink-0 items-center md:flex", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) }),
733
+ orgSwitcher && /* @__PURE__ */ jsx("div", { className: "hidden min-w-0 items-center md:flex", children: orgSwitcher })
644
734
  ] }),
645
735
  /* @__PURE__ */ jsx("div", { className: "mx-8 hidden max-w-sm flex-1 md:flex", children: /* @__PURE__ */ jsxs(
646
736
  "button",
@@ -661,6 +751,8 @@ function Topbar({
661
751
  TopbarUserMenu,
662
752
  {
663
753
  user,
754
+ userPlan,
755
+ billingLabel,
664
756
  onSignOut,
665
757
  onProfile,
666
758
  onSettings,
@@ -703,6 +795,7 @@ function Topbar({
703
795
  children: [
704
796
  /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
705
797
  /* @__PURE__ */ jsx("span", { children: item.label }),
798
+ item.premium && /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3 text-amber-500", "aria-hidden": true }),
706
799
  item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-primary px-1.5 py-0.5 text-[10px] font-semibold text-primary-foreground", children: item.badge })
707
800
  ]
708
801
  },
@@ -742,7 +835,10 @@ function SidebarLayout({
742
835
  notificationSlot,
743
836
  unreadCount = 0,
744
837
  hasBottomNav = false,
745
- mobileHeader = "minimal"
838
+ mobileHeader = "minimal",
839
+ sidebarSectionLabels,
840
+ sidebarNavKey,
841
+ sidebarNavDirection
746
842
  }) {
747
843
  const sidebarCollapsed = useLayoutStore((s) => s.sidebarCollapsed);
748
844
  const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
@@ -776,7 +872,10 @@ function SidebarLayout({
776
872
  borderless: false,
777
873
  userMenuSlot,
778
874
  notificationSlot,
779
- unreadCount
875
+ unreadCount,
876
+ sectionLabels: sidebarSectionLabels,
877
+ navKey: sidebarNavKey,
878
+ navDirection: sidebarNavDirection
780
879
  }
781
880
  ) }),
782
881
  /* @__PURE__ */ jsxs("div", { className: cn(
@@ -806,7 +905,7 @@ function SidebarLayout({
806
905
  topbarEnd
807
906
  ] })
808
907
  ] }),
809
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto pb-16 md:pb-0", children }),
908
+ /* @__PURE__ */ jsx("main", { className: "min-w-0 flex-1 overflow-y-auto pb-16 md:pb-0", children }),
810
909
  /* @__PURE__ */ jsx(SaveBar, {})
811
910
  ] }),
812
911
  mobileMenuOpen && /* @__PURE__ */ jsx(
@@ -842,11 +941,15 @@ function TopbarLayout({
842
941
  onProfile,
843
942
  onSettings,
844
943
  onBilling,
944
+ userPlan,
945
+ billingLabel,
845
946
  userMenuExtras,
947
+ orgSwitcher,
846
948
  frame,
847
949
  currentPath,
848
950
  topbarStart,
849
951
  topbarEnd,
952
+ notificationSlot,
850
953
  hasBottomNav = false
851
954
  }) {
852
955
  const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
@@ -863,13 +966,19 @@ function TopbarLayout({
863
966
  onProfile,
864
967
  onSettings,
865
968
  onBilling,
969
+ userPlan,
970
+ billingLabel,
866
971
  userMenuExtras,
972
+ orgSwitcher,
867
973
  leftContent: topbarStart,
868
- rightContent: topbarEnd,
974
+ rightContent: topbarEnd || notificationSlot ? /* @__PURE__ */ jsxs(Fragment, { children: [
975
+ topbarEnd,
976
+ notificationSlot
977
+ ] }) : void 0,
869
978
  onMenuClick: hasBottomNav ? void 0 : () => setMobileMenuOpen(true)
870
979
  }
871
980
  ),
872
- /* @__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 }) }),
981
+ /* @__PURE__ */ jsx("main", { className: cn("flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", frame && "md:bg-sidebar md:p-2"), children: /* @__PURE__ */ jsx("div", { className: cn("flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", frame && "md:rounded-xl md:border md:border-border md:bg-card"), children: /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pb-16 md:pb-0", children }) }) }),
873
982
  /* @__PURE__ */ jsx(SaveBar, {}),
874
983
  mobileMenuOpen && /* @__PURE__ */ jsx(
875
984
  MobileOverlay,
@@ -883,6 +992,7 @@ function TopbarLayout({
883
992
  onProfile,
884
993
  onSettings,
885
994
  onBilling,
995
+ orgSwitcher,
886
996
  userMenuSlot: user ? /* @__PURE__ */ jsx(DrawerUserRow, { user }) : void 0,
887
997
  onClose: () => setMobileMenuOpen(false)
888
998
  }
@@ -907,7 +1017,7 @@ function MinimalLayout({
907
1017
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) }),
908
1018
  headerEnd && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: headerEnd })
909
1019
  ] }),
910
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-y-auto pb-16 md:pb-0", children })
1020
+ /* @__PURE__ */ jsx("main", { className: "min-w-0 flex-1 overflow-y-auto pb-16 md:pb-0", children })
911
1021
  ] });
912
1022
  }
913
1023
  function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
@@ -1057,6 +1167,8 @@ function AppShell({
1057
1167
  onProfile,
1058
1168
  onSettings,
1059
1169
  onBilling,
1170
+ userPlan,
1171
+ billingLabel,
1060
1172
  pageTitle,
1061
1173
  currentPath,
1062
1174
  userMenuExtras,
@@ -1070,7 +1182,17 @@ function AppShell({
1070
1182
  mobileHeader = "minimal",
1071
1183
  userMenuSlot,
1072
1184
  notificationSlot,
1073
- unreadCount = 0
1185
+ unreadCount = 0,
1186
+ sidebarSectionLabels,
1187
+ sidebarNavKey,
1188
+ sidebarNavDirection,
1189
+ rightRail,
1190
+ rightRailOpen = true,
1191
+ defaultRightRailWidth,
1192
+ onRightRailWidthChange,
1193
+ rightRailMinWidth,
1194
+ rightRailMaxWidth,
1195
+ rightRailResizeLabel
1074
1196
  }) {
1075
1197
  const hasBottomNav = !!bottomNav?.length;
1076
1198
  const bottomBar = hasBottomNav ? /* @__PURE__ */ jsx(
@@ -1111,6 +1233,9 @@ function AppShell({
1111
1233
  unreadCount,
1112
1234
  hasBottomNav,
1113
1235
  mobileHeader,
1236
+ sidebarSectionLabels,
1237
+ sidebarNavKey,
1238
+ sidebarNavDirection,
1114
1239
  children
1115
1240
  }
1116
1241
  );
@@ -1127,11 +1252,15 @@ function AppShell({
1127
1252
  onProfile,
1128
1253
  onSettings,
1129
1254
  onBilling,
1255
+ userPlan,
1256
+ billingLabel,
1130
1257
  userMenuExtras,
1258
+ orgSwitcher,
1131
1259
  frame: contentFrame,
1132
1260
  currentPath,
1133
1261
  topbarStart,
1134
1262
  topbarEnd,
1263
+ notificationSlot,
1135
1264
  hasBottomNav,
1136
1265
  children
1137
1266
  }
@@ -1145,11 +1274,142 @@ function AppShell({
1145
1274
  }
1146
1275
  }
1147
1276
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1148
- layoutElement,
1277
+ rightRail ? /* @__PURE__ */ jsx(
1278
+ SplitWithRightRail,
1279
+ {
1280
+ rail: rightRail,
1281
+ open: rightRailOpen,
1282
+ frame: contentFrame,
1283
+ defaultWidth: defaultRightRailWidth,
1284
+ onWidthChange: onRightRailWidthChange,
1285
+ minWidth: rightRailMinWidth,
1286
+ maxWidth: rightRailMaxWidth,
1287
+ resizeLabel: rightRailResizeLabel,
1288
+ children: layoutElement
1289
+ }
1290
+ ) : layoutElement,
1149
1291
  floatingAvatar,
1150
1292
  bottomBar
1151
1293
  ] });
1152
1294
  }
1295
+ function SplitWithRightRail({
1296
+ children,
1297
+ rail,
1298
+ open,
1299
+ frame,
1300
+ defaultWidth = 380,
1301
+ onWidthChange,
1302
+ minWidth = 300,
1303
+ maxWidth = 720,
1304
+ resizeLabel = "Resize panel"
1305
+ }) {
1306
+ const [width, setWidth] = React3.useState(defaultWidth);
1307
+ const [dragging, setDragging] = React3.useState(false);
1308
+ const clamp = React3.useCallback(
1309
+ (value) => Math.min(maxWidth, Math.max(minWidth, value)),
1310
+ [minWidth, maxWidth]
1311
+ );
1312
+ React3.useEffect(() => {
1313
+ if (!dragging) return;
1314
+ const onMove = (event) => {
1315
+ event.preventDefault();
1316
+ setWidth(clamp(window.innerWidth - event.clientX));
1317
+ };
1318
+ const stop = () => setDragging(false);
1319
+ window.addEventListener("pointermove", onMove);
1320
+ window.addEventListener("pointerup", stop);
1321
+ window.addEventListener("pointercancel", stop);
1322
+ const previousSelect = document.body.style.userSelect;
1323
+ const previousCursor = document.body.style.cursor;
1324
+ document.body.style.userSelect = "none";
1325
+ document.body.style.cursor = "col-resize";
1326
+ return () => {
1327
+ window.removeEventListener("pointermove", onMove);
1328
+ window.removeEventListener("pointerup", stop);
1329
+ window.removeEventListener("pointercancel", stop);
1330
+ document.body.style.userSelect = previousSelect;
1331
+ document.body.style.cursor = previousCursor;
1332
+ };
1333
+ }, [dragging, clamp]);
1334
+ React3.useEffect(() => {
1335
+ if (dragging) return;
1336
+ onWidthChange?.(width);
1337
+ }, [dragging]);
1338
+ const nudge = (delta) => setWidth((current) => clamp(current + delta));
1339
+ return (
1340
+ // Sidebar tone always: the gutter and the divider sit in the shell's
1341
+ // chrome, next to the menu — painting them page-white put a bright strip
1342
+ // between the dark chrome and the rail, which read as a seam rather than
1343
+ // as space.
1344
+ /* @__PURE__ */ jsxs("div", { className: cn("flex h-screen w-full overflow-hidden bg-sidebar", !frame && "md:bg-background"), children: [
1345
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children }),
1346
+ /* @__PURE__ */ jsxs(
1347
+ "div",
1348
+ {
1349
+ role: "separator",
1350
+ "aria-orientation": "vertical",
1351
+ "aria-label": resizeLabel,
1352
+ "aria-valuenow": width,
1353
+ "aria-valuemin": minWidth,
1354
+ "aria-valuemax": maxWidth,
1355
+ tabIndex: 0,
1356
+ onPointerDown: (event) => {
1357
+ event.preventDefault();
1358
+ setDragging(true);
1359
+ },
1360
+ onDoubleClick: () => setWidth(clamp(defaultWidth)),
1361
+ onKeyDown: (event) => {
1362
+ if (event.key === "ArrowLeft") {
1363
+ event.preventDefault();
1364
+ nudge(24);
1365
+ } else if (event.key === "ArrowRight") {
1366
+ event.preventDefault();
1367
+ nudge(-24);
1368
+ } else if (event.key === "Home") {
1369
+ event.preventDefault();
1370
+ setWidth(maxWidth);
1371
+ } else if (event.key === "End") {
1372
+ event.preventDefault();
1373
+ setWidth(minWidth);
1374
+ }
1375
+ },
1376
+ className: cn(
1377
+ "group relative hidden w-1 shrink-0 cursor-col-resize focus-visible:outline-none",
1378
+ open && "md:block"
1379
+ ),
1380
+ children: [
1381
+ /* @__PURE__ */ jsx(
1382
+ "span",
1383
+ {
1384
+ className: cn(
1385
+ "absolute inset-y-6 left-1/2 w-px -translate-x-1/2 rounded-full bg-transparent transition-colors",
1386
+ "group-hover:bg-primary/60 group-focus-visible:bg-primary",
1387
+ dragging && "bg-primary"
1388
+ )
1389
+ }
1390
+ ),
1391
+ /* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 -left-1.5 -right-1.5" })
1392
+ ]
1393
+ }
1394
+ ),
1395
+ /* @__PURE__ */ jsx(
1396
+ "aside",
1397
+ {
1398
+ style: { ["--fayz-rail-w"]: `${width}px` },
1399
+ className: cn(
1400
+ "w-0 shrink-0 overflow-hidden",
1401
+ // Animating WIDTH is what makes the app glide back instead of
1402
+ // snapping; skipped mid-drag so the divider stays glued to the cursor.
1403
+ !dragging && "motion-safe:transition-[width] motion-safe:duration-200 motion-safe:ease-out",
1404
+ open && "md:w-[var(--fayz-rail-w)]",
1405
+ frame && "md:py-2 md:pr-2"
1406
+ ),
1407
+ children: rail
1408
+ }
1409
+ )
1410
+ ] })
1411
+ );
1412
+ }
1153
1413
  var NavTransitionContext = React3.createContext("slide");
1154
1414
  function NavTransitionProvider({ value, children }) {
1155
1415
  return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
@@ -1179,6 +1439,11 @@ function PageHeaderActions({ children }) {
1179
1439
  if (slot) return createPortal(children, slot);
1180
1440
  return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
1181
1441
  }
1442
+ function PremiumBadge({ className }) {
1443
+ const t = useTranslation();
1444
+ const tip = t("upgrade.badgeTooltip");
1445
+ return /* @__PURE__ */ jsx("span", { title: tip, "aria-label": tip, className: cn("inline-flex shrink-0", className), children: /* @__PURE__ */ jsx(Crown, { className: "h-3.5 w-3.5 text-amber-500", "aria-hidden": true }) });
1446
+ }
1182
1447
  var ModuleLayoutContext = React3.createContext("rail");
1183
1448
  function ModuleLayoutProvider({ variant, children }) {
1184
1449
  return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
@@ -1205,11 +1470,12 @@ function NavItem2({ item }) {
1205
1470
  children: [
1206
1471
  Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
1207
1472
  /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: item.label }),
1473
+ item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
1208
1474
  hasChildren && (expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 opacity-50" }))
1209
1475
  ]
1210
1476
  }
1211
1477
  ),
1212
- hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2", children: item.children.map((child) => /* @__PURE__ */ jsx(
1478
+ hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2", children: item.children.map((child) => /* @__PURE__ */ jsxs(
1213
1479
  "button",
1214
1480
  {
1215
1481
  type: "button",
@@ -1218,7 +1484,10 @@ function NavItem2({ item }) {
1218
1484
  "flex items-center w-full rounded-md px-2.5 py-1 text-xs transition-colors",
1219
1485
  child.active ? "text-primary font-medium bg-primary/5" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
1220
1486
  ),
1221
- children: child.label
1487
+ children: [
1488
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: child.label }),
1489
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
1490
+ ]
1222
1491
  },
1223
1492
  child.id
1224
1493
  )) })
@@ -1262,6 +1531,7 @@ function MobileTabs({ nav }) {
1262
1531
  children: [
1263
1532
  Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3" }),
1264
1533
  item.label,
1534
+ item.premium && /* @__PURE__ */ jsx(PremiumBadge, {}),
1265
1535
  hasChildren && /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-2.5 w-2.5 transition-transform", isExpanded && "rotate-180") })
1266
1536
  ]
1267
1537
  },
@@ -1271,7 +1541,7 @@ function MobileTabs({ nav }) {
1271
1541
  expandedId && (() => {
1272
1542
  const item = nav.find((n) => n.id === expandedId);
1273
1543
  if (!item?.children) return null;
1274
- return /* @__PURE__ */ jsx("div", { className: "flex gap-1 px-2 pb-2 animate-in fade-in-0 slide-in-from-top-1", children: item.children.map((child) => /* @__PURE__ */ jsx(
1544
+ return /* @__PURE__ */ jsx("div", { className: "flex gap-1 px-2 pb-2 animate-in fade-in-0 slide-in-from-top-1", children: item.children.map((child) => /* @__PURE__ */ jsxs(
1275
1545
  "button",
1276
1546
  {
1277
1547
  type: "button",
@@ -1283,7 +1553,10 @@ function MobileTabs({ nav }) {
1283
1553
  "whitespace-nowrap rounded-full px-2.5 py-1 text-[11px] font-medium transition-colors shrink-0",
1284
1554
  child.active ? "bg-foreground/10 text-foreground" : "text-muted-foreground hover:text-foreground"
1285
1555
  ),
1286
- children: child.label
1556
+ children: [
1557
+ child.label,
1558
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, {})
1559
+ ]
1287
1560
  },
1288
1561
  child.id
1289
1562
  )) });
@@ -1375,7 +1648,8 @@ function ModuleHeader({ nav }) {
1375
1648
  ),
1376
1649
  children: [
1377
1650
  Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }),
1378
- item.label
1651
+ item.label,
1652
+ item.premium && /* @__PURE__ */ jsx(PremiumBadge, {})
1379
1653
  ]
1380
1654
  },
1381
1655
  item.id
@@ -1503,5 +1777,5 @@ function ContentSplitTrigger({ label, iconOnly, className }) {
1503
1777
  }
1504
1778
 
1505
1779
  export { AppShell, BackStyleProvider, ContentSplit, ContentSplitTrigger, ICON_MAP, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeaderActions, PageTransition, Sidebar, SubpageHeader, Topbar, useBackStyle, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition };
1506
- //# sourceMappingURL=chunk-MZZMZYSE.js.map
1507
- //# sourceMappingURL=chunk-MZZMZYSE.js.map
1780
+ //# sourceMappingURL=chunk-VVQ45ZDZ.js.map
1781
+ //# sourceMappingURL=chunk-VVQ45ZDZ.js.map