@fayz-ai/ui 0.33.0 → 0.33.1

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 (48) hide show
  1. package/dist/{chunk-PL5CUWNE.js → chunk-33A7SN2N.js} +583 -119
  2. package/dist/chunk-33A7SN2N.js.map +1 -0
  3. package/dist/{chunk-UFT3MA5H.js → chunk-6GWXDVCO.js} +203 -15
  4. package/dist/chunk-6GWXDVCO.js.map +1 -0
  5. package/dist/{chunk-NXSDQ7HO.js → chunk-Q2B5RPH5.js} +13 -16
  6. package/dist/chunk-Q2B5RPH5.js.map +1 -0
  7. package/dist/{chunk-3XKDGBP4.js → chunk-UNEEY5XG.js} +3 -3
  8. package/dist/{chunk-3XKDGBP4.js.map → chunk-UNEEY5XG.js.map} +1 -1
  9. package/dist/dashboard/DashboardGrid.d.ts +8 -1
  10. package/dist/dashboard/DashboardGrid.d.ts.map +1 -1
  11. package/dist/dashboard/KpiCard.d.ts.map +1 -1
  12. package/dist/dashboard/index.js +3 -3
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +8 -8
  16. package/dist/layout/AppShell.d.ts.map +1 -1
  17. package/dist/layout/ModulePage.d.ts +47 -1
  18. package/dist/layout/ModulePage.d.ts.map +1 -1
  19. package/dist/layout/Sidebar.d.ts.map +1 -1
  20. package/dist/layout/index.d.ts +1 -1
  21. package/dist/layout/index.d.ts.map +1 -1
  22. package/dist/layout/index.js +1 -1
  23. package/dist/layout/rail-flyout.d.ts.map +1 -1
  24. package/dist/primitives/collapsible-column.d.ts +38 -0
  25. package/dist/primitives/collapsible-column.d.ts.map +1 -0
  26. package/dist/primitives/coming-soon.d.ts +31 -0
  27. package/dist/primitives/coming-soon.d.ts.map +1 -0
  28. package/dist/primitives/filter-panel.d.ts +85 -0
  29. package/dist/primitives/filter-panel.d.ts.map +1 -0
  30. package/dist/primitives/filter-rail.d.ts +10 -7
  31. package/dist/primitives/filter-rail.d.ts.map +1 -1
  32. package/dist/primitives/header-tabs.d.ts +9 -35
  33. package/dist/primitives/header-tabs.d.ts.map +1 -1
  34. package/dist/primitives/index.d.ts +2 -0
  35. package/dist/primitives/index.d.ts.map +1 -1
  36. package/dist/primitives/index.js +3 -3
  37. package/dist/primitives/nav-connector.d.ts +23 -0
  38. package/dist/primitives/nav-connector.d.ts.map +1 -0
  39. package/dist/primitives/search-select.d.ts.map +1 -1
  40. package/dist/stores/index.d.ts +1 -1
  41. package/dist/stores/index.d.ts.map +1 -1
  42. package/dist/stores/page-header.store.d.ts +17 -0
  43. package/dist/stores/page-header.store.d.ts.map +1 -1
  44. package/dist/styles.css +58 -0
  45. package/package.json +1 -1
  46. package/dist/chunk-NXSDQ7HO.js.map +0 -1
  47. package/dist/chunk-PL5CUWNE.js.map +0 -1
  48. package/dist/chunk-UFT3MA5H.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { cn } from './chunk-OKZ6WQB3.js';
2
2
  import { ICON_MAP } from './chunk-ATDIWKBD.js';
3
3
  import * as React11 from 'react';
4
- import { Loader2, ChevronLeft, ArrowLeft, X, Bell, PanelLeft, PanelLeftClose, Search, CornerDownLeft, Menu, Crown, ChevronDown, ChevronRight, Info, ExternalLink, CreditCard, Sparkles, Home, ChevronUp, Plus, Settings, UserCog, LogOut } from 'lucide-react';
4
+ import { Loader2, ChevronLeft, ArrowLeft, X, Bell, PanelLeft, PanelLeftClose, Search, CornerDownLeft, Menu, Crown, ChevronsRight, ChevronsLeft, ChevronDown, ChevronRight, Info, ExternalLink, CreditCard, Sparkles, Home, ChevronUp, Plus, Settings, UserCog, LogOut } from 'lucide-react';
5
5
  import { useTranslation, useNavReferrer, routeModule, navHistoryBack, recordNavigation } from '@fayz-ai/core';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
@@ -215,6 +215,8 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
215
215
  ));
216
216
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
217
217
  var usePageHeaderStore = create((set, get) => ({
218
+ moduleViewLabel: null,
219
+ setModuleViewLabel: (moduleViewLabel) => set((state) => state.moduleViewLabel === moduleViewLabel ? state : { moduleViewLabel }),
218
220
  shellSlot: null,
219
221
  setShellSlot: (element) => set({ shellSlot: element }),
220
222
  outletSlot: null,
@@ -317,6 +319,16 @@ function usePageHeader(active, options) {
317
319
  function useHasPageHeaderBack() {
318
320
  return usePageHeaderStore((s) => s.hasBack);
319
321
  }
322
+ function useModuleViewLabel() {
323
+ return usePageHeaderStore((s) => s.moduleViewLabel);
324
+ }
325
+ function usePublishModuleViewLabel(label) {
326
+ const setLabel = usePageHeaderStore((s) => s.setModuleViewLabel);
327
+ React11.useEffect(() => {
328
+ setLabel(label ?? null);
329
+ return () => setLabel(null);
330
+ }, [label, setLabel]);
331
+ }
320
332
  function PageTitlePortal({ children }) {
321
333
  const slot = usePageTitleSlot();
322
334
  if (!slot) return React11.createElement(React11.Fragment, null, children);
@@ -555,6 +567,7 @@ function useRailFlyout({
555
567
  "div",
556
568
  {
557
569
  ref: panelRef,
570
+ style: { borderTopLeftRadius: 2, borderBottomLeftRadius: 2 },
558
571
  className: cn(
559
572
  // Sidebar tone, sidebar border: the panel is the menu leaning out,
560
573
  // not a popover from the page underneath it.
@@ -635,6 +648,51 @@ function FlyoutBody({
635
648
  ] })
636
649
  ] });
637
650
  }
651
+ function NavChildConnector({ onPath, active }) {
652
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
653
+ onPath && /* @__PURE__ */ jsx(
654
+ "span",
655
+ {
656
+ "aria-hidden": true,
657
+ className: "pointer-events-none absolute bottom-0 left-[13px] top-0 w-[1.5px] bg-current"
658
+ }
659
+ ),
660
+ active && /* @__PURE__ */ jsxs(
661
+ "svg",
662
+ {
663
+ "aria-hidden": true,
664
+ className: "pointer-events-none absolute left-1 top-0",
665
+ width: "21",
666
+ height: "32",
667
+ viewBox: "0 0 21 32",
668
+ fill: "none",
669
+ children: [
670
+ /* @__PURE__ */ jsx(
671
+ "path",
672
+ {
673
+ d: "M9.75 0 V11 Q9.75 16 14.75 16 H20",
674
+ stroke: "currentColor",
675
+ strokeWidth: "1.5",
676
+ strokeLinecap: "round",
677
+ fill: "none"
678
+ }
679
+ ),
680
+ /* @__PURE__ */ jsx(
681
+ "path",
682
+ {
683
+ d: "M17 13 L20 16 L17 19",
684
+ stroke: "currentColor",
685
+ strokeWidth: "1.5",
686
+ strokeLinecap: "round",
687
+ strokeLinejoin: "round",
688
+ fill: "none"
689
+ }
690
+ )
691
+ ]
692
+ }
693
+ )
694
+ ] });
695
+ }
638
696
  var RAIL_PUSH_MS = 260;
639
697
  var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ? React11.useLayoutEffect : React11.useEffect;
640
698
  function getIcon(name) {
@@ -861,47 +919,7 @@ function NavGroup({
861
919
  // to /70 when inactive, and a line fading along with the label it
862
920
  // points AT was nearly invisible on a dark rail.
863
921
  /* @__PURE__ */ jsxs("div", { className: "relative h-8 text-sidebar-foreground/45", children: [
864
- onPath && /* @__PURE__ */ jsx(
865
- "span",
866
- {
867
- "aria-hidden": true,
868
- className: "pointer-events-none absolute bottom-0 left-[13px] top-0 w-[1.5px] bg-current"
869
- }
870
- ),
871
- isActive && /* @__PURE__ */ jsxs(
872
- "svg",
873
- {
874
- "aria-hidden": true,
875
- className: "pointer-events-none absolute left-1 top-0",
876
- width: "21",
877
- height: "32",
878
- viewBox: "0 0 21 32",
879
- fill: "none",
880
- children: [
881
- /* @__PURE__ */ jsx(
882
- "path",
883
- {
884
- d: "M9.75 0 V11 Q9.75 16 14.75 16 H20",
885
- stroke: "currentColor",
886
- strokeWidth: "1.5",
887
- strokeLinecap: "round",
888
- fill: "none"
889
- }
890
- ),
891
- /* @__PURE__ */ jsx(
892
- "path",
893
- {
894
- d: "M17 13 L20 16 L17 19",
895
- stroke: "currentColor",
896
- strokeWidth: "1.5",
897
- strokeLinecap: "round",
898
- strokeLinejoin: "round",
899
- fill: "none"
900
- }
901
- )
902
- ]
903
- }
904
- ),
922
+ /* @__PURE__ */ jsx(NavChildConnector, { onPath, active: isActive }),
905
923
  row
906
924
  ] }, child.id)
907
925
  );
@@ -2076,16 +2094,43 @@ function SidebarLayout({
2076
2094
  frame && (railOpen ? "md:rounded-r-none md:border-r-0" : "md:mr-2"),
2077
2095
  immersive && "md:overflow-hidden"
2078
2096
  ), children: [
2079
- /* @__PURE__ */ jsxs("div", { className: cn(
2080
- "relative z-20 flex min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-3 md:px-6",
2081
- menuOpen && "invisible md:visible"
2082
- ), children: [
2083
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
2084
- !pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack, primary: pagePrimary }),
2085
- /* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" })
2086
- ] }),
2087
- /* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
2088
- ] }),
2097
+ /* @__PURE__ */ jsxs(
2098
+ "div",
2099
+ {
2100
+ style: {
2101
+ // A RÉGUA NÃO ATRAVESSA A COLUNA DO MÓDULO.
2102
+ //
2103
+ // Ela fecha o cabeçalho, e o cabeçalho termina onde a coluna começa:
2104
+ // sobre a coluna, a mesma linha separava duas coisas que são uma só —
2105
+ // o nome da tela e o menu que pende dele. Tapar o pedaço com um pixel
2106
+ // da cor do papel funcionava num tema e falhava no outro, porque o
2107
+ // papel do cartão e o `--page-surface` nem sempre são a mesma tinta.
2108
+ //
2109
+ // Então ela NASCE depois: a régua é um degradê de 1px que só começa
2110
+ // em `--page-rail-seam` — a largura da coluna mais o raio da curva,
2111
+ // publicado por quem a desenha (ver RailColumn). Sem coluna, a
2112
+ // variável não existe e a régua começa em zero, como sempre.
2113
+ backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
2114
+ backgroundSize: "100% 1px",
2115
+ backgroundRepeat: "no-repeat",
2116
+ backgroundPosition: "left bottom"
2117
+ },
2118
+ className: cn(
2119
+ // O MESMO vidro da coluna do módulo logo abaixo — uma classe só,
2120
+ // senão as duas superfícies encostadas saem em tons diferentes e
2121
+ // a emenda que acabamos de apagar volta como degrau de cor.
2122
+ "fz-liquid-glass relative z-20 flex min-h-12 shrink-0 items-center justify-between gap-3 px-3 md:px-6",
2123
+ menuOpen && "invisible md:visible"
2124
+ ),
2125
+ children: [
2126
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
2127
+ !pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack, primary: pagePrimary }),
2128
+ /* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" })
2129
+ ] }),
2130
+ /* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
2131
+ ]
2132
+ }
2133
+ ),
2089
2134
  /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 overflow-hidden", children: [
2090
2135
  /* @__PURE__ */ jsx("div", { ref: setPageRailSlot, className: "flex shrink-0 empty:hidden" }),
2091
2136
  /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", children: [
@@ -2223,10 +2268,16 @@ function TopbarLayout({
2223
2268
  (pageHeaderClaimed || pageBack || hasPageActions || barOwnsNav) && /* @__PURE__ */ jsxs(
2224
2269
  "div",
2225
2270
  {
2271
+ style: {
2272
+ backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
2273
+ backgroundSize: "100% 1px",
2274
+ backgroundRepeat: "no-repeat",
2275
+ backgroundPosition: "left bottom"
2276
+ },
2226
2277
  className: cn(
2227
2278
  // `relative` + glass for the same reason as the sidebar
2228
2279
  // layout's band: on a phone this IS the navigation bar.
2229
- "relative flex min-h-[44px] md:min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-2",
2280
+ "relative flex min-h-[44px] md:min-h-12 shrink-0 items-center justify-between gap-3 px-4 py-2",
2230
2281
  menuOpen && "invisible md:visible",
2231
2282
  "fayz-glass-topbar",
2232
2283
  !(pageHeaderClaimed || pageBack || hasPageActions) && "md:hidden"
@@ -3371,6 +3422,14 @@ function HeaderTabs({
3371
3422
  }
3372
3423
  );
3373
3424
  }
3425
+ var PAGE_BAND_CLASS = "sticky top-0 z-20 -mx-3 -mt-3 mb-4 flex flex-nowrap items-end justify-between gap-3 border-b border-border px-3 pt-2 md:-mx-6 md:-mt-4 md:px-6 md:min-h-[2.5rem]";
3426
+ var PAGE_BAND_SURFACE = { background: "var(--page-surface, hsl(var(--background)))" };
3427
+ function PageBand({ children, actions, className }) {
3428
+ return /* @__PURE__ */ jsxs("div", { style: PAGE_BAND_SURFACE, className: cn(PAGE_BAND_CLASS, "items-center", className), children: [
3429
+ /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-3", children }),
3430
+ actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2 empty:hidden", children: actions })
3431
+ ] });
3432
+ }
3374
3433
  function PageTabs({ actions, className, ...props }) {
3375
3434
  return /* @__PURE__ */ jsxs(
3376
3435
  "div",
@@ -3473,15 +3532,15 @@ function navigateToCrumb(crumb) {
3473
3532
  else window.location.hash = crumb.href;
3474
3533
  }
3475
3534
  function useCurrentRouteHref() {
3476
- const read = () => {
3535
+ const read2 = () => {
3477
3536
  if (typeof window === "undefined") return "";
3478
3537
  const hash = window.location.hash.replace(/^#/, "");
3479
3538
  const clean = hash.split("?")[0];
3480
3539
  return clean.startsWith("/") ? clean : `/${clean}`;
3481
3540
  };
3482
- const [href, setHref] = React11.useState(read);
3541
+ const [href, setHref] = React11.useState(read2);
3483
3542
  React11.useEffect(() => {
3484
- const handler = () => setHref(read());
3543
+ const handler = () => setHref(read2());
3485
3544
  window.addEventListener("hashchange", handler);
3486
3545
  handler();
3487
3546
  return () => window.removeEventListener("hashchange", handler);
@@ -3496,6 +3555,241 @@ function useTrailBack(href) {
3496
3555
  [parent]
3497
3556
  );
3498
3557
  }
3558
+ var COLUMN_WIDTH = 224;
3559
+ var COLUMN_COLLAPSED_WIDTH = 64;
3560
+ function read(key) {
3561
+ try {
3562
+ return localStorage.getItem(key) === "1";
3563
+ } catch {
3564
+ return false;
3565
+ }
3566
+ }
3567
+ function CollapsibleColumn({
3568
+ children,
3569
+ storageKey,
3570
+ footer,
3571
+ squeezed,
3572
+ autoCollapseKey,
3573
+ autoCollapseMs = 1800,
3574
+ onWidth,
3575
+ className,
3576
+ seamTop = 12,
3577
+ "aria-label": ariaLabel
3578
+ }) {
3579
+ const pinnedKey = `${storageKey}.pinned`;
3580
+ const [collapsed, setCollapsed] = React11.useState(() => read(storageKey));
3581
+ const [pinned, setPinned] = React11.useState(() => read(pinnedKey));
3582
+ const [hovering, setHovering] = React11.useState(false);
3583
+ const hoveringRef = React11.useRef(false);
3584
+ const collapsedRef = React11.useRef(collapsed);
3585
+ collapsedRef.current = collapsed;
3586
+ const autoRef = React11.useRef(false);
3587
+ const open = !collapsed || hovering;
3588
+ const width = open ? COLUMN_WIDTH : COLUMN_COLLAPSED_WIDTH;
3589
+ const setHover = (on) => {
3590
+ hoveringRef.current = on;
3591
+ setHovering(on);
3592
+ };
3593
+ React11.useEffect(() => {
3594
+ onWidth?.(width);
3595
+ }, [width, onWidth]);
3596
+ const setOpenState = React11.useCallback((nextCollapsed) => {
3597
+ setCollapsed(nextCollapsed);
3598
+ setPinned(!nextCollapsed);
3599
+ autoRef.current = false;
3600
+ try {
3601
+ localStorage.setItem(storageKey, nextCollapsed ? "1" : "0");
3602
+ localStorage.setItem(pinnedKey, nextCollapsed ? "0" : "1");
3603
+ } catch {
3604
+ }
3605
+ if (nextCollapsed) setHover(false);
3606
+ }, [storageKey, pinnedKey]);
3607
+ React11.useEffect(() => {
3608
+ if (squeezed === void 0) return;
3609
+ if (squeezed) {
3610
+ if (!collapsedRef.current) {
3611
+ autoRef.current = true;
3612
+ setCollapsed(true);
3613
+ }
3614
+ } else if (autoRef.current) {
3615
+ autoRef.current = false;
3616
+ setCollapsed(false);
3617
+ }
3618
+ }, [squeezed]);
3619
+ const seen = React11.useRef(null);
3620
+ React11.useEffect(() => {
3621
+ if (autoCollapseKey === void 0) return;
3622
+ if (seen.current === null) {
3623
+ seen.current = autoCollapseKey;
3624
+ return;
3625
+ }
3626
+ if (seen.current === autoCollapseKey) return;
3627
+ seen.current = autoCollapseKey;
3628
+ if (collapsed || pinned) return;
3629
+ const t = setTimeout(() => {
3630
+ if (!hoveringRef.current) setCollapsed(true);
3631
+ }, autoCollapseMs);
3632
+ return () => clearTimeout(t);
3633
+ }, [autoCollapseKey, collapsed, pinned, autoCollapseMs]);
3634
+ const scrollRef = React11.useRef(null);
3635
+ const [hasMore, setHasMore] = React11.useState(false);
3636
+ const onScroll = React11.useCallback(() => {
3637
+ const el = scrollRef.current;
3638
+ if (!el) return;
3639
+ setHasMore(el.scrollHeight - el.scrollTop - el.clientHeight > 4);
3640
+ }, []);
3641
+ React11.useEffect(() => {
3642
+ onScroll();
3643
+ const el = scrollRef.current;
3644
+ if (!el) return;
3645
+ const ro = new ResizeObserver(onScroll);
3646
+ ro.observe(el);
3647
+ return () => {
3648
+ ro.disconnect();
3649
+ };
3650
+ }, [onScroll, open, children]);
3651
+ const boxRef = React11.useRef(null);
3652
+ const panelRef = React11.useRef(null);
3653
+ const [seamed, setSeamed] = React11.useState(false);
3654
+ const armedRef = React11.useRef(false);
3655
+ const publish = React11.useCallback(() => {
3656
+ if (!seamTop) return;
3657
+ const el = panelRef.current;
3658
+ const card = el?.closest(".fz-page-surface");
3659
+ const band = card?.firstElementChild;
3660
+ if (!el || !card || !band) return;
3661
+ const root = document.documentElement;
3662
+ const flush = Math.abs(el.getBoundingClientRect().top - band.getBoundingClientRect().bottom) <= 2;
3663
+ setSeamed(flush);
3664
+ if (!flush) {
3665
+ root.style.removeProperty("--page-rail-seam");
3666
+ return;
3667
+ }
3668
+ const x = el.getBoundingClientRect().right - card.getBoundingClientRect().left;
3669
+ if (!armedRef.current) root.style.transition = "none";
3670
+ root.style.setProperty("--page-rail-seam", `${x + seamTop}px`);
3671
+ if (!armedRef.current) {
3672
+ armedRef.current = true;
3673
+ requestAnimationFrame(() => {
3674
+ root.style.transition = "--page-rail-seam 200ms";
3675
+ });
3676
+ }
3677
+ }, [seamTop]);
3678
+ React11.useEffect(() => {
3679
+ publish();
3680
+ }, [publish, width]);
3681
+ React11.useEffect(() => {
3682
+ if (!seamTop) return;
3683
+ const el = panelRef.current;
3684
+ const card = el?.closest(".fz-page-surface");
3685
+ if (!el || !card) return;
3686
+ const root = document.documentElement;
3687
+ const ro = new ResizeObserver(publish);
3688
+ ro.observe(el);
3689
+ ro.observe(card);
3690
+ return () => {
3691
+ ro.disconnect();
3692
+ armedRef.current = false;
3693
+ root.style.transition = "none";
3694
+ root.style.removeProperty("--page-rail-seam");
3695
+ requestAnimationFrame(() => {
3696
+ root.style.removeProperty("transition");
3697
+ });
3698
+ };
3699
+ }, [publish, seamTop]);
3700
+ return (
3701
+ // A caixa RESERVA a largura; a coluna mora dentro dela, posicionada. Sem
3702
+ // isso, reabrir no hover empurraria o conteúdo a cada passada do ponteiro.
3703
+ /* @__PURE__ */ jsxs(
3704
+ "div",
3705
+ {
3706
+ ref: boxRef,
3707
+ className: cn("relative hidden shrink-0 no-print transition-[width] duration-200 md:block", className),
3708
+ style: { width: collapsed ? COLUMN_COLLAPSED_WIDTH : COLUMN_WIDTH },
3709
+ children: [
3710
+ /* @__PURE__ */ jsxs(
3711
+ "nav",
3712
+ {
3713
+ ref: panelRef,
3714
+ "aria-label": ariaLabel,
3715
+ onMouseEnter: () => setHover(true),
3716
+ onMouseLeave: () => setHover(false),
3717
+ onDoubleClick: () => {
3718
+ if (collapsed) setOpenState(false);
3719
+ },
3720
+ style: { width },
3721
+ className: cn(
3722
+ // O vidro é uma classe compartilhada com a faixa do cabeçalho.
3723
+ "fz-liquid-glass absolute inset-y-0 left-0 flex flex-col overflow-hidden p-3 transition-[width] duration-200",
3724
+ collapsed && hovering && "z-30 shadow-xl"
3725
+ ),
3726
+ children: [
3727
+ /* @__PURE__ */ jsx(
3728
+ "span",
3729
+ {
3730
+ "aria-hidden": true,
3731
+ className: "pointer-events-none absolute right-0 w-px",
3732
+ style: { top: seamTop, bottom: 0, background: "hsl(var(--border))" }
3733
+ }
3734
+ ),
3735
+ /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1", children: [
3736
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, onScroll, className: "scrollbar-none h-full overflow-y-auto overflow-x-hidden", children: children({ collapsed: !open }) }),
3737
+ /* @__PURE__ */ jsx(
3738
+ "div",
3739
+ {
3740
+ "aria-hidden": true,
3741
+ className: cn(
3742
+ "pointer-events-none absolute inset-x-0 bottom-0 h-8 transition-opacity duration-200",
3743
+ hasMore ? "opacity-100" : "opacity-0"
3744
+ ),
3745
+ style: { backgroundImage: "linear-gradient(to top, var(--page-surface, hsl(var(--background))), transparent)" }
3746
+ }
3747
+ )
3748
+ ] }),
3749
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex shrink-0 items-center gap-2 border-t border-border pt-2", children: [
3750
+ open && footer && /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: footer }),
3751
+ /* @__PURE__ */ jsx(
3752
+ "button",
3753
+ {
3754
+ type: "button",
3755
+ onClick: () => setOpenState(!collapsed),
3756
+ "aria-label": collapsed ? "Expandir menu" : "Recolher menu",
3757
+ title: collapsed ? "Expandir menu" : "Recolher menu",
3758
+ "aria-expanded": !collapsed,
3759
+ className: "flex h-8 w-full items-center justify-end rounded-button bg-transparent px-2.5 text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground",
3760
+ children: collapsed ? /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
3761
+ }
3762
+ )
3763
+ ] })
3764
+ ]
3765
+ }
3766
+ ),
3767
+ seamed && /* @__PURE__ */ jsx(
3768
+ "svg",
3769
+ {
3770
+ "aria-hidden": true,
3771
+ className: "pointer-events-none absolute top-0",
3772
+ style: { left: `${width - 1}px`, marginTop: "-1px", zIndex: 25, transition: "left 200ms" },
3773
+ width: seamTop,
3774
+ height: seamTop,
3775
+ viewBox: `0 0 ${seamTop} ${seamTop}`,
3776
+ fill: "none",
3777
+ children: /* @__PURE__ */ jsx(
3778
+ "path",
3779
+ {
3780
+ d: `M ${seamTop} 0.5 Q 0.5 0.5 0.5 ${seamTop}`,
3781
+ stroke: "hsl(var(--border))",
3782
+ strokeWidth: "1",
3783
+ fill: "none"
3784
+ }
3785
+ )
3786
+ }
3787
+ )
3788
+ ]
3789
+ }
3790
+ )
3791
+ );
3792
+ }
3499
3793
  function PageRail({ children }) {
3500
3794
  const slot = usePageRailSlot();
3501
3795
  if (slot) return createPortal(children, slot);
@@ -3539,6 +3833,159 @@ function PageViewBar({ children }) {
3539
3833
  if (slot) return createPortal(children, slot);
3540
3834
  return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
3541
3835
  }
3836
+ var SUB_NAV_STYLE = "nested";
3837
+ function RailSections({ sections, search, collapsed }) {
3838
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3839
+ search && !collapsed && /* @__PURE__ */ jsxs("div", { className: "relative mb-2", children: [
3840
+ /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-1 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
3841
+ /* @__PURE__ */ jsx(
3842
+ "input",
3843
+ {
3844
+ type: "search",
3845
+ value: search.value,
3846
+ onChange: (e) => search.onChange(e.target.value),
3847
+ placeholder: search.placeholder,
3848
+ "aria-label": search.placeholder,
3849
+ className: "h-8 w-full border-0 bg-transparent pl-7 pr-2 text-[13px] outline-none placeholder:text-muted-foreground focus:ring-0"
3850
+ }
3851
+ )
3852
+ ] }),
3853
+ sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: i > 0 ? "mt-3 border-t border-border pt-3" : void 0, children: [
3854
+ section.heading && !collapsed && /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: section.heading }),
3855
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item, collapsed }, item.id)) })
3856
+ ] }, section.key ?? i))
3857
+ ] });
3858
+ }
3859
+ var RAIL_COLLAPSED_KEY = "fayz.subnav.collapsed";
3860
+ function RailColumn({ className, "aria-label": ariaLabel, sections, search, footer }) {
3861
+ const boxRef = React11.useRef(null);
3862
+ const [squeezed, setSqueezed] = React11.useState(void 0);
3863
+ React11.useEffect(() => {
3864
+ if (typeof window === "undefined") return;
3865
+ const row = boxRef.current?.parentElement?.parentElement;
3866
+ if (!row) return;
3867
+ const COLLAPSE_BELOW = 560;
3868
+ const RESTORE_ABOVE = 820;
3869
+ let timer;
3870
+ const decide = () => {
3871
+ const content = row.clientWidth - COLUMN_WIDTH;
3872
+ if (content < COLLAPSE_BELOW) setSqueezed(true);
3873
+ else if (content > RESTORE_ABOVE) setSqueezed(false);
3874
+ };
3875
+ const apply = () => {
3876
+ if (timer) clearTimeout(timer);
3877
+ timer = setTimeout(decide, 180);
3878
+ };
3879
+ apply();
3880
+ const ro = new ResizeObserver(apply);
3881
+ ro.observe(row);
3882
+ window.addEventListener("resize", apply);
3883
+ return () => {
3884
+ if (timer) clearTimeout(timer);
3885
+ ro.disconnect();
3886
+ window.removeEventListener("resize", apply);
3887
+ };
3888
+ }, []);
3889
+ const activeKey = sections.flatMap((sec) => sec.items).filter((i) => i.active).map((i) => i.id).join("|");
3890
+ return /* @__PURE__ */ jsx("div", { ref: boxRef, className: "contents", children: /* @__PURE__ */ jsx(
3891
+ CollapsibleColumn,
3892
+ {
3893
+ "aria-label": ariaLabel,
3894
+ storageKey: RAIL_COLLAPSED_KEY,
3895
+ className,
3896
+ footer,
3897
+ squeezed,
3898
+ autoCollapseKey: activeKey,
3899
+ children: ({ collapsed }) => /* @__PURE__ */ jsx(RailSections, { sections, search, collapsed })
3900
+ }
3901
+ ) });
3902
+ }
3903
+ var published = [];
3904
+ var subNavHosts = 0;
3905
+ var subNavListeners = /* @__PURE__ */ new Set();
3906
+ var subNavNotify = () => subNavListeners.forEach((l) => l());
3907
+ var subNavSubscribe = (l) => {
3908
+ subNavListeners.add(l);
3909
+ return () => {
3910
+ subNavListeners.delete(l);
3911
+ };
3912
+ };
3913
+ function publishSubNav(entry) {
3914
+ const i = published.findIndex((p) => p.id === entry.id);
3915
+ published = i < 0 ? [...published, entry] : published.map((p, n) => n === i ? entry : p);
3916
+ subNavNotify();
3917
+ }
3918
+ function unpublishSubNav(id) {
3919
+ published = published.filter((p) => p.id !== id);
3920
+ subNavNotify();
3921
+ }
3922
+ function useSubNavPublished() {
3923
+ return React11.useSyncExternalStore(subNavSubscribe, () => published, () => published);
3924
+ }
3925
+ function useSubNavHost() {
3926
+ React11.useEffect(() => {
3927
+ subNavHosts++;
3928
+ subNavNotify();
3929
+ return () => {
3930
+ subNavHosts--;
3931
+ subNavNotify();
3932
+ };
3933
+ }, []);
3934
+ }
3935
+ function useHasSubNavHost() {
3936
+ return React11.useSyncExternalStore(subNavSubscribe, () => subNavHosts > 0, () => false);
3937
+ }
3938
+ function SubNavBand({ sections, "aria-label": ariaLabel, className }) {
3939
+ const items = sections.flatMap((s) => s.items);
3940
+ const value = items.find((i) => i.active)?.id ?? items[0]?.id;
3941
+ if (!value) return null;
3942
+ return /* @__PURE__ */ jsx(
3943
+ ViewTabs,
3944
+ {
3945
+ className,
3946
+ "aria-label": ariaLabel,
3947
+ options: items.map((i) => ({ value: i.id, label: i.label })),
3948
+ value,
3949
+ onChange: (id) => items.find((i) => i.id === id)?.onClick?.()
3950
+ }
3951
+ );
3952
+ }
3953
+ function SubNavBandHost({ leading, label }) {
3954
+ useSubNavHost();
3955
+ const pubs = useSubNavPublished();
3956
+ const sections = leading ?? pubs.flatMap((p) => p.sections);
3957
+ if (sections.length === 0) return null;
3958
+ return /* @__PURE__ */ jsx(
3959
+ "div",
3960
+ {
3961
+ style: { marginTop: "0.5rem" },
3962
+ className: "flex min-w-0 items-center gap-3",
3963
+ children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": leading ? label : pubs[0]?.label })
3964
+ }
3965
+ );
3966
+ }
3967
+ function PageSubNav({ items, sections, search, footer, style, "aria-label": ariaLabel }) {
3968
+ const id = React11.useId();
3969
+ const hasHost = useHasSubNavHost();
3970
+ const resolved = sections ?? (items ? [{ items }] : []);
3971
+ const ref = React11.useRef(resolved);
3972
+ ref.current = resolved;
3973
+ const signature = JSON.stringify(resolved.map((s) => [s.key, s.heading, s.items.map((i) => [i.id, i.label, i.icon, !!i.active, !!i.premium])]));
3974
+ React11.useEffect(() => {
3975
+ publishSubNav({ id, label: ariaLabel, sections: ref.current });
3976
+ return () => unpublishSubNav(id);
3977
+ }, [id, ariaLabel, signature]);
3978
+ if (resolved.every((s) => s.items.length === 0)) return null;
3979
+ if (hasHost) return null;
3980
+ const asRail = (style ?? SUB_NAV_STYLE) === "nested";
3981
+ if (!asRail) {
3982
+ return /* @__PURE__ */ jsx("div", { className: "mb-4 flex min-w-0 items-center gap-3", children: /* @__PURE__ */ jsx(SubNavBand, { sections: resolved, "aria-label": ariaLabel }) });
3983
+ }
3984
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3985
+ /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(RailColumn, { sections: resolved, search, footer, "aria-label": ariaLabel }) }),
3986
+ /* @__PURE__ */ jsx("div", { className: "mb-4 flex min-w-0 items-center gap-3 md:hidden", children: /* @__PURE__ */ jsx(SubNavBand, { sections: resolved, "aria-label": ariaLabel }) })
3987
+ ] });
3988
+ }
3542
3989
  function PageHeaderActions({ children }) {
3543
3990
  const outlet = usePageActionsOutletSlot();
3544
3991
  const shellSlot = useModuleHeaderActionsSlot();
@@ -3559,8 +4006,11 @@ function ModuleLayoutProvider({ variant, children }) {
3559
4006
  function useModuleLayout() {
3560
4007
  return React11.useContext(ModuleLayoutContext);
3561
4008
  }
3562
- function RailNavItem({ item }) {
3563
- const [expanded, setExpanded] = React11.useState(true);
4009
+ function RailNavItem({ item, collapsed }) {
4010
+ const [expanded, setExpanded] = React11.useState(false);
4011
+ React11.useEffect(() => {
4012
+ if (collapsed) setExpanded(false);
4013
+ }, [collapsed]);
3564
4014
  const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
3565
4015
  const hasChildren = item.children && item.children.length > 0;
3566
4016
  const hasActiveChild = hasChildren && item.children.some((c) => c.active);
@@ -3571,36 +4021,53 @@ function RailNavItem({ item }) {
3571
4021
  {
3572
4022
  type: "button",
3573
4023
  "data-tour": `modnav.${item.id}`,
3574
- onClick: () => hasChildren ? setExpanded(!expanded) : item.onClick?.(),
4024
+ onClick: () => hasChildren && !collapsed ? setExpanded(!expanded) : item.onClick?.(),
4025
+ title: collapsed ? item.label : void 0,
3575
4026
  className: cn(
3576
- "flex items-center gap-2 w-full rounded-md px-2.5 py-1.5 text-sm transition-colors",
4027
+ // `px-2.5` NOS DOIS estados: centralizado, o ícone da tira ficava 2px
4028
+ // à direita do mesmo ícone com a coluna aberta, e todos eles davam um
4029
+ // pulinho lateral quando o ponteiro chegava. O recuo é o mesmo; o que
4030
+ // muda é só o rótulo aparecer.
4031
+ // ALTURA FIXA. Com `py-1.5` a linha media o que tinha dentro: 32px com
4032
+ // rótulo (a entrelinha do texto) e 28px só com o ícone — então cada
4033
+ // linha da tira caía num y diferente do da coluna aberta, e a lista
4034
+ // inteira escorregava quando o ponteiro chegava. `h-8` nos dois.
4035
+ "flex h-8 w-full items-center gap-2 rounded-md px-2.5 text-sm transition-colors",
3577
4036
  isActive ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
3578
4037
  ),
3579
4038
  children: [
3580
4039
  Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
3581
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: item.label }),
3582
- item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
3583
- 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" }))
4040
+ !collapsed && /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
4041
+ !collapsed && item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
4042
+ !collapsed && 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" }))
3584
4043
  ]
3585
4044
  }
3586
4045
  ),
3587
- 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(
3588
- "button",
3589
- {
3590
- type: "button",
3591
- "data-tour": `modnav.${child.id}`,
3592
- onClick: child.onClick,
3593
- className: cn(
3594
- "flex items-center w-full rounded-md px-2.5 py-1 text-xs transition-colors",
3595
- child.active ? "text-primary font-medium bg-primary/5" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
3596
- ),
3597
- children: [
3598
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: child.label }),
3599
- child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
3600
- ]
3601
- },
3602
- child.id
3603
- )) })
4046
+ hasChildren && expanded && !collapsed && /* @__PURE__ */ jsx("div", { className: "relative mt-0.5 text-muted-foreground/45", children: item.children.map((child, i) => {
4047
+ const activeIndex = item.children.findIndex((c) => c.active);
4048
+ return /* @__PURE__ */ jsxs("div", { className: "relative h-8", children: [
4049
+ /* @__PURE__ */ jsx(NavChildConnector, { onPath: activeIndex >= 0 && i < activeIndex, active: !!child.active }),
4050
+ /* @__PURE__ */ jsxs(
4051
+ "button",
4052
+ {
4053
+ type: "button",
4054
+ "data-tour": `modnav.${child.id}`,
4055
+ onClick: child.onClick,
4056
+ className: cn(
4057
+ // `pl-11` passa da ponta da seta (~24px) com folga, para as
4058
+ // filhas lerem como UMA coluna indentada em vez de apertarem
4059
+ // a linha que aponta para elas.
4060
+ "flex h-8 w-full items-center rounded-button pl-11 pr-1 text-sm transition-colors",
4061
+ child.active ? "font-medium text-primary" : "text-muted-foreground hover:text-foreground"
4062
+ ),
4063
+ children: [
4064
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: child.label }),
4065
+ child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
4066
+ ]
4067
+ }
4068
+ )
4069
+ ] }, child.id);
4070
+ }) })
3604
4071
  ] });
3605
4072
  }
3606
4073
  function defaultChildOf(item) {
@@ -3796,11 +4263,18 @@ function ShellSubpageHeader({
3796
4263
  /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "no-print flex shrink-0 items-center gap-2", children: actions }) })
3797
4264
  ] });
3798
4265
  }
4266
+ function ModuleSubBand({ nav }) {
4267
+ useSubNavHost();
4268
+ const pubs = useSubNavPublished();
4269
+ const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
4270
+ const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
4271
+ kids.find((c) => c.active)?.id ?? kids[0]?.id;
4272
+ const own = [];
4273
+ const sections = own.length ? own : pubs.flatMap((p) => p.sections);
4274
+ if (sections.every((sec) => sec.items.length === 0)) return null;
4275
+ return /* @__PURE__ */ jsx(PageBand, { actions: /* @__PURE__ */ jsx(ViewBarHost, {}), children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": own.length ? activeItem?.label : pubs[0]?.label }) });
4276
+ }
3799
4277
  function ModuleHeader({ nav }) {
3800
- function defaultChild(item) {
3801
- const kids2 = (item.children ?? []).filter((c) => c.kind !== "action");
3802
- return kids2.find((c) => /list/i.test(c.id) || /^list$/i.test(c.label)) ?? kids2[kids2.length - 1];
3803
- }
3804
4278
  const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
3805
4279
  const tabs = nav.map((item) => ({
3806
4280
  value: item.id,
@@ -3814,23 +4288,12 @@ function ModuleHeader({ nav }) {
3814
4288
  const item = nav.find((n) => n.id === id);
3815
4289
  if (!item) return;
3816
4290
  const hasChildren = item.children && item.children.length > 0;
3817
- if (hasChildren) defaultChild(item)?.onClick?.();
4291
+ if (hasChildren) defaultChildOf(item)?.onClick?.();
3818
4292
  else item.onClick?.();
3819
4293
  };
3820
4294
  const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
3821
4295
  const activeKid = kids.find((c) => c.active)?.id ?? kids[0]?.id;
3822
- const childControl = kids.length > 1 && activeKid ? /* @__PURE__ */ jsxs(PageViewBar, { children: [
3823
- /* @__PURE__ */ jsx(
3824
- ViewTabs,
3825
- {
3826
- "aria-label": activeItem?.label,
3827
- options: kids.map((c) => ({ value: c.id, label: c.label })),
3828
- value: activeKid,
3829
- onChange: (id) => kids.find((c) => c.id === id)?.onClick?.()
3830
- }
3831
- ),
3832
- /* @__PURE__ */ jsx("span", {})
3833
- ] }) : void 0;
4296
+ const childNav = kids.length > 1 && activeKid ? [{ items: kids.map((c) => ({ id: c.id, label: c.label, icon: c.icon, premium: c.premium, active: c.id === activeKid, onClick: c.onClick })) }] : void 0;
3834
4297
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3835
4298
  /* @__PURE__ */ jsx(
3836
4299
  PageTabs,
@@ -3842,7 +4305,7 @@ function ModuleHeader({ nav }) {
3842
4305
  actions: /* @__PURE__ */ jsx(ViewBarHost, {})
3843
4306
  }
3844
4307
  ),
3845
- childControl
4308
+ /* @__PURE__ */ jsx(SubNavBandHost, { leading: childNav, label: activeItem?.label })
3846
4309
  ] });
3847
4310
  }
3848
4311
  function ModulePage({ title: _title, subtitle, nav, children, className, headerAction, showHeader = true, sidebarFooter, navVariant, viewKey, direction, navFilterPlaceholder }) {
@@ -3861,6 +4324,16 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
3861
4324
  }, [nav, navQuery]);
3862
4325
  const transitionKey = viewKey ?? "view";
3863
4326
  const onSubpage = useHasPageHeaderBack();
4327
+ const activeLabel = React11.useMemo(() => {
4328
+ if (onSubpage) return null;
4329
+ for (const item of nav) {
4330
+ const kid = item.children?.find((c) => c.active);
4331
+ if (kid) return kid.label === item.label ? item.label : `${item.label} \u203A ${kid.label}`;
4332
+ if (item.active) return item.label;
4333
+ }
4334
+ return null;
4335
+ }, [nav, onSubpage]);
4336
+ usePublishModuleViewLabel(activeLabel);
3864
4337
  if (variant === "sidebar") {
3865
4338
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3866
4339
  showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
@@ -3875,32 +4348,23 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
3875
4348
  ] });
3876
4349
  }
3877
4350
  return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", className), children: [
3878
- /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsxs("div", { className: "hidden w-48 shrink-0 flex-col overflow-y-auto border-r border-border p-3 no-print md:flex", children: [
3879
- navFilterPlaceholder && /* @__PURE__ */ jsxs("div", { className: "relative mb-2", children: [
3880
- /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-1 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
3881
- /* @__PURE__ */ jsx(
3882
- "input",
3883
- {
3884
- type: "search",
3885
- value: navQuery,
3886
- onChange: (e) => setNavQuery(e.target.value),
3887
- placeholder: navFilterPlaceholder,
3888
- "aria-label": navFilterPlaceholder,
3889
- className: "h-8 w-full border-0 bg-transparent pl-7 pr-2 text-[13px] outline-none placeholder:text-muted-foreground focus:ring-0"
3890
- }
3891
- )
3892
- ] }),
3893
- /* @__PURE__ */ jsx("nav", { className: "space-y-0.5", children: filteredNav.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item }, item.id)) }),
3894
- sidebarFooter && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-3", children: sidebarFooter })
3895
- ] }) }),
4351
+ /* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(
4352
+ RailColumn,
4353
+ {
4354
+ sections: [{ items: filteredNav }],
4355
+ search: navFilterPlaceholder ? { value: navQuery, onChange: setNavQuery, placeholder: navFilterPlaceholder } : void 0,
4356
+ footer: sidebarFooter
4357
+ }
4358
+ ) }),
3896
4359
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
3897
4360
  showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
3898
4361
  !onSubpage && /* @__PURE__ */ jsx(MobileTabs, { nav }),
4362
+ !onSubpage && /* @__PURE__ */ jsx(ModuleSubBand, { nav }),
3899
4363
  /* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
3900
4364
  ] })
3901
4365
  ] });
3902
4366
  }
3903
4367
 
3904
- export { AppShell, BackStyleProvider, BottomSheet, HeaderTabs, Hint, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageHeaderOutlet, PageRail, PageTabs, PageTitlePortal, PageTrail, PageTransition, PageViewBar, RailNavItem, SaveBar, SaveBarProvider, SheetCard, SheetRow, ShellSearch, Sidebar, SubpageHeader, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Topbar, ViewTabs, bottomNavReachesAll, isCreateRoute, navigateToCrumb, useBackHandler, useBackStyle, useCrossModuleBack, useCurrentRouteHref, useHasPageActions, useHasPageHeaderBack, useHasPageHeaderHost, useHasPageHeaderOutlet, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition, usePageHeader, usePageHeaderClaimed, usePageHeaderHost, usePageTrail, usePageTrailParent, useRailRow, useRegisterPageActions, useSaveBar, useSaveBarVisible, useSheetClose, useSheetDrag, useTrailBack };
3905
- //# sourceMappingURL=chunk-PL5CUWNE.js.map
3906
- //# sourceMappingURL=chunk-PL5CUWNE.js.map
4368
+ export { AppShell, BackStyleProvider, BottomSheet, COLUMN_WIDTH, CollapsibleColumn, HeaderTabs, Hint, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageHeaderOutlet, PageRail, PageSubNav, PageTabs, PageTitlePortal, PageTrail, PageTransition, PageViewBar, RailColumn, RailNavItem, SUB_NAV_STYLE, SaveBar, SaveBarProvider, SheetCard, SheetRow, ShellSearch, Sidebar, SubpageHeader, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Topbar, ViewTabs, bottomNavReachesAll, isCreateRoute, navigateToCrumb, useBackHandler, useBackStyle, useCrossModuleBack, useCurrentRouteHref, useHasPageActions, useHasPageHeaderBack, useHasPageHeaderHost, useHasPageHeaderOutlet, useLayoutStore, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useModuleViewLabel, useNavTransition, usePageHeader, usePageHeaderClaimed, usePageHeaderHost, usePageTrail, usePageTrailParent, usePublishModuleViewLabel, useRailRow, useRegisterPageActions, useSaveBar, useSaveBarVisible, useSheetClose, useSheetDrag, useTrailBack };
4369
+ //# sourceMappingURL=chunk-33A7SN2N.js.map
4370
+ //# sourceMappingURL=chunk-33A7SN2N.js.map