@fayz-ai/ui 0.33.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NXSDQ7HO.js → chunk-2CRN3BOD.js} +13 -16
- package/dist/chunk-2CRN3BOD.js.map +1 -0
- package/dist/{chunk-PL5CUWNE.js → chunk-63BB2CNP.js} +883 -309
- package/dist/chunk-63BB2CNP.js.map +1 -0
- package/dist/{chunk-3XKDGBP4.js → chunk-FNGCA3XR.js} +3 -3
- package/dist/{chunk-3XKDGBP4.js.map → chunk-FNGCA3XR.js.map} +1 -1
- package/dist/{chunk-UFT3MA5H.js → chunk-OBWOHU5E.js} +324 -223
- package/dist/chunk-OBWOHU5E.js.map +1 -0
- package/dist/dashboard/DashboardGrid.d.ts +8 -1
- package/dist/dashboard/DashboardGrid.d.ts.map +1 -1
- package/dist/dashboard/KpiCard.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +47 -1
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/SaveBar.d.ts.map +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +1 -1
- package/dist/layout/rail-flyout.d.ts.map +1 -1
- package/dist/primitives/collapsible-column.d.ts +38 -0
- package/dist/primitives/collapsible-column.d.ts.map +1 -0
- package/dist/primitives/coming-soon.d.ts +31 -0
- package/dist/primitives/coming-soon.d.ts.map +1 -0
- package/dist/primitives/filter-panel.d.ts +85 -0
- package/dist/primitives/filter-panel.d.ts.map +1 -0
- package/dist/primitives/filter-rail.d.ts +10 -7
- package/dist/primitives/filter-rail.d.ts.map +1 -1
- package/dist/primitives/header-tabs.d.ts +9 -35
- package/dist/primitives/header-tabs.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +3 -1
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +3 -3
- package/dist/primitives/modal.d.ts +2 -0
- package/dist/primitives/modal.d.ts.map +1 -1
- package/dist/primitives/nav-connector.d.ts +23 -0
- package/dist/primitives/nav-connector.d.ts.map +1 -0
- package/dist/primitives/page-actions.d.ts.map +1 -1
- package/dist/primitives/person-picker.d.ts +1 -1
- package/dist/primitives/person-picker.d.ts.map +1 -1
- package/dist/primitives/search-select.d.ts.map +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +17 -0
- package/dist/stores/page-header.store.d.ts.map +1 -1
- package/dist/styles.css +84 -0
- package/package.json +2 -2
- package/dist/chunk-NXSDQ7HO.js.map +0 -1
- package/dist/chunk-PL5CUWNE.js.map +0 -1
- package/dist/chunk-UFT3MA5H.js.map +0 -1
|
@@ -1,17 +1,120 @@
|
|
|
1
1
|
import { cn } from './chunk-OKZ6WQB3.js';
|
|
2
2
|
import { ICON_MAP } from './chunk-ATDIWKBD.js';
|
|
3
|
-
import * as
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import * as React12 from 'react';
|
|
4
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
5
|
+
import { X, Loader2, ChevronLeft, ArrowLeft, Bell, PanelLeft, PanelLeftClose, Search, CornerDownLeft, Menu, Crown, ChevronsRight, ChevronsLeft, ChevronDown, ChevronRight, Info, ExternalLink, CreditCard, Sparkles, Home, ChevronUp, Plus, Settings, UserCog, LogOut } from 'lucide-react';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
8
7
|
import { createPortal } from 'react-dom';
|
|
8
|
+
import { useTranslation, useNavReferrer, routeModule, navHistoryBack, recordNavigation } from '@fayz-ai/core';
|
|
9
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
9
10
|
import { create } from 'zustand';
|
|
10
11
|
import * as Popover from '@radix-ui/react-popover';
|
|
11
12
|
|
|
13
|
+
var SIZE_MAP = {
|
|
14
|
+
sm: "sm:max-w-sm",
|
|
15
|
+
md: "sm:max-w-md",
|
|
16
|
+
lg: "sm:max-w-lg",
|
|
17
|
+
xl: "sm:max-w-xl",
|
|
18
|
+
"2xl": "sm:max-w-2xl",
|
|
19
|
+
"3xl": "sm:max-w-3xl",
|
|
20
|
+
// Duas colunas de trabalho lado a lado (ficha + linha do tempo) não cabem em
|
|
21
|
+
// 3xl: a coluna da direita fica com 20rem e o texto de cada anotação quebra
|
|
22
|
+
// a cada quatro palavras.
|
|
23
|
+
"4xl": "sm:max-w-4xl",
|
|
24
|
+
"5xl": "sm:max-w-5xl",
|
|
25
|
+
full: "sm:max-w-[calc(100vw-4rem)]"
|
|
26
|
+
};
|
|
27
|
+
var Modal = DialogPrimitive.Root;
|
|
28
|
+
var ModalTrigger = DialogPrimitive.Trigger;
|
|
29
|
+
var ModalClose = DialogPrimitive.Close;
|
|
30
|
+
var ModalPortal = DialogPrimitive.Portal;
|
|
31
|
+
var ModalHostContext = React12.createContext(null);
|
|
32
|
+
function useModalHost() {
|
|
33
|
+
return React12.useContext(ModalHostContext);
|
|
34
|
+
}
|
|
35
|
+
var ModalOverlay = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
36
|
+
DialogPrimitive.Overlay,
|
|
37
|
+
{
|
|
38
|
+
ref,
|
|
39
|
+
className: cn(
|
|
40
|
+
"fayz-modal-overlay saas-mdl-ov fixed inset-0 z-[100]",
|
|
41
|
+
"flex items-center justify-center p-0 sm:p-6",
|
|
42
|
+
className
|
|
43
|
+
),
|
|
44
|
+
...props
|
|
45
|
+
}
|
|
46
|
+
));
|
|
47
|
+
ModalOverlay.displayName = "ModalOverlay";
|
|
48
|
+
var ModalContent = React12.forwardRef(({ className, children, size = "lg", hideClose, noPadding, onPointerDownOutside, onInteractOutside, onCloseAutoFocus, ...props }, ref) => {
|
|
49
|
+
const [host, setHost] = React12.useState(null);
|
|
50
|
+
const attach = React12.useCallback((node) => {
|
|
51
|
+
setHost(node);
|
|
52
|
+
if (typeof ref === "function") ref(node);
|
|
53
|
+
else if (ref) ref.current = node;
|
|
54
|
+
}, [ref]);
|
|
55
|
+
return /* @__PURE__ */ jsx(ModalPortal, { children: /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(
|
|
56
|
+
DialogPrimitive.Content,
|
|
57
|
+
{
|
|
58
|
+
ref: attach,
|
|
59
|
+
onCloseAutoFocus: (e) => {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
onCloseAutoFocus?.(e);
|
|
62
|
+
},
|
|
63
|
+
onPointerDownOutside: (e) => {
|
|
64
|
+
const target = e.target;
|
|
65
|
+
if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
}
|
|
68
|
+
onPointerDownOutside?.(e);
|
|
69
|
+
},
|
|
70
|
+
onInteractOutside: (e) => {
|
|
71
|
+
const target = e.target;
|
|
72
|
+
if (target.closest("[data-modal-passthrough]") || target.closest("[data-radix-popper-content-wrapper]")) {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
}
|
|
75
|
+
onInteractOutside?.(e);
|
|
76
|
+
},
|
|
77
|
+
className: cn(
|
|
78
|
+
// fz-container: a form inside a dialog measures the DIALOG. Without
|
|
79
|
+
// it a two-column field grid in an `sm` modal read the window's width
|
|
80
|
+
// and kept both columns in 380px.
|
|
81
|
+
"fayz-glass-surface fayz-modal-content saas-mdl-ct fz-container relative z-[100] flex flex-col w-full outline-none",
|
|
82
|
+
// Mobile fullscreen
|
|
83
|
+
"h-full rounded-none border-0",
|
|
84
|
+
// Desktop centered card
|
|
85
|
+
"sm:h-auto sm:max-h-[85vh] sm:rounded-2xl sm:border",
|
|
86
|
+
SIZE_MAP[size],
|
|
87
|
+
noPadding ? "" : "p-6 gap-4",
|
|
88
|
+
className
|
|
89
|
+
),
|
|
90
|
+
...props,
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ jsx(ModalHostContext.Provider, { value: host, children }),
|
|
93
|
+
!hideClose && /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 z-10 flex h-7 w-7 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring", children: [
|
|
94
|
+
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
95
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
96
|
+
] })
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
) }) });
|
|
100
|
+
});
|
|
101
|
+
ModalContent.displayName = "ModalContent";
|
|
102
|
+
function ModalHeader({ className, ...props }) {
|
|
103
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left shrink-0", className), ...props });
|
|
104
|
+
}
|
|
105
|
+
function ModalBody({ className, ...props }) {
|
|
106
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-1 flex-col overflow-y-auto min-h-0", className), ...props });
|
|
107
|
+
}
|
|
108
|
+
function ModalFooter({ className, ...props }) {
|
|
109
|
+
return /* @__PURE__ */ jsx("div", { className: cn("mt-auto flex flex-col-reverse gap-2 pb-[env(safe-area-inset-bottom)] sm:mt-0 sm:flex-row sm:justify-end sm:gap-0 sm:space-x-2 sm:pb-0 shrink-0", className), ...props });
|
|
110
|
+
}
|
|
111
|
+
var ModalTitle = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Title, { ref, className: cn("text-lg font-semibold leading-none tracking-tight", className), ...props }));
|
|
112
|
+
ModalTitle.displayName = "ModalTitle";
|
|
113
|
+
var ModalDescription = React12.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
114
|
+
ModalDescription.displayName = "ModalDescription";
|
|
12
115
|
var HIDDEN = { visible: false, saving: false };
|
|
13
|
-
var SaveBarApiContext =
|
|
14
|
-
var SaveBarStateContext =
|
|
116
|
+
var SaveBarApiContext = React12.createContext(null);
|
|
117
|
+
var SaveBarStateContext = React12.createContext({ visible: false, saving: false });
|
|
15
118
|
var _saveBarVisible = false;
|
|
16
119
|
var _saveBarSubs = /* @__PURE__ */ new Set();
|
|
17
120
|
function setSaveBarVisibleSignal(v) {
|
|
@@ -20,7 +123,7 @@ function setSaveBarVisibleSignal(v) {
|
|
|
20
123
|
_saveBarSubs.forEach((fn) => fn());
|
|
21
124
|
}
|
|
22
125
|
function useSaveBarVisible() {
|
|
23
|
-
return
|
|
126
|
+
return React12.useSyncExternalStore(
|
|
24
127
|
(cb) => {
|
|
25
128
|
_saveBarSubs.add(cb);
|
|
26
129
|
return () => {
|
|
@@ -32,10 +135,10 @@ function useSaveBarVisible() {
|
|
|
32
135
|
);
|
|
33
136
|
}
|
|
34
137
|
function SaveBarProvider({ children }) {
|
|
35
|
-
const [state, setState] =
|
|
36
|
-
const handlers =
|
|
37
|
-
const entries =
|
|
38
|
-
const api =
|
|
138
|
+
const [state, setState] = React12.useState({ visible: false, saving: false });
|
|
139
|
+
const handlers = React12.useRef({});
|
|
140
|
+
const entries = React12.useRef([]);
|
|
141
|
+
const api = React12.useMemo(() => ({
|
|
39
142
|
setState,
|
|
40
143
|
handlers,
|
|
41
144
|
entries,
|
|
@@ -45,12 +148,12 @@ function SaveBarProvider({ children }) {
|
|
|
45
148
|
setState(top ? top.state : HIDDEN);
|
|
46
149
|
}
|
|
47
150
|
}), []);
|
|
48
|
-
const backStack =
|
|
49
|
-
const backApi =
|
|
50
|
-
|
|
151
|
+
const backStack = React12.useRef([]);
|
|
152
|
+
const backApi = React12.useMemo(() => ({ stack: backStack }), []);
|
|
153
|
+
React12.useEffect(() => {
|
|
51
154
|
setSaveBarVisibleSignal(state.visible);
|
|
52
155
|
}, [state.visible]);
|
|
53
|
-
|
|
156
|
+
React12.useEffect(() => {
|
|
54
157
|
function onKey(e) {
|
|
55
158
|
if (state.visible && !state.saving) {
|
|
56
159
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
@@ -78,7 +181,7 @@ function SaveBarProvider({ children }) {
|
|
|
78
181
|
}, [state.visible, state.saving]);
|
|
79
182
|
return /* @__PURE__ */ jsx(SaveBarApiContext.Provider, { value: api, children: /* @__PURE__ */ jsx(BackNavApiContext.Provider, { value: backApi, children: /* @__PURE__ */ jsx(SaveBarStateContext.Provider, { value: state, children }) }) });
|
|
80
183
|
}
|
|
81
|
-
var BackNavApiContext =
|
|
184
|
+
var BackNavApiContext = React12.createContext(null);
|
|
82
185
|
function isEditableTarget(target) {
|
|
83
186
|
const el = target;
|
|
84
187
|
if (!el || !el.tagName) return false;
|
|
@@ -86,12 +189,12 @@ function isEditableTarget(target) {
|
|
|
86
189
|
return tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable;
|
|
87
190
|
}
|
|
88
191
|
function useBackHandler(onBack) {
|
|
89
|
-
const api =
|
|
90
|
-
const ref =
|
|
91
|
-
|
|
192
|
+
const api = React12.useContext(BackNavApiContext);
|
|
193
|
+
const ref = React12.useRef(onBack);
|
|
194
|
+
React12.useEffect(() => {
|
|
92
195
|
ref.current = onBack;
|
|
93
196
|
});
|
|
94
|
-
|
|
197
|
+
React12.useEffect(() => {
|
|
95
198
|
if (!api) return;
|
|
96
199
|
const stack = api.stack.current;
|
|
97
200
|
stack.push(ref);
|
|
@@ -102,15 +205,16 @@ function useBackHandler(onBack) {
|
|
|
102
205
|
}, [api]);
|
|
103
206
|
}
|
|
104
207
|
function useSaveBar({ dirty, alwaysVisible, saving = false, onSave, onDiscard, message, saveLabel, discardLabel }) {
|
|
105
|
-
const api =
|
|
106
|
-
const
|
|
107
|
-
|
|
208
|
+
const api = React12.useContext(SaveBarApiContext);
|
|
209
|
+
const host = useModalHost();
|
|
210
|
+
const entry = React12.useRef({ state: HIDDEN, handlers: {} });
|
|
211
|
+
React12.useEffect(() => {
|
|
108
212
|
entry.current.handlers = { onSave, onDiscard };
|
|
109
213
|
if (api && api.entries.current[api.entries.current.length - 1] === entry.current) {
|
|
110
214
|
api.handlers.current = entry.current.handlers;
|
|
111
215
|
}
|
|
112
216
|
});
|
|
113
|
-
|
|
217
|
+
React12.useEffect(() => {
|
|
114
218
|
if (!api) return;
|
|
115
219
|
const list = api.entries.current;
|
|
116
220
|
list.push(entry.current);
|
|
@@ -121,19 +225,19 @@ function useSaveBar({ dirty, alwaysVisible, saving = false, onSave, onDiscard, m
|
|
|
121
225
|
api.sync();
|
|
122
226
|
};
|
|
123
227
|
}, [api]);
|
|
124
|
-
|
|
228
|
+
React12.useEffect(() => {
|
|
125
229
|
if (!api) return;
|
|
126
|
-
entry.current.state = { visible: dirty || !!alwaysVisible, dirty, saving, message, saveLabel, discardLabel };
|
|
230
|
+
entry.current.state = { visible: dirty || !!alwaysVisible, dirty, saving, message, saveLabel, discardLabel, host };
|
|
127
231
|
if (api.entries.current[api.entries.current.length - 1] === entry.current) api.sync();
|
|
128
|
-
}, [api, dirty, alwaysVisible, saving, message, saveLabel, discardLabel]);
|
|
232
|
+
}, [api, dirty, alwaysVisible, saving, message, saveLabel, discardLabel, host]);
|
|
129
233
|
}
|
|
130
234
|
function SaveBar({ className }) {
|
|
131
|
-
const state =
|
|
132
|
-
const api =
|
|
235
|
+
const state = React12.useContext(SaveBarStateContext);
|
|
236
|
+
const api = React12.useContext(SaveBarApiContext);
|
|
133
237
|
const t = useTranslation();
|
|
134
|
-
const [rendered, setRendered] =
|
|
135
|
-
const [closing, setClosing] =
|
|
136
|
-
|
|
238
|
+
const [rendered, setRendered] = React12.useState(state.visible);
|
|
239
|
+
const [closing, setClosing] = React12.useState(false);
|
|
240
|
+
React12.useEffect(() => {
|
|
137
241
|
if (state.visible) {
|
|
138
242
|
setRendered(true);
|
|
139
243
|
setClosing(false);
|
|
@@ -148,15 +252,12 @@ function SaveBar({ className }) {
|
|
|
148
252
|
return () => clearTimeout(id);
|
|
149
253
|
}, [state.visible, rendered]);
|
|
150
254
|
if (!api || !rendered) return null;
|
|
151
|
-
const { saving, message, saveLabel, discardLabel } = state;
|
|
152
|
-
|
|
255
|
+
const { saving, message, saveLabel, discardLabel, host } = state;
|
|
256
|
+
const island = /* @__PURE__ */ jsx(
|
|
153
257
|
"div",
|
|
154
258
|
{
|
|
155
259
|
className: cn(
|
|
156
|
-
|
|
157
|
-
// clear of the bar's height so its actions are not sitting under it.
|
|
158
|
-
"pointer-events-none fixed inset-x-0 z-[55] flex justify-center px-4",
|
|
159
|
-
"bottom-[calc(var(--fz-bottom-bar,0px)+1.25rem)]",
|
|
260
|
+
host ? "pointer-events-none absolute inset-x-0 bottom-4 z-10 flex justify-center px-4" : "pointer-events-none fixed inset-x-0 z-[55] flex justify-center px-4 bottom-[calc(var(--fz-bottom-bar,0px)+1.25rem)]",
|
|
160
261
|
className
|
|
161
262
|
),
|
|
162
263
|
children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
@@ -197,11 +298,12 @@ function SaveBar({ className }) {
|
|
|
197
298
|
] })
|
|
198
299
|
}
|
|
199
300
|
);
|
|
301
|
+
return host ? createPortal(island, host) : island;
|
|
200
302
|
}
|
|
201
303
|
var TooltipProvider = TooltipPrimitive.Provider;
|
|
202
304
|
var Tooltip = TooltipPrimitive.Root;
|
|
203
305
|
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
204
|
-
var TooltipContent =
|
|
306
|
+
var TooltipContent = React12.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
205
307
|
TooltipPrimitive.Content,
|
|
206
308
|
{
|
|
207
309
|
ref,
|
|
@@ -215,6 +317,8 @@ var TooltipContent = React11.forwardRef(({ className, sideOffset = 4, ...props }
|
|
|
215
317
|
));
|
|
216
318
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
217
319
|
var usePageHeaderStore = create((set, get) => ({
|
|
320
|
+
moduleViewLabel: null,
|
|
321
|
+
setModuleViewLabel: (moduleViewLabel) => set((state) => state.moduleViewLabel === moduleViewLabel ? state : { moduleViewLabel }),
|
|
218
322
|
shellSlot: null,
|
|
219
323
|
setShellSlot: (element) => set({ shellSlot: element }),
|
|
220
324
|
outletSlot: null,
|
|
@@ -241,7 +345,7 @@ var usePageHeaderStore = create((set, get) => ({
|
|
|
241
345
|
function useRegisterPageActions() {
|
|
242
346
|
const add = usePageHeaderStore((s) => s.addActions);
|
|
243
347
|
const remove = usePageHeaderStore((s) => s.removeActions);
|
|
244
|
-
|
|
348
|
+
React12.useEffect(() => {
|
|
245
349
|
add();
|
|
246
350
|
return remove;
|
|
247
351
|
}, [add, remove]);
|
|
@@ -264,7 +368,7 @@ function usePageTitleSlotHost() {
|
|
|
264
368
|
function usePageHeaderHost() {
|
|
265
369
|
const addHost = usePageHeaderStore((s) => s.addHost);
|
|
266
370
|
const removeHost = usePageHeaderStore((s) => s.removeHost);
|
|
267
|
-
|
|
371
|
+
React12.useEffect(() => {
|
|
268
372
|
addHost();
|
|
269
373
|
return removeHost;
|
|
270
374
|
}, [addHost, removeHost]);
|
|
@@ -282,30 +386,30 @@ function PageHeaderOutlet({ className, active = true }) {
|
|
|
282
386
|
const hasActions = usePageHeaderStore((s) => s.actions > 0);
|
|
283
387
|
const addOutlet = usePageHeaderStore((s) => s.addOutlet);
|
|
284
388
|
const removeOutlet = usePageHeaderStore((s) => s.removeOutlet);
|
|
285
|
-
|
|
389
|
+
React12.useEffect(() => {
|
|
286
390
|
if (!active) return;
|
|
287
391
|
addOutlet();
|
|
288
392
|
return removeOutlet;
|
|
289
393
|
}, [active, addOutlet, removeOutlet]);
|
|
290
|
-
|
|
394
|
+
React12.useEffect(() => {
|
|
291
395
|
if (active) return;
|
|
292
396
|
setOutletSlot(null);
|
|
293
397
|
setOutletActionsSlot(null);
|
|
294
398
|
}, [active, setOutletSlot, setOutletActionsSlot]);
|
|
295
399
|
if (!active) return null;
|
|
296
|
-
return
|
|
400
|
+
return React12.createElement(
|
|
297
401
|
"div",
|
|
298
402
|
{ className: `flex min-h-9 items-center justify-between gap-3${claimed || hasActions ? "" : " hidden"} ${className ?? "mb-3"}` },
|
|
299
|
-
|
|
300
|
-
|
|
403
|
+
React12.createElement("div", { ref: setOutletSlot, className: "flex min-w-0 flex-1 items-center" }),
|
|
404
|
+
React12.createElement("div", { ref: setOutletActionsSlot, className: "flex shrink-0 items-center gap-2" })
|
|
301
405
|
);
|
|
302
406
|
}
|
|
303
407
|
function usePageHeader(active, options) {
|
|
304
|
-
const id =
|
|
408
|
+
const id = React12.useId();
|
|
305
409
|
const claim = usePageHeaderStore((s) => s.claim);
|
|
306
410
|
const release = usePageHeaderStore((s) => s.release);
|
|
307
411
|
const back = options?.back ?? false;
|
|
308
|
-
|
|
412
|
+
React12.useEffect(() => {
|
|
309
413
|
if (!active) {
|
|
310
414
|
release(id);
|
|
311
415
|
return;
|
|
@@ -317,13 +421,23 @@ function usePageHeader(active, options) {
|
|
|
317
421
|
function useHasPageHeaderBack() {
|
|
318
422
|
return usePageHeaderStore((s) => s.hasBack);
|
|
319
423
|
}
|
|
424
|
+
function useModuleViewLabel() {
|
|
425
|
+
return usePageHeaderStore((s) => s.moduleViewLabel);
|
|
426
|
+
}
|
|
427
|
+
function usePublishModuleViewLabel(label) {
|
|
428
|
+
const setLabel = usePageHeaderStore((s) => s.setModuleViewLabel);
|
|
429
|
+
React12.useEffect(() => {
|
|
430
|
+
setLabel(label ?? null);
|
|
431
|
+
return () => setLabel(null);
|
|
432
|
+
}, [label, setLabel]);
|
|
433
|
+
}
|
|
320
434
|
function PageTitlePortal({ children }) {
|
|
321
435
|
const slot = usePageTitleSlot();
|
|
322
|
-
if (!slot) return
|
|
436
|
+
if (!slot) return React12.createElement(React12.Fragment, null, children);
|
|
323
437
|
return createPortal(children, slot);
|
|
324
438
|
}
|
|
325
|
-
var Hint =
|
|
326
|
-
if (!label) return
|
|
439
|
+
var Hint = React12.forwardRef(function Hint2({ label, children, side = "top", delayDuration = 0, ...rest }, ref) {
|
|
440
|
+
if (!label) return React12.cloneElement(children, { ...rest, ref });
|
|
327
441
|
return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
328
442
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, ...rest, ref, children }),
|
|
329
443
|
/* @__PURE__ */ jsx(TooltipContent, { side, className: "px-2 py-1 text-xs font-medium", children: label })
|
|
@@ -412,7 +526,7 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
|
|
|
412
526
|
const hasHost = useHasPageHeaderHost();
|
|
413
527
|
const { onBack: effectiveOnBack, parentLabel: effectiveParent } = useCrossModuleBack(onBack, parentLabel);
|
|
414
528
|
useBackHandler(effectiveOnBack);
|
|
415
|
-
const node =
|
|
529
|
+
const node = React12.useMemo(() => /* @__PURE__ */ jsx(
|
|
416
530
|
PageHeaderCrumb,
|
|
417
531
|
{
|
|
418
532
|
title,
|
|
@@ -426,15 +540,15 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
|
|
|
426
540
|
}
|
|
427
541
|
var GUTTER_PX = 8;
|
|
428
542
|
var CLOSE_DELAY_MS = 140;
|
|
429
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ?
|
|
543
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React12.useLayoutEffect : React12.useEffect;
|
|
430
544
|
function iconOf(name) {
|
|
431
545
|
if (!name) return null;
|
|
432
546
|
return ICON_MAP[name] ?? null;
|
|
433
547
|
}
|
|
434
|
-
var RailFlyoutContext =
|
|
548
|
+
var RailFlyoutContext = React12.createContext(null);
|
|
435
549
|
var RailFlyoutProvider = RailFlyoutContext.Provider;
|
|
436
550
|
function useRailRow(content) {
|
|
437
|
-
const flyout =
|
|
551
|
+
const flyout = React12.useContext(RailFlyoutContext);
|
|
438
552
|
if (!flyout || !content) return {};
|
|
439
553
|
return flyout.rowProps(content);
|
|
440
554
|
}
|
|
@@ -444,19 +558,19 @@ function useRailFlyout({
|
|
|
444
558
|
activeRoute,
|
|
445
559
|
onNavigate
|
|
446
560
|
}) {
|
|
447
|
-
const [state, setState] =
|
|
448
|
-
const [pos, setPos] =
|
|
449
|
-
const [animate, setAnimate] =
|
|
450
|
-
const panelRef =
|
|
451
|
-
const closeTimer =
|
|
452
|
-
const lastContent =
|
|
453
|
-
const cancelClose =
|
|
561
|
+
const [state, setState] = React12.useState(null);
|
|
562
|
+
const [pos, setPos] = React12.useState({ top: 0, arrow: 20 });
|
|
563
|
+
const [animate, setAnimate] = React12.useState(false);
|
|
564
|
+
const panelRef = React12.useRef(null);
|
|
565
|
+
const closeTimer = React12.useRef(null);
|
|
566
|
+
const lastContent = React12.useRef(null);
|
|
567
|
+
const cancelClose = React12.useCallback(() => {
|
|
454
568
|
if (closeTimer.current) {
|
|
455
569
|
clearTimeout(closeTimer.current);
|
|
456
570
|
closeTimer.current = null;
|
|
457
571
|
}
|
|
458
572
|
}, []);
|
|
459
|
-
const show =
|
|
573
|
+
const show = React12.useCallback(
|
|
460
574
|
(anchor, content2) => {
|
|
461
575
|
if (!enabled) return;
|
|
462
576
|
cancelClose();
|
|
@@ -464,19 +578,19 @@ function useRailFlyout({
|
|
|
464
578
|
},
|
|
465
579
|
[enabled, cancelClose]
|
|
466
580
|
);
|
|
467
|
-
const hide =
|
|
581
|
+
const hide = React12.useCallback(() => {
|
|
468
582
|
cancelClose();
|
|
469
583
|
closeTimer.current = setTimeout(() => setState(null), CLOSE_DELAY_MS);
|
|
470
584
|
}, [cancelClose]);
|
|
471
|
-
const dismiss =
|
|
585
|
+
const dismiss = React12.useCallback(() => {
|
|
472
586
|
cancelClose();
|
|
473
587
|
setState(null);
|
|
474
588
|
}, [cancelClose]);
|
|
475
|
-
|
|
476
|
-
|
|
589
|
+
React12.useEffect(() => () => cancelClose(), [cancelClose]);
|
|
590
|
+
React12.useEffect(() => {
|
|
477
591
|
if (!enabled) dismiss();
|
|
478
592
|
}, [enabled, dismiss]);
|
|
479
|
-
const reposition =
|
|
593
|
+
const reposition = React12.useCallback(() => {
|
|
480
594
|
const rail = railRef.current;
|
|
481
595
|
const anchor = state?.anchor;
|
|
482
596
|
if (!rail || !anchor) return;
|
|
@@ -491,7 +605,7 @@ function useRailFlyout({
|
|
|
491
605
|
setPos({ top, arrow });
|
|
492
606
|
}, [railRef, state]);
|
|
493
607
|
useIsomorphicLayoutEffect(reposition, [reposition, state?.content.key]);
|
|
494
|
-
|
|
608
|
+
React12.useEffect(() => {
|
|
495
609
|
if (!state) return;
|
|
496
610
|
const rail = railRef.current;
|
|
497
611
|
const onScroll = () => reposition();
|
|
@@ -503,7 +617,7 @@ function useRailFlyout({
|
|
|
503
617
|
};
|
|
504
618
|
}, [state, railRef, reposition]);
|
|
505
619
|
const visible = !!state;
|
|
506
|
-
|
|
620
|
+
React12.useEffect(() => {
|
|
507
621
|
if (!visible) {
|
|
508
622
|
setAnimate(false);
|
|
509
623
|
return;
|
|
@@ -511,7 +625,7 @@ function useRailFlyout({
|
|
|
511
625
|
const id = requestAnimationFrame(() => setAnimate(true));
|
|
512
626
|
return () => cancelAnimationFrame(id);
|
|
513
627
|
}, [visible]);
|
|
514
|
-
|
|
628
|
+
React12.useEffect(() => {
|
|
515
629
|
if (!visible) return;
|
|
516
630
|
const onKey = (event) => {
|
|
517
631
|
if (event.key === "Escape") dismiss();
|
|
@@ -519,7 +633,7 @@ function useRailFlyout({
|
|
|
519
633
|
window.addEventListener("keydown", onKey);
|
|
520
634
|
return () => window.removeEventListener("keydown", onKey);
|
|
521
635
|
}, [visible, dismiss]);
|
|
522
|
-
const rowProps =
|
|
636
|
+
const rowProps = React12.useCallback(
|
|
523
637
|
(content2) => ({
|
|
524
638
|
onMouseEnter: (event) => show(event.currentTarget, content2),
|
|
525
639
|
onFocus: (event) => show(event.currentTarget, content2),
|
|
@@ -555,6 +669,7 @@ function useRailFlyout({
|
|
|
555
669
|
"div",
|
|
556
670
|
{
|
|
557
671
|
ref: panelRef,
|
|
672
|
+
style: { borderTopLeftRadius: 2, borderBottomLeftRadius: 2 },
|
|
558
673
|
className: cn(
|
|
559
674
|
// Sidebar tone, sidebar border: the panel is the menu leaning out,
|
|
560
675
|
// not a popover from the page underneath it.
|
|
@@ -635,8 +750,53 @@ function FlyoutBody({
|
|
|
635
750
|
] })
|
|
636
751
|
] });
|
|
637
752
|
}
|
|
753
|
+
function NavChildConnector({ onPath, active }) {
|
|
754
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
755
|
+
onPath && /* @__PURE__ */ jsx(
|
|
756
|
+
"span",
|
|
757
|
+
{
|
|
758
|
+
"aria-hidden": true,
|
|
759
|
+
className: "pointer-events-none absolute bottom-0 left-[13px] top-0 w-[1.5px] bg-current"
|
|
760
|
+
}
|
|
761
|
+
),
|
|
762
|
+
active && /* @__PURE__ */ jsxs(
|
|
763
|
+
"svg",
|
|
764
|
+
{
|
|
765
|
+
"aria-hidden": true,
|
|
766
|
+
className: "pointer-events-none absolute left-1 top-0",
|
|
767
|
+
width: "21",
|
|
768
|
+
height: "32",
|
|
769
|
+
viewBox: "0 0 21 32",
|
|
770
|
+
fill: "none",
|
|
771
|
+
children: [
|
|
772
|
+
/* @__PURE__ */ jsx(
|
|
773
|
+
"path",
|
|
774
|
+
{
|
|
775
|
+
d: "M9.75 0 V11 Q9.75 16 14.75 16 H20",
|
|
776
|
+
stroke: "currentColor",
|
|
777
|
+
strokeWidth: "1.5",
|
|
778
|
+
strokeLinecap: "round",
|
|
779
|
+
fill: "none"
|
|
780
|
+
}
|
|
781
|
+
),
|
|
782
|
+
/* @__PURE__ */ jsx(
|
|
783
|
+
"path",
|
|
784
|
+
{
|
|
785
|
+
d: "M17 13 L20 16 L17 19",
|
|
786
|
+
stroke: "currentColor",
|
|
787
|
+
strokeWidth: "1.5",
|
|
788
|
+
strokeLinecap: "round",
|
|
789
|
+
strokeLinejoin: "round",
|
|
790
|
+
fill: "none"
|
|
791
|
+
}
|
|
792
|
+
)
|
|
793
|
+
]
|
|
794
|
+
}
|
|
795
|
+
)
|
|
796
|
+
] });
|
|
797
|
+
}
|
|
638
798
|
var RAIL_PUSH_MS = 260;
|
|
639
|
-
var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ?
|
|
799
|
+
var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ? React12.useLayoutEffect : React12.useEffect;
|
|
640
800
|
function getIcon(name) {
|
|
641
801
|
return ICON_MAP[name] ?? Home;
|
|
642
802
|
}
|
|
@@ -847,7 +1007,7 @@ function NavGroup({
|
|
|
847
1007
|
// case in an app that groups its rail).
|
|
848
1008
|
/* @__PURE__ */ jsx("button", { "data-tour": `nav.${child.route}`, onClick: () => onNavigate(child.route), className: childClass, children: childInner })
|
|
849
1009
|
);
|
|
850
|
-
if (!childConnector) return /* @__PURE__ */ jsx(
|
|
1010
|
+
if (!childConnector) return /* @__PURE__ */ jsx(React12.Fragment, { children: row }, child.id);
|
|
851
1011
|
const activeIndex = item.children.findIndex((c) => c.route === activeRoute);
|
|
852
1012
|
const onPath = activeIndex >= 0 && childIndex < activeIndex;
|
|
853
1013
|
return (
|
|
@@ -861,47 +1021,7 @@ function NavGroup({
|
|
|
861
1021
|
// to /70 when inactive, and a line fading along with the label it
|
|
862
1022
|
// points AT was nearly invisible on a dark rail.
|
|
863
1023
|
/* @__PURE__ */ jsxs("div", { className: "relative h-8 text-sidebar-foreground/45", children: [
|
|
864
|
-
|
|
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
|
-
),
|
|
1024
|
+
/* @__PURE__ */ jsx(NavChildConnector, { onPath, active: isActive }),
|
|
905
1025
|
row
|
|
906
1026
|
] }, child.id)
|
|
907
1027
|
);
|
|
@@ -909,9 +1029,9 @@ function NavGroup({
|
|
|
909
1029
|
] });
|
|
910
1030
|
}
|
|
911
1031
|
function withCollapsed(slot, collapsed) {
|
|
912
|
-
if (!
|
|
1032
|
+
if (!React12.isValidElement(slot)) return slot;
|
|
913
1033
|
if (typeof slot.type === "string") return slot;
|
|
914
|
-
return
|
|
1034
|
+
return React12.cloneElement(slot, { collapsed });
|
|
915
1035
|
}
|
|
916
1036
|
var SKELETON_ROWS = [
|
|
917
1037
|
{ width: 56, group: false },
|
|
@@ -953,7 +1073,7 @@ function Sidebar({
|
|
|
953
1073
|
}) {
|
|
954
1074
|
const currentPath = currentPathProp;
|
|
955
1075
|
const activeRoute = resolveActiveRoute(navigation, currentPath);
|
|
956
|
-
const railRef =
|
|
1076
|
+
const railRef = React12.useRef(null);
|
|
957
1077
|
const flyout = useRailFlyout({
|
|
958
1078
|
enabled: collapsed,
|
|
959
1079
|
railRef,
|
|
@@ -966,14 +1086,14 @@ function Sidebar({
|
|
|
966
1086
|
const handleNavigate = (route) => {
|
|
967
1087
|
onNavigate?.(route);
|
|
968
1088
|
};
|
|
969
|
-
const groupWithActiveRoute =
|
|
1089
|
+
const groupWithActiveRoute = React12.useMemo(() => {
|
|
970
1090
|
const groups = navigation.filter((item) => item.children && item.children.length > 0);
|
|
971
1091
|
return groups.find(
|
|
972
1092
|
(item) => item.route === activeRoute || item.children.some((child) => child.route === activeRoute)
|
|
973
1093
|
)?.id ?? null;
|
|
974
1094
|
}, [navigation, activeRoute]);
|
|
975
|
-
const [openGroup, setOpenGroup] =
|
|
976
|
-
|
|
1095
|
+
const [openGroup, setOpenGroup] = React12.useState(groupWithActiveRoute);
|
|
1096
|
+
React12.useEffect(() => {
|
|
977
1097
|
if (groupWithActiveRoute) setOpenGroup(groupWithActiveRoute);
|
|
978
1098
|
}, [groupWithActiveRoute]);
|
|
979
1099
|
const sectionHeading = (label) => label && !collapsed ? /* @__PURE__ */ jsx("p", { className: "px-2.5 pb-0.5 pt-1 text-[10px] font-semibold uppercase tracking-wider text-sidebar-muted", children: label }) : null;
|
|
@@ -1025,10 +1145,10 @@ function Sidebar({
|
|
|
1025
1145
|
mainItems.length > 0 && renderSection(mainItems, sectionLabels?.main),
|
|
1026
1146
|
secondaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6", children: renderSection(secondaryItems, sectionLabels?.secondary) })
|
|
1027
1147
|
] });
|
|
1028
|
-
const [outgoing, setOutgoing] =
|
|
1029
|
-
const lastBodyRef =
|
|
1030
|
-
const lastKeyRef =
|
|
1031
|
-
const timerRef =
|
|
1148
|
+
const [outgoing, setOutgoing] = React12.useState(null);
|
|
1149
|
+
const lastBodyRef = React12.useRef(null);
|
|
1150
|
+
const lastKeyRef = React12.useRef(navKey);
|
|
1151
|
+
const timerRef = React12.useRef(null);
|
|
1032
1152
|
useIsomorphicLayoutEffect2(() => {
|
|
1033
1153
|
if (lastKeyRef.current !== navKey) {
|
|
1034
1154
|
const previousBody = lastBodyRef.current;
|
|
@@ -1041,7 +1161,7 @@ function Sidebar({
|
|
|
1041
1161
|
}
|
|
1042
1162
|
lastBodyRef.current = navBody;
|
|
1043
1163
|
});
|
|
1044
|
-
|
|
1164
|
+
React12.useEffect(() => () => {
|
|
1045
1165
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1046
1166
|
}, []);
|
|
1047
1167
|
return (
|
|
@@ -1285,7 +1405,7 @@ function ShellSearch({
|
|
|
1285
1405
|
const rail = tone === "rail";
|
|
1286
1406
|
const contextual = !!onValueChange && !collapsed;
|
|
1287
1407
|
const query = value ?? "";
|
|
1288
|
-
const inputRef =
|
|
1408
|
+
const inputRef = React12.useRef(null);
|
|
1289
1409
|
const escalate = () => setCommandPaletteOpen(true, query);
|
|
1290
1410
|
const surface = rail ? "bg-sidebar-accent/40 text-sidebar-muted hover:bg-sidebar-accent/70 hover:text-sidebar-foreground" : "bg-accent/40 text-muted-foreground hover:bg-accent/70 hover:text-foreground";
|
|
1291
1411
|
const ring = rail ? "focus-within:bg-sidebar-accent/70 focus-within:ring-1 focus-within:ring-sidebar-accent-foreground/25" : "focus-within:bg-accent/70 focus-within:ring-1 focus-within:ring-ring/40";
|
|
@@ -1396,7 +1516,7 @@ function TopbarUserMenu({
|
|
|
1396
1516
|
onBilling,
|
|
1397
1517
|
userMenuExtras
|
|
1398
1518
|
}) {
|
|
1399
|
-
const [open, setOpen] =
|
|
1519
|
+
const [open, setOpen] = React12.useState(false);
|
|
1400
1520
|
if (!user) return null;
|
|
1401
1521
|
const initial = (user.fullName?.trim()?.[0] ?? user.email?.[0] ?? "?").toUpperCase();
|
|
1402
1522
|
const item = (label, onClick, Icon) => onClick ? /* @__PURE__ */ jsxs(
|
|
@@ -1480,7 +1600,7 @@ function getIcon2(name) {
|
|
|
1480
1600
|
return ICON_MAP[name] ?? Home;
|
|
1481
1601
|
}
|
|
1482
1602
|
function NavDropdown({ item, currentPath, onNavigate }) {
|
|
1483
|
-
const [open, setOpen] =
|
|
1603
|
+
const [open, setOpen] = React12.useState(false);
|
|
1484
1604
|
const Icon = getIcon2(item.icon);
|
|
1485
1605
|
const isChildActive = item.children?.some(
|
|
1486
1606
|
(child) => currentPath === child.route || currentPath.startsWith(child.route + "/")
|
|
@@ -1648,9 +1768,9 @@ function Topbar({
|
|
|
1648
1768
|
] });
|
|
1649
1769
|
}
|
|
1650
1770
|
function useSheetDrag({ onDismiss, canDrag }) {
|
|
1651
|
-
const [offset, setOffset] =
|
|
1652
|
-
const [dragging, setDragging] =
|
|
1653
|
-
const start =
|
|
1771
|
+
const [offset, setOffset] = React12.useState(0);
|
|
1772
|
+
const [dragging, setDragging] = React12.useState(false);
|
|
1773
|
+
const start = React12.useRef(null);
|
|
1654
1774
|
const onPointerDown = (e) => {
|
|
1655
1775
|
if (e.pointerType === "mouse") return;
|
|
1656
1776
|
if (canDrag && !canDrag()) return;
|
|
@@ -1684,9 +1804,9 @@ function useSheetDrag({ onDismiss, canDrag }) {
|
|
|
1684
1804
|
handlers: { onPointerDown, onPointerMove, onPointerUp: end, onPointerCancel: end }
|
|
1685
1805
|
};
|
|
1686
1806
|
}
|
|
1687
|
-
var SheetCloseContext =
|
|
1807
|
+
var SheetCloseContext = React12.createContext(null);
|
|
1688
1808
|
function useSheetClose() {
|
|
1689
|
-
const close =
|
|
1809
|
+
const close = React12.useContext(SheetCloseContext);
|
|
1690
1810
|
return close ?? (() => {
|
|
1691
1811
|
});
|
|
1692
1812
|
}
|
|
@@ -1700,9 +1820,9 @@ function BottomSheet({
|
|
|
1700
1820
|
className,
|
|
1701
1821
|
label
|
|
1702
1822
|
}) {
|
|
1703
|
-
const [leaving, setLeaving] =
|
|
1704
|
-
const scroller =
|
|
1705
|
-
const close =
|
|
1823
|
+
const [leaving, setLeaving] = React12.useState(false);
|
|
1824
|
+
const scroller = React12.useRef(null);
|
|
1825
|
+
const close = React12.useCallback(() => {
|
|
1706
1826
|
setLeaving(true);
|
|
1707
1827
|
window.setTimeout(onClose, 200);
|
|
1708
1828
|
}, [onClose]);
|
|
@@ -1710,7 +1830,7 @@ function BottomSheet({
|
|
|
1710
1830
|
onDismiss: close,
|
|
1711
1831
|
canDrag: () => (scroller.current?.scrollTop ?? 0) <= 0
|
|
1712
1832
|
});
|
|
1713
|
-
|
|
1833
|
+
React12.useEffect(() => {
|
|
1714
1834
|
const onKey = (e) => {
|
|
1715
1835
|
if (e.key !== "Escape") return;
|
|
1716
1836
|
if (onBack) onBack();
|
|
@@ -1719,15 +1839,15 @@ function BottomSheet({
|
|
|
1719
1839
|
window.addEventListener("keydown", onKey);
|
|
1720
1840
|
return () => window.removeEventListener("keydown", onKey);
|
|
1721
1841
|
}, [close, onBack]);
|
|
1722
|
-
|
|
1842
|
+
React12.useEffect(() => {
|
|
1723
1843
|
const previous = document.body.style.overflow;
|
|
1724
1844
|
document.body.style.overflow = "hidden";
|
|
1725
1845
|
return () => {
|
|
1726
1846
|
document.body.style.overflow = previous;
|
|
1727
1847
|
};
|
|
1728
1848
|
}, []);
|
|
1729
|
-
const [host, setHost] =
|
|
1730
|
-
|
|
1849
|
+
const [host, setHost] = React12.useState(null);
|
|
1850
|
+
React12.useEffect(() => {
|
|
1731
1851
|
setHost(document.body);
|
|
1732
1852
|
}, []);
|
|
1733
1853
|
if (!host) return null;
|
|
@@ -1842,17 +1962,17 @@ function SheetRow({
|
|
|
1842
1962
|
}
|
|
1843
1963
|
);
|
|
1844
1964
|
}
|
|
1845
|
-
var ModuleHeaderSlotContext =
|
|
1965
|
+
var ModuleHeaderSlotContext = React12.createContext(null);
|
|
1846
1966
|
function useModuleHeaderSlot() {
|
|
1847
|
-
return
|
|
1967
|
+
return React12.useContext(ModuleHeaderSlotContext);
|
|
1848
1968
|
}
|
|
1849
|
-
var ModuleHeaderActionsSlotContext =
|
|
1969
|
+
var ModuleHeaderActionsSlotContext = React12.createContext(null);
|
|
1850
1970
|
function useModuleHeaderActionsSlot() {
|
|
1851
|
-
return
|
|
1971
|
+
return React12.useContext(ModuleHeaderActionsSlotContext);
|
|
1852
1972
|
}
|
|
1853
|
-
var PageRailSlotContext =
|
|
1973
|
+
var PageRailSlotContext = React12.createContext(null);
|
|
1854
1974
|
function usePageRailSlot() {
|
|
1855
|
-
return
|
|
1975
|
+
return React12.useContext(PageRailSlotContext);
|
|
1856
1976
|
}
|
|
1857
1977
|
function isCreateRoute(route) {
|
|
1858
1978
|
return !!route && /\/(new|create)$/.test(route);
|
|
@@ -1939,9 +2059,9 @@ function SidebarLayout({
|
|
|
1939
2059
|
const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
|
|
1940
2060
|
const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
1941
2061
|
const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
1942
|
-
const [headerSlot, setHeaderSlot] =
|
|
1943
|
-
const [actionsSlot, setActionsSlot] =
|
|
1944
|
-
const [pageRailSlot, setPageRailSlot] =
|
|
2062
|
+
const [headerSlot, setHeaderSlot] = React12.useState(null);
|
|
2063
|
+
const [actionsSlot, setActionsSlot] = React12.useState(null);
|
|
2064
|
+
const [pageRailSlot, setPageRailSlot] = React12.useState(null);
|
|
1945
2065
|
const hasPageActions = useHasPageActions();
|
|
1946
2066
|
return /* @__PURE__ */ jsx(SaveBarProvider, { children: /* @__PURE__ */ jsx(ModuleHeaderSlotContext.Provider, { value: headerSlot, children: /* @__PURE__ */ jsx(ModuleHeaderActionsSlotContext.Provider, { value: actionsSlot, children: /* @__PURE__ */ jsx(PageRailSlotContext.Provider, { value: pageRailSlot, children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
1947
2067
|
"shell-enter fz-viewport-h flex overflow-hidden bg-background",
|
|
@@ -2014,6 +2134,10 @@ function SidebarLayout({
|
|
|
2014
2134
|
// Com `min-h` bastava um controle mais alto de um lado para o cartão
|
|
2015
2135
|
// daquele lado descer sozinho.
|
|
2016
2136
|
frame && "fz-on-band md:h-14 md:border-b-0 md:text-sidebar-foreground md:[--accent-foreground:var(--sidebar-accent-foreground)] md:[--accent:var(--sidebar-accent)] md:[--background:var(--sidebar)] md:[--border:var(--sidebar-border)] md:[--card:var(--sidebar)] md:[--foreground:var(--sidebar-foreground)] md:[--muted-foreground:var(--sidebar-muted)] md:[--muted:var(--sidebar-accent)]",
|
|
2137
|
+
// A destination keeps the app controls; a deeper screen keeps its
|
|
2138
|
+
// own title/back row. On phones with complete bottom navigation,
|
|
2139
|
+
// showing both was a two-storey header with no extra way out.
|
|
2140
|
+
barOwnsNav && !pagePrimary && "hidden md:flex",
|
|
2017
2141
|
// …unless the page put its actions in it. Hiding the bar on mobile
|
|
2018
2142
|
// used to hide the only "Novo" the screen had.
|
|
2019
2143
|
mobileHeader !== "minimal" && !hasPageActions && "hidden md:flex",
|
|
@@ -2076,16 +2200,52 @@ function SidebarLayout({
|
|
|
2076
2200
|
frame && (railOpen ? "md:rounded-r-none md:border-r-0" : "md:mr-2"),
|
|
2077
2201
|
immersive && "md:overflow-hidden"
|
|
2078
2202
|
), children: [
|
|
2079
|
-
/* @__PURE__ */ jsxs(
|
|
2080
|
-
"
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2203
|
+
/* @__PURE__ */ jsxs(
|
|
2204
|
+
"div",
|
|
2205
|
+
{
|
|
2206
|
+
style: {
|
|
2207
|
+
// A RÉGUA NÃO ATRAVESSA A COLUNA DO MÓDULO.
|
|
2208
|
+
//
|
|
2209
|
+
// Ela fecha o cabeçalho, e o cabeçalho termina onde a coluna começa:
|
|
2210
|
+
// sobre a coluna, a mesma linha separava duas coisas que são uma só —
|
|
2211
|
+
// o nome da tela e o menu que pende dele. Tapar o pedaço com um pixel
|
|
2212
|
+
// da cor do papel funcionava num tema e falhava no outro, porque o
|
|
2213
|
+
// papel do cartão e o `--page-surface` nem sempre são a mesma tinta.
|
|
2214
|
+
//
|
|
2215
|
+
// Então ela NASCE depois: a régua é um degradê de 1px que só começa
|
|
2216
|
+
// em `--page-rail-seam` — a largura da coluna mais o raio da curva,
|
|
2217
|
+
// publicado por quem a desenha (ver RailColumn). Sem coluna, a
|
|
2218
|
+
// variável não existe e a régua começa em zero, como sempre.
|
|
2219
|
+
backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
|
|
2220
|
+
backgroundSize: "100% 1px",
|
|
2221
|
+
backgroundRepeat: "no-repeat",
|
|
2222
|
+
backgroundPosition: "left bottom"
|
|
2223
|
+
},
|
|
2224
|
+
className: cn(
|
|
2225
|
+
// O MESMO vidro da coluna do módulo logo abaixo — uma classe só,
|
|
2226
|
+
// senão as duas superfícies encostadas saem em tons diferentes e
|
|
2227
|
+
// a emenda que acabamos de apagar volta como degrau de cor.
|
|
2228
|
+
"fz-liquid-glass relative z-20 flex min-h-12 shrink-0 items-center justify-between gap-3 px-3 md:px-6",
|
|
2229
|
+
menuOpen && "invisible md:visible",
|
|
2230
|
+
// On a primary phone destination the selected bottom-nav item
|
|
2231
|
+
// already names the page. Declared actions render as a body-level
|
|
2232
|
+
// FAB, so this entire duplicate band can disappear.
|
|
2233
|
+
barOwnsNav && pagePrimary && "hidden md:flex"
|
|
2234
|
+
),
|
|
2235
|
+
children: [
|
|
2236
|
+
/* @__PURE__ */ jsxs("div", { className: cn(
|
|
2237
|
+
"flex min-w-0 flex-1 items-center gap-3",
|
|
2238
|
+
// Primary destinations are already named by the selected mobile
|
|
2239
|
+
// navigation item. Keep this side only for deeper breadcrumbs.
|
|
2240
|
+
pagePrimary && "hidden md:flex"
|
|
2241
|
+
), children: [
|
|
2242
|
+
!pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack, primary: pagePrimary }),
|
|
2243
|
+
/* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" })
|
|
2244
|
+
] }),
|
|
2245
|
+
/* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
|
|
2246
|
+
]
|
|
2247
|
+
}
|
|
2248
|
+
),
|
|
2089
2249
|
/* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 overflow-hidden", children: [
|
|
2090
2250
|
/* @__PURE__ */ jsx("div", { ref: setPageRailSlot, className: "flex shrink-0 empty:hidden" }),
|
|
2091
2251
|
/* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", children: [
|
|
@@ -2182,9 +2342,9 @@ function TopbarLayout({
|
|
|
2182
2342
|
}) {
|
|
2183
2343
|
const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
2184
2344
|
const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
2185
|
-
const [headerSlot, setHeaderSlot] =
|
|
2186
|
-
const [actionsSlot, setActionsSlot] =
|
|
2187
|
-
const [pageRailSlot, setPageRailSlot] =
|
|
2345
|
+
const [headerSlot, setHeaderSlot] = React12.useState(null);
|
|
2346
|
+
const [actionsSlot, setActionsSlot] = React12.useState(null);
|
|
2347
|
+
const [pageRailSlot, setPageRailSlot] = React12.useState(null);
|
|
2188
2348
|
const rawClaimed = usePageHeaderClaimed();
|
|
2189
2349
|
const setTitleSlot = usePageTitleSlotHost();
|
|
2190
2350
|
const hasOutlet = useHasPageHeaderOutlet();
|
|
@@ -2223,10 +2383,16 @@ function TopbarLayout({
|
|
|
2223
2383
|
(pageHeaderClaimed || pageBack || hasPageActions || barOwnsNav) && /* @__PURE__ */ jsxs(
|
|
2224
2384
|
"div",
|
|
2225
2385
|
{
|
|
2386
|
+
style: {
|
|
2387
|
+
backgroundImage: "linear-gradient(to right, transparent 0 var(--page-rail-seam, 0px), hsl(var(--border)) var(--page-rail-seam, 0px) 100%)",
|
|
2388
|
+
backgroundSize: "100% 1px",
|
|
2389
|
+
backgroundRepeat: "no-repeat",
|
|
2390
|
+
backgroundPosition: "left bottom"
|
|
2391
|
+
},
|
|
2226
2392
|
className: cn(
|
|
2227
2393
|
// `relative` + glass for the same reason as the sidebar
|
|
2228
2394
|
// 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
|
|
2395
|
+
"relative flex min-h-[44px] md:min-h-12 shrink-0 items-center justify-between gap-3 px-4 py-2",
|
|
2230
2396
|
menuOpen && "invisible md:visible",
|
|
2231
2397
|
"fayz-glass-topbar",
|
|
2232
2398
|
!(pageHeaderClaimed || pageBack || hasPageActions) && "md:hidden"
|
|
@@ -2311,17 +2477,16 @@ function MobileMoreScreen({
|
|
|
2311
2477
|
orgSwitcher,
|
|
2312
2478
|
mobileIdentity,
|
|
2313
2479
|
identity,
|
|
2314
|
-
notificationSlot,
|
|
2315
2480
|
searchLabel,
|
|
2316
2481
|
sectionLabels,
|
|
2317
2482
|
leaving = false,
|
|
2318
2483
|
onDismiss,
|
|
2319
2484
|
onClose
|
|
2320
2485
|
}) {
|
|
2321
|
-
const [pushed, setPushed] =
|
|
2322
|
-
const [query, setQuery] =
|
|
2323
|
-
const scroller =
|
|
2324
|
-
const close =
|
|
2486
|
+
const [pushed, setPushed] = React12.useState(null);
|
|
2487
|
+
const [query, setQuery] = React12.useState("");
|
|
2488
|
+
const scroller = React12.useRef(null);
|
|
2489
|
+
const close = React12.useCallback(() => {
|
|
2325
2490
|
onClose();
|
|
2326
2491
|
}, [onClose]);
|
|
2327
2492
|
const drag = useSheetDrag({
|
|
@@ -2330,7 +2495,7 @@ function MobileMoreScreen({
|
|
|
2330
2495
|
// a pushed section would dismiss the screen the back button is for.
|
|
2331
2496
|
canDrag: () => !pushed && (scroller.current?.scrollTop ?? 0) <= 0
|
|
2332
2497
|
});
|
|
2333
|
-
|
|
2498
|
+
React12.useEffect(() => {
|
|
2334
2499
|
const onKey = (e) => {
|
|
2335
2500
|
if (e.key !== "Escape") return;
|
|
2336
2501
|
if (pushed) setPushed(null);
|
|
@@ -2339,7 +2504,7 @@ function MobileMoreScreen({
|
|
|
2339
2504
|
window.addEventListener("keydown", onKey);
|
|
2340
2505
|
return () => window.removeEventListener("keydown", onKey);
|
|
2341
2506
|
}, [close, pushed]);
|
|
2342
|
-
|
|
2507
|
+
React12.useEffect(() => {
|
|
2343
2508
|
const previous = document.body.style.overflow;
|
|
2344
2509
|
document.body.style.overflow = "hidden";
|
|
2345
2510
|
return () => {
|
|
@@ -2359,13 +2524,13 @@ function MobileMoreScreen({
|
|
|
2359
2524
|
else onNavigate?.(route);
|
|
2360
2525
|
};
|
|
2361
2526
|
const q = query.trim().toLowerCase();
|
|
2362
|
-
const flat =
|
|
2527
|
+
const flat = React12.useMemo(
|
|
2363
2528
|
() => navigation.flatMap((n) => n.children?.length ? n.children : [n]),
|
|
2364
2529
|
[navigation]
|
|
2365
2530
|
);
|
|
2366
2531
|
const searching = q.length > 0;
|
|
2367
2532
|
const hits = searching ? flat.filter((n) => n.label.toLowerCase().includes(q)) : [];
|
|
2368
|
-
const sections =
|
|
2533
|
+
const sections = React12.useMemo(() => {
|
|
2369
2534
|
const out = [];
|
|
2370
2535
|
for (const key of ["main", "secondary", "settings"]) {
|
|
2371
2536
|
const items = navigation.filter((n) => n.section === key);
|
|
@@ -2386,7 +2551,10 @@ function MobileMoreScreen({
|
|
|
2386
2551
|
"div",
|
|
2387
2552
|
{
|
|
2388
2553
|
className: cn(
|
|
2389
|
-
|
|
2554
|
+
// Isolate the full-screen menu into its own backdrop root. Without it,
|
|
2555
|
+
// the glass header samples the app header underneath and both sets of
|
|
2556
|
+
// controls become visible in the same 44px strip.
|
|
2557
|
+
"fixed inset-0 z-[65] isolate flex flex-col bg-background text-foreground will-change-transform md:hidden",
|
|
2390
2558
|
leaving ? "fz-sheet-out" : "fz-sheet-in",
|
|
2391
2559
|
drag.dragging && "transition-none",
|
|
2392
2560
|
!drag.dragging && !leaving && "transition-transform duration-200 ease-out"
|
|
@@ -2410,18 +2578,15 @@ function MobileMoreScreen({
|
|
|
2410
2578
|
}
|
|
2411
2579
|
) }),
|
|
2412
2580
|
/* @__PURE__ */ jsx("h1", { className: "truncate px-1 text-[15px] font-semibold", children: pushed?.label ?? "Mais" }),
|
|
2413
|
-
/* @__PURE__ */
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
"button",
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
}
|
|
2423
|
-
)
|
|
2424
|
-
] })
|
|
2581
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 items-center justify-end gap-1", children: /* @__PURE__ */ jsx(
|
|
2582
|
+
"button",
|
|
2583
|
+
{
|
|
2584
|
+
type: "button",
|
|
2585
|
+
onClick: close,
|
|
2586
|
+
className: "fz-ios-tint fz-tap rounded-button px-2 py-1 text-[15px] font-semibold",
|
|
2587
|
+
children: "Conclu\xEDdo"
|
|
2588
|
+
}
|
|
2589
|
+
) })
|
|
2425
2590
|
] }) }),
|
|
2426
2591
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsxs(
|
|
2427
2592
|
"div",
|
|
@@ -2634,23 +2799,23 @@ function MinimalLayout({
|
|
|
2634
2799
|
] });
|
|
2635
2800
|
}
|
|
2636
2801
|
function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
|
|
2637
|
-
const [visible, setVisible] =
|
|
2638
|
-
|
|
2802
|
+
const [visible, setVisible] = React12.useState(false);
|
|
2803
|
+
React12.useEffect(() => {
|
|
2639
2804
|
const id = requestAnimationFrame(() => setVisible(true));
|
|
2640
2805
|
return () => cancelAnimationFrame(id);
|
|
2641
2806
|
}, []);
|
|
2642
|
-
const close =
|
|
2807
|
+
const close = React12.useCallback(() => {
|
|
2643
2808
|
setVisible(false);
|
|
2644
2809
|
window.setTimeout(onClose, 250);
|
|
2645
2810
|
}, [onClose]);
|
|
2646
|
-
|
|
2811
|
+
React12.useEffect(() => {
|
|
2647
2812
|
const previous = document.body.style.overflow;
|
|
2648
2813
|
document.body.style.overflow = "hidden";
|
|
2649
2814
|
return () => {
|
|
2650
2815
|
document.body.style.overflow = previous;
|
|
2651
2816
|
};
|
|
2652
2817
|
}, []);
|
|
2653
|
-
|
|
2818
|
+
React12.useEffect(() => {
|
|
2654
2819
|
const onKey = (e) => {
|
|
2655
2820
|
if (e.key === "Escape") close();
|
|
2656
2821
|
};
|
|
@@ -2753,11 +2918,11 @@ function MobileBottomNav({
|
|
|
2753
2918
|
retracted
|
|
2754
2919
|
}) {
|
|
2755
2920
|
const path = currentPath ?? "";
|
|
2756
|
-
const [openSheet, setOpenSheet] =
|
|
2757
|
-
|
|
2921
|
+
const [openSheet, setOpenSheet] = React12.useState(null);
|
|
2922
|
+
React12.useEffect(() => {
|
|
2758
2923
|
setOpenSheet(null);
|
|
2759
2924
|
}, [currentPath]);
|
|
2760
|
-
|
|
2925
|
+
React12.useEffect(() => {
|
|
2761
2926
|
if (retracted) setOpenSheet(null);
|
|
2762
2927
|
}, [retracted]);
|
|
2763
2928
|
const sheetItem = openSheet != null ? items[openSheet] : void 0;
|
|
@@ -2768,12 +2933,8 @@ function MobileBottomNav({
|
|
|
2768
2933
|
"aria-label": "Navega\xE7\xE3o principal",
|
|
2769
2934
|
"aria-hidden": retracted || void 0,
|
|
2770
2935
|
className: cn(
|
|
2771
|
-
// Liquid glass, not a painted strip: the bar sits ON the content, so
|
|
2772
|
-
// the content keeps showing through it as a wash. An opaque bar in the
|
|
2773
|
-
// page's own colour just cut the screen short; an opaque bar in the
|
|
2774
|
-
// RAIL's dark colour made a phone look like it had a second theme.
|
|
2775
2936
|
"fz-safe-b fixed inset-x-0 bottom-0 z-50 flex min-h-16 items-stretch justify-around md:hidden",
|
|
2776
|
-
"
|
|
2937
|
+
"border-t border-sidebar-border bg-sidebar text-sidebar-foreground shadow-[0_-8px_24px_hsl(var(--sidebar)/0.18)]",
|
|
2777
2938
|
"motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-out",
|
|
2778
2939
|
retracted && "pointer-events-none translate-y-full"
|
|
2779
2940
|
),
|
|
@@ -2826,7 +2987,7 @@ function MobileBottomNav({
|
|
|
2826
2987
|
// min-h-[44px] is the floor a finger needs; the bar was letting
|
|
2827
2988
|
// content decide and landing around 40.
|
|
2828
2989
|
"relative flex min-h-[44px] flex-1 flex-col items-center justify-center gap-0.5 px-1 py-2 transition-colors",
|
|
2829
|
-
isActive ? "text-
|
|
2990
|
+
isActive ? "text-sidebar-accent-foreground" : "text-sidebar-muted"
|
|
2830
2991
|
),
|
|
2831
2992
|
children: [
|
|
2832
2993
|
/* @__PURE__ */ jsx(
|
|
@@ -2835,7 +2996,7 @@ function MobileBottomNav({
|
|
|
2835
2996
|
"aria-hidden": true,
|
|
2836
2997
|
className: cn(
|
|
2837
2998
|
"absolute inset-x-3 top-0 h-0.5 rounded-full transition-opacity",
|
|
2838
|
-
isActive ? "bg-
|
|
2999
|
+
isActive ? "bg-sidebar-accent-foreground opacity-100" : "opacity-0"
|
|
2839
3000
|
)
|
|
2840
3001
|
}
|
|
2841
3002
|
),
|
|
@@ -2933,7 +3094,7 @@ function AppShell({
|
|
|
2933
3094
|
const hasBottomNav = !!bottomNav?.length;
|
|
2934
3095
|
const barOwnsNav = bottomNavReachesAll(bottomNav);
|
|
2935
3096
|
const menuNavigation = appNavigation ?? navigation;
|
|
2936
|
-
const routeLabel =
|
|
3097
|
+
const routeLabel = React12.useCallback((path) => {
|
|
2937
3098
|
let best;
|
|
2938
3099
|
const consider = (route, label) => {
|
|
2939
3100
|
if (!route || !label) return;
|
|
@@ -2948,14 +3109,14 @@ function AppShell({
|
|
|
2948
3109
|
}
|
|
2949
3110
|
return best?.label ?? pageTitle ?? "";
|
|
2950
3111
|
}, [menuNavigation, pageTitle]);
|
|
2951
|
-
|
|
3112
|
+
React12.useEffect(() => {
|
|
2952
3113
|
if (!currentPath) return;
|
|
2953
3114
|
if (currentPath === MENU_ROUTE) return;
|
|
2954
3115
|
const label = routeLabel(currentPath);
|
|
2955
3116
|
if (!label) return;
|
|
2956
3117
|
recordNavigation(currentPath, label);
|
|
2957
3118
|
}, [currentPath, routeLabel]);
|
|
2958
|
-
const destinationRoutes =
|
|
3119
|
+
const destinationRoutes = React12.useMemo(() => {
|
|
2959
3120
|
const routes = [];
|
|
2960
3121
|
for (const item of menuNavigation) {
|
|
2961
3122
|
if (item.route) routes.push(item.route);
|
|
@@ -2964,7 +3125,7 @@ function AppShell({
|
|
|
2964
3125
|
return routes;
|
|
2965
3126
|
}, [menuNavigation]);
|
|
2966
3127
|
const isDestination = !!currentPath && destinationRoutes.includes(currentPath);
|
|
2967
|
-
|
|
3128
|
+
React12.useEffect(() => {
|
|
2968
3129
|
setDestinationRoutes(destinationRoutes);
|
|
2969
3130
|
}, [destinationRoutes]);
|
|
2970
3131
|
const pageClaimedBack = useHasPageHeaderBack();
|
|
@@ -2972,7 +3133,7 @@ function AppShell({
|
|
|
2972
3133
|
const barRetracted = !!pageBack || pageClaimedBack || inSettings;
|
|
2973
3134
|
const mobileDrawerOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
2974
3135
|
const setMobileDrawerOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
2975
|
-
|
|
3136
|
+
React12.useEffect(() => {
|
|
2976
3137
|
if (useLayoutStore.getState().drawerKeepOpenOnce) {
|
|
2977
3138
|
useLayoutStore.setState({ drawerKeepOpenOnce: false });
|
|
2978
3139
|
return;
|
|
@@ -2980,12 +3141,12 @@ function AppShell({
|
|
|
2980
3141
|
setMobileDrawerOpen(false);
|
|
2981
3142
|
}, [currentPath]);
|
|
2982
3143
|
const menuRouteOpen = barOwnsNav && currentPath === MENU_ROUTE;
|
|
2983
|
-
const firstDestination =
|
|
3144
|
+
const firstDestination = React12.useMemo(() => {
|
|
2984
3145
|
const first = bottomNav?.find((i) => !("kind" in i) || i.kind === "route");
|
|
2985
3146
|
return first?.route ?? "/";
|
|
2986
3147
|
}, [bottomNav]);
|
|
2987
|
-
const menuOrigin =
|
|
2988
|
-
const openMenu =
|
|
3148
|
+
const menuOrigin = React12.useRef(void 0);
|
|
3149
|
+
const openMenu = React12.useCallback(() => {
|
|
2989
3150
|
if (!barOwnsNav) {
|
|
2990
3151
|
setMobileDrawerOpen(true);
|
|
2991
3152
|
return;
|
|
@@ -2996,10 +3157,10 @@ function AppShell({
|
|
|
2996
3157
|
menuOrigin.current = currentPath;
|
|
2997
3158
|
onNavigate?.(MENU_ROUTE);
|
|
2998
3159
|
}, [barOwnsNav, currentPath, onNavigate, setMobileDrawerOpen]);
|
|
2999
|
-
const [menuLeaving, setMenuLeaving] =
|
|
3000
|
-
const [menuLingering, setMenuLingering] =
|
|
3001
|
-
const menuTimer =
|
|
3002
|
-
const dismissMenu =
|
|
3160
|
+
const [menuLeaving, setMenuLeaving] = React12.useState(false);
|
|
3161
|
+
const [menuLingering, setMenuLingering] = React12.useState(false);
|
|
3162
|
+
const menuTimer = React12.useRef(void 0);
|
|
3163
|
+
const dismissMenu = React12.useCallback((navigate) => {
|
|
3003
3164
|
window.clearTimeout(menuTimer.current);
|
|
3004
3165
|
setMenuLingering(true);
|
|
3005
3166
|
setMenuLeaving(true);
|
|
@@ -3009,8 +3170,8 @@ function AppShell({
|
|
|
3009
3170
|
setMenuLingering(false);
|
|
3010
3171
|
}, 240);
|
|
3011
3172
|
}, []);
|
|
3012
|
-
|
|
3013
|
-
const closeMenu =
|
|
3173
|
+
React12.useEffect(() => () => window.clearTimeout(menuTimer.current), []);
|
|
3174
|
+
const closeMenu = React12.useCallback(() => {
|
|
3014
3175
|
if (!barOwnsNav) {
|
|
3015
3176
|
setMobileDrawerOpen(false);
|
|
3016
3177
|
return;
|
|
@@ -3023,7 +3184,7 @@ function AppShell({
|
|
|
3023
3184
|
onNavigate?.(back);
|
|
3024
3185
|
});
|
|
3025
3186
|
}, [barOwnsNav, setMobileDrawerOpen, onNavigate, firstDestination, dismissMenu]);
|
|
3026
|
-
|
|
3187
|
+
React12.useEffect(() => {
|
|
3027
3188
|
if (!menuRouteOpen || typeof window === "undefined") return;
|
|
3028
3189
|
const wide = window.matchMedia("(min-width: 768px)");
|
|
3029
3190
|
const settle = () => {
|
|
@@ -3184,13 +3345,13 @@ function SplitWithRightRail({
|
|
|
3184
3345
|
maxWidth = 720,
|
|
3185
3346
|
resizeLabel = "Resize panel"
|
|
3186
3347
|
}) {
|
|
3187
|
-
const [width, setWidth] =
|
|
3188
|
-
const [dragging, setDragging] =
|
|
3189
|
-
const clamp =
|
|
3348
|
+
const [width, setWidth] = React12.useState(defaultWidth);
|
|
3349
|
+
const [dragging, setDragging] = React12.useState(false);
|
|
3350
|
+
const clamp = React12.useCallback(
|
|
3190
3351
|
(value) => Math.min(maxWidth, Math.max(minWidth, value)),
|
|
3191
3352
|
[minWidth, maxWidth]
|
|
3192
3353
|
);
|
|
3193
|
-
|
|
3354
|
+
React12.useEffect(() => {
|
|
3194
3355
|
if (!dragging) return;
|
|
3195
3356
|
const onMove = (event) => {
|
|
3196
3357
|
event.preventDefault();
|
|
@@ -3212,7 +3373,7 @@ function SplitWithRightRail({
|
|
|
3212
3373
|
document.body.style.cursor = previousCursor;
|
|
3213
3374
|
};
|
|
3214
3375
|
}, [dragging, clamp]);
|
|
3215
|
-
|
|
3376
|
+
React12.useEffect(() => {
|
|
3216
3377
|
if (dragging) return;
|
|
3217
3378
|
onWidthChange?.(width);
|
|
3218
3379
|
}, [dragging]);
|
|
@@ -3371,6 +3532,14 @@ function HeaderTabs({
|
|
|
3371
3532
|
}
|
|
3372
3533
|
);
|
|
3373
3534
|
}
|
|
3535
|
+
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]";
|
|
3536
|
+
var PAGE_BAND_SURFACE = { background: "var(--page-surface, hsl(var(--background)))" };
|
|
3537
|
+
function PageBand({ children, actions, className }) {
|
|
3538
|
+
return /* @__PURE__ */ jsxs("div", { style: PAGE_BAND_SURFACE, className: cn(PAGE_BAND_CLASS, "items-center", className), children: [
|
|
3539
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-3", children }),
|
|
3540
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2 empty:hidden", children: actions })
|
|
3541
|
+
] });
|
|
3542
|
+
}
|
|
3374
3543
|
function PageTabs({ actions, className, ...props }) {
|
|
3375
3544
|
return /* @__PURE__ */ jsxs(
|
|
3376
3545
|
"div",
|
|
@@ -3419,12 +3588,12 @@ function ViewTabs({ value, onChange, options, "aria-label": ariaLabel, className
|
|
|
3419
3588
|
);
|
|
3420
3589
|
}) });
|
|
3421
3590
|
}
|
|
3422
|
-
var NavTransitionContext =
|
|
3591
|
+
var NavTransitionContext = React12.createContext("slide");
|
|
3423
3592
|
function NavTransitionProvider({ value, children }) {
|
|
3424
3593
|
return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
|
|
3425
3594
|
}
|
|
3426
3595
|
function useNavTransition() {
|
|
3427
|
-
return
|
|
3596
|
+
return React12.useContext(NavTransitionContext);
|
|
3428
3597
|
}
|
|
3429
3598
|
function resolveTransitionClass(transition, direction) {
|
|
3430
3599
|
if (transition === "none") return "";
|
|
@@ -3444,26 +3613,26 @@ function PageTransition({
|
|
|
3444
3613
|
return /* @__PURE__ */ jsx("div", { className: cn(animClass, className), children }, transitionKey);
|
|
3445
3614
|
}
|
|
3446
3615
|
var EMPTY = [];
|
|
3447
|
-
var PageTrailContext =
|
|
3616
|
+
var PageTrailContext = React12.createContext(EMPTY);
|
|
3448
3617
|
function PageTrail({
|
|
3449
3618
|
label,
|
|
3450
3619
|
href,
|
|
3451
3620
|
onNavigate,
|
|
3452
3621
|
children
|
|
3453
3622
|
}) {
|
|
3454
|
-
const parent =
|
|
3455
|
-
const trail =
|
|
3623
|
+
const parent = React12.useContext(PageTrailContext);
|
|
3624
|
+
const trail = React12.useMemo(
|
|
3456
3625
|
() => [...parent, { label, href, onNavigate }],
|
|
3457
3626
|
[parent, label, href, onNavigate]
|
|
3458
3627
|
);
|
|
3459
3628
|
return /* @__PURE__ */ jsx(PageTrailContext.Provider, { value: trail, children });
|
|
3460
3629
|
}
|
|
3461
3630
|
function usePageTrail() {
|
|
3462
|
-
return
|
|
3631
|
+
return React12.useContext(PageTrailContext);
|
|
3463
3632
|
}
|
|
3464
3633
|
function usePageTrailParent(href) {
|
|
3465
|
-
const trail =
|
|
3466
|
-
return
|
|
3634
|
+
const trail = React12.useContext(PageTrailContext);
|
|
3635
|
+
return React12.useMemo(() => {
|
|
3467
3636
|
const above = href ? trail.filter((c) => c.href !== href) : trail;
|
|
3468
3637
|
return above[above.length - 1];
|
|
3469
3638
|
}, [trail, href]);
|
|
@@ -3473,15 +3642,15 @@ function navigateToCrumb(crumb) {
|
|
|
3473
3642
|
else window.location.hash = crumb.href;
|
|
3474
3643
|
}
|
|
3475
3644
|
function useCurrentRouteHref() {
|
|
3476
|
-
const
|
|
3645
|
+
const read2 = () => {
|
|
3477
3646
|
if (typeof window === "undefined") return "";
|
|
3478
3647
|
const hash = window.location.hash.replace(/^#/, "");
|
|
3479
3648
|
const clean = hash.split("?")[0];
|
|
3480
3649
|
return clean.startsWith("/") ? clean : `/${clean}`;
|
|
3481
3650
|
};
|
|
3482
|
-
const [href, setHref] =
|
|
3483
|
-
|
|
3484
|
-
const handler = () => setHref(
|
|
3651
|
+
const [href, setHref] = React12.useState(read2);
|
|
3652
|
+
React12.useEffect(() => {
|
|
3653
|
+
const handler = () => setHref(read2());
|
|
3485
3654
|
window.addEventListener("hashchange", handler);
|
|
3486
3655
|
handler();
|
|
3487
3656
|
return () => window.removeEventListener("hashchange", handler);
|
|
@@ -3491,11 +3660,246 @@ function useCurrentRouteHref() {
|
|
|
3491
3660
|
function useTrailBack(href) {
|
|
3492
3661
|
const current = useCurrentRouteHref();
|
|
3493
3662
|
const parent = usePageTrailParent(href ?? current);
|
|
3494
|
-
return
|
|
3663
|
+
return React12.useMemo(
|
|
3495
3664
|
() => parent ? { onBack: () => navigateToCrumb(parent), parentLabel: parent.label } : {},
|
|
3496
3665
|
[parent]
|
|
3497
3666
|
);
|
|
3498
3667
|
}
|
|
3668
|
+
var COLUMN_WIDTH = 224;
|
|
3669
|
+
var COLUMN_COLLAPSED_WIDTH = 64;
|
|
3670
|
+
function read(key) {
|
|
3671
|
+
try {
|
|
3672
|
+
return localStorage.getItem(key) === "1";
|
|
3673
|
+
} catch {
|
|
3674
|
+
return false;
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
function CollapsibleColumn({
|
|
3678
|
+
children,
|
|
3679
|
+
storageKey,
|
|
3680
|
+
footer,
|
|
3681
|
+
squeezed,
|
|
3682
|
+
autoCollapseKey,
|
|
3683
|
+
autoCollapseMs = 1800,
|
|
3684
|
+
onWidth,
|
|
3685
|
+
className,
|
|
3686
|
+
seamTop = 12,
|
|
3687
|
+
"aria-label": ariaLabel
|
|
3688
|
+
}) {
|
|
3689
|
+
const pinnedKey = `${storageKey}.pinned`;
|
|
3690
|
+
const [collapsed, setCollapsed] = React12.useState(() => read(storageKey));
|
|
3691
|
+
const [pinned, setPinned] = React12.useState(() => read(pinnedKey));
|
|
3692
|
+
const [hovering, setHovering] = React12.useState(false);
|
|
3693
|
+
const hoveringRef = React12.useRef(false);
|
|
3694
|
+
const collapsedRef = React12.useRef(collapsed);
|
|
3695
|
+
collapsedRef.current = collapsed;
|
|
3696
|
+
const autoRef = React12.useRef(false);
|
|
3697
|
+
const open = !collapsed || hovering;
|
|
3698
|
+
const width = open ? COLUMN_WIDTH : COLUMN_COLLAPSED_WIDTH;
|
|
3699
|
+
const setHover = (on) => {
|
|
3700
|
+
hoveringRef.current = on;
|
|
3701
|
+
setHovering(on);
|
|
3702
|
+
};
|
|
3703
|
+
React12.useEffect(() => {
|
|
3704
|
+
onWidth?.(width);
|
|
3705
|
+
}, [width, onWidth]);
|
|
3706
|
+
const setOpenState = React12.useCallback((nextCollapsed) => {
|
|
3707
|
+
setCollapsed(nextCollapsed);
|
|
3708
|
+
setPinned(!nextCollapsed);
|
|
3709
|
+
autoRef.current = false;
|
|
3710
|
+
try {
|
|
3711
|
+
localStorage.setItem(storageKey, nextCollapsed ? "1" : "0");
|
|
3712
|
+
localStorage.setItem(pinnedKey, nextCollapsed ? "0" : "1");
|
|
3713
|
+
} catch {
|
|
3714
|
+
}
|
|
3715
|
+
if (nextCollapsed) setHover(false);
|
|
3716
|
+
}, [storageKey, pinnedKey]);
|
|
3717
|
+
React12.useEffect(() => {
|
|
3718
|
+
if (squeezed === void 0) return;
|
|
3719
|
+
if (squeezed) {
|
|
3720
|
+
if (!collapsedRef.current) {
|
|
3721
|
+
autoRef.current = true;
|
|
3722
|
+
setCollapsed(true);
|
|
3723
|
+
}
|
|
3724
|
+
} else if (autoRef.current) {
|
|
3725
|
+
autoRef.current = false;
|
|
3726
|
+
setCollapsed(false);
|
|
3727
|
+
}
|
|
3728
|
+
}, [squeezed]);
|
|
3729
|
+
const seen = React12.useRef(null);
|
|
3730
|
+
React12.useEffect(() => {
|
|
3731
|
+
if (autoCollapseKey === void 0) return;
|
|
3732
|
+
if (seen.current === null) {
|
|
3733
|
+
seen.current = autoCollapseKey;
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
if (seen.current === autoCollapseKey) return;
|
|
3737
|
+
seen.current = autoCollapseKey;
|
|
3738
|
+
if (collapsed || pinned) return;
|
|
3739
|
+
const t = setTimeout(() => {
|
|
3740
|
+
if (!hoveringRef.current) setCollapsed(true);
|
|
3741
|
+
}, autoCollapseMs);
|
|
3742
|
+
return () => clearTimeout(t);
|
|
3743
|
+
}, [autoCollapseKey, collapsed, pinned, autoCollapseMs]);
|
|
3744
|
+
const scrollRef = React12.useRef(null);
|
|
3745
|
+
const [hasMore, setHasMore] = React12.useState(false);
|
|
3746
|
+
const onScroll = React12.useCallback(() => {
|
|
3747
|
+
const el = scrollRef.current;
|
|
3748
|
+
if (!el) return;
|
|
3749
|
+
setHasMore(el.scrollHeight - el.scrollTop - el.clientHeight > 4);
|
|
3750
|
+
}, []);
|
|
3751
|
+
React12.useEffect(() => {
|
|
3752
|
+
onScroll();
|
|
3753
|
+
const el = scrollRef.current;
|
|
3754
|
+
if (!el) return;
|
|
3755
|
+
const ro = new ResizeObserver(onScroll);
|
|
3756
|
+
ro.observe(el);
|
|
3757
|
+
return () => {
|
|
3758
|
+
ro.disconnect();
|
|
3759
|
+
};
|
|
3760
|
+
}, [onScroll, open, children]);
|
|
3761
|
+
const boxRef = React12.useRef(null);
|
|
3762
|
+
const panelRef = React12.useRef(null);
|
|
3763
|
+
const [seamed, setSeamed] = React12.useState(false);
|
|
3764
|
+
const armedRef = React12.useRef(false);
|
|
3765
|
+
const publish = React12.useCallback(() => {
|
|
3766
|
+
if (!seamTop) return;
|
|
3767
|
+
const el = panelRef.current;
|
|
3768
|
+
const card = el?.closest(".fz-page-surface");
|
|
3769
|
+
const band = card?.firstElementChild;
|
|
3770
|
+
if (!el || !card || !band) return;
|
|
3771
|
+
const root = document.documentElement;
|
|
3772
|
+
const flush = Math.abs(el.getBoundingClientRect().top - band.getBoundingClientRect().bottom) <= 2;
|
|
3773
|
+
setSeamed(flush);
|
|
3774
|
+
if (!flush) {
|
|
3775
|
+
root.style.removeProperty("--page-rail-seam");
|
|
3776
|
+
return;
|
|
3777
|
+
}
|
|
3778
|
+
const x = el.getBoundingClientRect().right - card.getBoundingClientRect().left;
|
|
3779
|
+
if (!armedRef.current) root.style.transition = "none";
|
|
3780
|
+
root.style.setProperty("--page-rail-seam", `${x + seamTop}px`);
|
|
3781
|
+
if (!armedRef.current) {
|
|
3782
|
+
armedRef.current = true;
|
|
3783
|
+
requestAnimationFrame(() => {
|
|
3784
|
+
root.style.transition = "--page-rail-seam 200ms";
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
}, [seamTop]);
|
|
3788
|
+
React12.useEffect(() => {
|
|
3789
|
+
publish();
|
|
3790
|
+
}, [publish, width]);
|
|
3791
|
+
React12.useEffect(() => {
|
|
3792
|
+
if (!seamTop) return;
|
|
3793
|
+
const el = panelRef.current;
|
|
3794
|
+
const card = el?.closest(".fz-page-surface");
|
|
3795
|
+
if (!el || !card) return;
|
|
3796
|
+
const root = document.documentElement;
|
|
3797
|
+
const ro = new ResizeObserver(publish);
|
|
3798
|
+
ro.observe(el);
|
|
3799
|
+
ro.observe(card);
|
|
3800
|
+
return () => {
|
|
3801
|
+
ro.disconnect();
|
|
3802
|
+
armedRef.current = false;
|
|
3803
|
+
root.style.transition = "none";
|
|
3804
|
+
root.style.removeProperty("--page-rail-seam");
|
|
3805
|
+
requestAnimationFrame(() => {
|
|
3806
|
+
root.style.removeProperty("transition");
|
|
3807
|
+
});
|
|
3808
|
+
};
|
|
3809
|
+
}, [publish, seamTop]);
|
|
3810
|
+
return (
|
|
3811
|
+
// A caixa RESERVA a largura; a coluna mora dentro dela, posicionada. Sem
|
|
3812
|
+
// isso, reabrir no hover empurraria o conteúdo a cada passada do ponteiro.
|
|
3813
|
+
/* @__PURE__ */ jsxs(
|
|
3814
|
+
"div",
|
|
3815
|
+
{
|
|
3816
|
+
ref: boxRef,
|
|
3817
|
+
className: cn("relative hidden shrink-0 no-print transition-[width] duration-200 md:block", className),
|
|
3818
|
+
style: { width: collapsed ? COLUMN_COLLAPSED_WIDTH : COLUMN_WIDTH },
|
|
3819
|
+
children: [
|
|
3820
|
+
/* @__PURE__ */ jsxs(
|
|
3821
|
+
"nav",
|
|
3822
|
+
{
|
|
3823
|
+
ref: panelRef,
|
|
3824
|
+
"aria-label": ariaLabel,
|
|
3825
|
+
onMouseEnter: () => setHover(true),
|
|
3826
|
+
onMouseLeave: () => setHover(false),
|
|
3827
|
+
onDoubleClick: () => {
|
|
3828
|
+
if (collapsed) setOpenState(false);
|
|
3829
|
+
},
|
|
3830
|
+
style: { width },
|
|
3831
|
+
className: cn(
|
|
3832
|
+
// O vidro é uma classe compartilhada com a faixa do cabeçalho.
|
|
3833
|
+
"fz-liquid-glass absolute inset-y-0 left-0 flex flex-col overflow-hidden p-3 transition-[width] duration-200",
|
|
3834
|
+
collapsed && hovering && "z-30 shadow-xl"
|
|
3835
|
+
),
|
|
3836
|
+
children: [
|
|
3837
|
+
/* @__PURE__ */ jsx(
|
|
3838
|
+
"span",
|
|
3839
|
+
{
|
|
3840
|
+
"aria-hidden": true,
|
|
3841
|
+
className: "pointer-events-none absolute right-0 w-px",
|
|
3842
|
+
style: { top: seamTop, bottom: 0, background: "hsl(var(--border))" }
|
|
3843
|
+
}
|
|
3844
|
+
),
|
|
3845
|
+
/* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1", children: [
|
|
3846
|
+
/* @__PURE__ */ jsx("div", { ref: scrollRef, onScroll, className: "scrollbar-none h-full overflow-y-auto overflow-x-hidden", children: children({ collapsed: !open }) }),
|
|
3847
|
+
/* @__PURE__ */ jsx(
|
|
3848
|
+
"div",
|
|
3849
|
+
{
|
|
3850
|
+
"aria-hidden": true,
|
|
3851
|
+
className: cn(
|
|
3852
|
+
"pointer-events-none absolute inset-x-0 bottom-0 h-8 transition-opacity duration-200",
|
|
3853
|
+
hasMore ? "opacity-100" : "opacity-0"
|
|
3854
|
+
),
|
|
3855
|
+
style: { backgroundImage: "linear-gradient(to top, var(--page-surface, hsl(var(--background))), transparent)" }
|
|
3856
|
+
}
|
|
3857
|
+
)
|
|
3858
|
+
] }),
|
|
3859
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex shrink-0 items-center gap-2 border-t border-border pt-2", children: [
|
|
3860
|
+
open && footer && /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: footer }),
|
|
3861
|
+
/* @__PURE__ */ jsx(
|
|
3862
|
+
"button",
|
|
3863
|
+
{
|
|
3864
|
+
type: "button",
|
|
3865
|
+
onClick: () => setOpenState(!collapsed),
|
|
3866
|
+
"aria-label": collapsed ? "Expandir menu" : "Recolher menu",
|
|
3867
|
+
title: collapsed ? "Expandir menu" : "Recolher menu",
|
|
3868
|
+
"aria-expanded": !collapsed,
|
|
3869
|
+
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",
|
|
3870
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronsRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronsLeft, { className: "h-4 w-4" })
|
|
3871
|
+
}
|
|
3872
|
+
)
|
|
3873
|
+
] })
|
|
3874
|
+
]
|
|
3875
|
+
}
|
|
3876
|
+
),
|
|
3877
|
+
seamed && /* @__PURE__ */ jsx(
|
|
3878
|
+
"svg",
|
|
3879
|
+
{
|
|
3880
|
+
"aria-hidden": true,
|
|
3881
|
+
className: "pointer-events-none absolute top-0",
|
|
3882
|
+
style: { left: `${width - 1}px`, marginTop: "-1px", zIndex: 25, transition: "left 200ms" },
|
|
3883
|
+
width: seamTop,
|
|
3884
|
+
height: seamTop,
|
|
3885
|
+
viewBox: `0 0 ${seamTop} ${seamTop}`,
|
|
3886
|
+
fill: "none",
|
|
3887
|
+
children: /* @__PURE__ */ jsx(
|
|
3888
|
+
"path",
|
|
3889
|
+
{
|
|
3890
|
+
d: `M ${seamTop} 0.5 Q 0.5 0.5 0.5 ${seamTop}`,
|
|
3891
|
+
stroke: "hsl(var(--border))",
|
|
3892
|
+
strokeWidth: "1",
|
|
3893
|
+
fill: "none"
|
|
3894
|
+
}
|
|
3895
|
+
)
|
|
3896
|
+
}
|
|
3897
|
+
)
|
|
3898
|
+
]
|
|
3899
|
+
}
|
|
3900
|
+
)
|
|
3901
|
+
);
|
|
3902
|
+
}
|
|
3499
3903
|
function PageRail({ children }) {
|
|
3500
3904
|
const slot = usePageRailSlot();
|
|
3501
3905
|
if (slot) return createPortal(children, slot);
|
|
@@ -3514,7 +3918,7 @@ function viewBarSubscribe(l) {
|
|
|
3514
3918
|
};
|
|
3515
3919
|
}
|
|
3516
3920
|
function ViewBarHost() {
|
|
3517
|
-
const active =
|
|
3921
|
+
const active = React12.useSyncExternalStore(viewBarSubscribe, () => viewBarCount > 0);
|
|
3518
3922
|
return /* @__PURE__ */ jsx(
|
|
3519
3923
|
"div",
|
|
3520
3924
|
{
|
|
@@ -3527,8 +3931,8 @@ function ViewBarHost() {
|
|
|
3527
3931
|
);
|
|
3528
3932
|
}
|
|
3529
3933
|
function PageViewBar({ children }) {
|
|
3530
|
-
const slot =
|
|
3531
|
-
|
|
3934
|
+
const slot = React12.useSyncExternalStore(viewBarSubscribe, () => viewBarSlot);
|
|
3935
|
+
React12.useEffect(() => {
|
|
3532
3936
|
viewBarCount++;
|
|
3533
3937
|
viewBarNotify();
|
|
3534
3938
|
return () => {
|
|
@@ -3539,6 +3943,159 @@ function PageViewBar({ children }) {
|
|
|
3539
3943
|
if (slot) return createPortal(children, slot);
|
|
3540
3944
|
return /* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-end gap-2", children });
|
|
3541
3945
|
}
|
|
3946
|
+
var SUB_NAV_STYLE = "nested";
|
|
3947
|
+
function RailSections({ sections, search, collapsed }) {
|
|
3948
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3949
|
+
search && !collapsed && /* @__PURE__ */ jsxs("div", { className: "relative mb-2", children: [
|
|
3950
|
+
/* @__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" }),
|
|
3951
|
+
/* @__PURE__ */ jsx(
|
|
3952
|
+
"input",
|
|
3953
|
+
{
|
|
3954
|
+
type: "search",
|
|
3955
|
+
value: search.value,
|
|
3956
|
+
onChange: (e) => search.onChange(e.target.value),
|
|
3957
|
+
placeholder: search.placeholder,
|
|
3958
|
+
"aria-label": search.placeholder,
|
|
3959
|
+
className: "h-8 w-full border-0 bg-transparent pl-7 pr-2 text-[13px] outline-none placeholder:text-muted-foreground focus:ring-0"
|
|
3960
|
+
}
|
|
3961
|
+
)
|
|
3962
|
+
] }),
|
|
3963
|
+
sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: i > 0 ? "mt-3 border-t border-border pt-3" : void 0, children: [
|
|
3964
|
+
section.heading && !collapsed && /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: section.heading }),
|
|
3965
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(RailNavItem, { item, collapsed }, item.id)) })
|
|
3966
|
+
] }, section.key ?? i))
|
|
3967
|
+
] });
|
|
3968
|
+
}
|
|
3969
|
+
var RAIL_COLLAPSED_KEY = "fayz.subnav.collapsed";
|
|
3970
|
+
function RailColumn({ className, "aria-label": ariaLabel, sections, search, footer }) {
|
|
3971
|
+
const boxRef = React12.useRef(null);
|
|
3972
|
+
const [squeezed, setSqueezed] = React12.useState(void 0);
|
|
3973
|
+
React12.useEffect(() => {
|
|
3974
|
+
if (typeof window === "undefined") return;
|
|
3975
|
+
const row = boxRef.current?.parentElement?.parentElement;
|
|
3976
|
+
if (!row) return;
|
|
3977
|
+
const COLLAPSE_BELOW = 560;
|
|
3978
|
+
const RESTORE_ABOVE = 820;
|
|
3979
|
+
let timer;
|
|
3980
|
+
const decide = () => {
|
|
3981
|
+
const content = row.clientWidth - COLUMN_WIDTH;
|
|
3982
|
+
if (content < COLLAPSE_BELOW) setSqueezed(true);
|
|
3983
|
+
else if (content > RESTORE_ABOVE) setSqueezed(false);
|
|
3984
|
+
};
|
|
3985
|
+
const apply = () => {
|
|
3986
|
+
if (timer) clearTimeout(timer);
|
|
3987
|
+
timer = setTimeout(decide, 180);
|
|
3988
|
+
};
|
|
3989
|
+
apply();
|
|
3990
|
+
const ro = new ResizeObserver(apply);
|
|
3991
|
+
ro.observe(row);
|
|
3992
|
+
window.addEventListener("resize", apply);
|
|
3993
|
+
return () => {
|
|
3994
|
+
if (timer) clearTimeout(timer);
|
|
3995
|
+
ro.disconnect();
|
|
3996
|
+
window.removeEventListener("resize", apply);
|
|
3997
|
+
};
|
|
3998
|
+
}, []);
|
|
3999
|
+
const activeKey = sections.flatMap((sec) => sec.items).filter((i) => i.active).map((i) => i.id).join("|");
|
|
4000
|
+
return /* @__PURE__ */ jsx("div", { ref: boxRef, className: "contents", children: /* @__PURE__ */ jsx(
|
|
4001
|
+
CollapsibleColumn,
|
|
4002
|
+
{
|
|
4003
|
+
"aria-label": ariaLabel,
|
|
4004
|
+
storageKey: RAIL_COLLAPSED_KEY,
|
|
4005
|
+
className,
|
|
4006
|
+
footer,
|
|
4007
|
+
squeezed,
|
|
4008
|
+
autoCollapseKey: activeKey,
|
|
4009
|
+
children: ({ collapsed }) => /* @__PURE__ */ jsx(RailSections, { sections, search, collapsed })
|
|
4010
|
+
}
|
|
4011
|
+
) });
|
|
4012
|
+
}
|
|
4013
|
+
var published = [];
|
|
4014
|
+
var subNavHosts = 0;
|
|
4015
|
+
var subNavListeners = /* @__PURE__ */ new Set();
|
|
4016
|
+
var subNavNotify = () => subNavListeners.forEach((l) => l());
|
|
4017
|
+
var subNavSubscribe = (l) => {
|
|
4018
|
+
subNavListeners.add(l);
|
|
4019
|
+
return () => {
|
|
4020
|
+
subNavListeners.delete(l);
|
|
4021
|
+
};
|
|
4022
|
+
};
|
|
4023
|
+
function publishSubNav(entry) {
|
|
4024
|
+
const i = published.findIndex((p) => p.id === entry.id);
|
|
4025
|
+
published = i < 0 ? [...published, entry] : published.map((p, n) => n === i ? entry : p);
|
|
4026
|
+
subNavNotify();
|
|
4027
|
+
}
|
|
4028
|
+
function unpublishSubNav(id) {
|
|
4029
|
+
published = published.filter((p) => p.id !== id);
|
|
4030
|
+
subNavNotify();
|
|
4031
|
+
}
|
|
4032
|
+
function useSubNavPublished() {
|
|
4033
|
+
return React12.useSyncExternalStore(subNavSubscribe, () => published, () => published);
|
|
4034
|
+
}
|
|
4035
|
+
function useSubNavHost() {
|
|
4036
|
+
React12.useEffect(() => {
|
|
4037
|
+
subNavHosts++;
|
|
4038
|
+
subNavNotify();
|
|
4039
|
+
return () => {
|
|
4040
|
+
subNavHosts--;
|
|
4041
|
+
subNavNotify();
|
|
4042
|
+
};
|
|
4043
|
+
}, []);
|
|
4044
|
+
}
|
|
4045
|
+
function useHasSubNavHost() {
|
|
4046
|
+
return React12.useSyncExternalStore(subNavSubscribe, () => subNavHosts > 0, () => false);
|
|
4047
|
+
}
|
|
4048
|
+
function SubNavBand({ sections, "aria-label": ariaLabel, className }) {
|
|
4049
|
+
const items = sections.flatMap((s) => s.items);
|
|
4050
|
+
const value = items.find((i) => i.active)?.id ?? items[0]?.id;
|
|
4051
|
+
if (!value) return null;
|
|
4052
|
+
return /* @__PURE__ */ jsx(
|
|
4053
|
+
ViewTabs,
|
|
4054
|
+
{
|
|
4055
|
+
className,
|
|
4056
|
+
"aria-label": ariaLabel,
|
|
4057
|
+
options: items.map((i) => ({ value: i.id, label: i.label })),
|
|
4058
|
+
value,
|
|
4059
|
+
onChange: (id) => items.find((i) => i.id === id)?.onClick?.()
|
|
4060
|
+
}
|
|
4061
|
+
);
|
|
4062
|
+
}
|
|
4063
|
+
function SubNavBandHost({ leading, label }) {
|
|
4064
|
+
useSubNavHost();
|
|
4065
|
+
const pubs = useSubNavPublished();
|
|
4066
|
+
const sections = leading ?? pubs.flatMap((p) => p.sections);
|
|
4067
|
+
if (sections.length === 0) return null;
|
|
4068
|
+
return /* @__PURE__ */ jsx(
|
|
4069
|
+
"div",
|
|
4070
|
+
{
|
|
4071
|
+
style: { marginTop: "0.5rem" },
|
|
4072
|
+
className: "flex min-w-0 items-center gap-3",
|
|
4073
|
+
children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": leading ? label : pubs[0]?.label })
|
|
4074
|
+
}
|
|
4075
|
+
);
|
|
4076
|
+
}
|
|
4077
|
+
function PageSubNav({ items, sections, search, footer, style, "aria-label": ariaLabel }) {
|
|
4078
|
+
const id = React12.useId();
|
|
4079
|
+
const hasHost = useHasSubNavHost();
|
|
4080
|
+
const resolved = sections ?? (items ? [{ items }] : []);
|
|
4081
|
+
const ref = React12.useRef(resolved);
|
|
4082
|
+
ref.current = resolved;
|
|
4083
|
+
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])]));
|
|
4084
|
+
React12.useEffect(() => {
|
|
4085
|
+
publishSubNav({ id, label: ariaLabel, sections: ref.current });
|
|
4086
|
+
return () => unpublishSubNav(id);
|
|
4087
|
+
}, [id, ariaLabel, signature]);
|
|
4088
|
+
if (resolved.every((s) => s.items.length === 0)) return null;
|
|
4089
|
+
if (hasHost) return null;
|
|
4090
|
+
const asRail = (style ?? SUB_NAV_STYLE) === "nested";
|
|
4091
|
+
if (!asRail) {
|
|
4092
|
+
return /* @__PURE__ */ jsx("div", { className: "mb-4 flex min-w-0 items-center gap-3", children: /* @__PURE__ */ jsx(SubNavBand, { sections: resolved, "aria-label": ariaLabel }) });
|
|
4093
|
+
}
|
|
4094
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4095
|
+
/* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(RailColumn, { sections: resolved, search, footer, "aria-label": ariaLabel }) }),
|
|
4096
|
+
/* @__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 }) })
|
|
4097
|
+
] });
|
|
4098
|
+
}
|
|
3542
4099
|
function PageHeaderActions({ children }) {
|
|
3543
4100
|
const outlet = usePageActionsOutletSlot();
|
|
3544
4101
|
const shellSlot = useModuleHeaderActionsSlot();
|
|
@@ -3552,15 +4109,18 @@ function PremiumBadge({ className }) {
|
|
|
3552
4109
|
const tip = t("upgrade.badgeTooltip");
|
|
3553
4110
|
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 }) });
|
|
3554
4111
|
}
|
|
3555
|
-
var ModuleLayoutContext =
|
|
4112
|
+
var ModuleLayoutContext = React12.createContext("rail");
|
|
3556
4113
|
function ModuleLayoutProvider({ variant, children }) {
|
|
3557
4114
|
return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
|
|
3558
4115
|
}
|
|
3559
4116
|
function useModuleLayout() {
|
|
3560
|
-
return
|
|
4117
|
+
return React12.useContext(ModuleLayoutContext);
|
|
3561
4118
|
}
|
|
3562
|
-
function RailNavItem({ item }) {
|
|
3563
|
-
const [expanded, setExpanded] =
|
|
4119
|
+
function RailNavItem({ item, collapsed }) {
|
|
4120
|
+
const [expanded, setExpanded] = React12.useState(false);
|
|
4121
|
+
React12.useEffect(() => {
|
|
4122
|
+
if (collapsed) setExpanded(false);
|
|
4123
|
+
}, [collapsed]);
|
|
3564
4124
|
const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
|
|
3565
4125
|
const hasChildren = item.children && item.children.length > 0;
|
|
3566
4126
|
const hasActiveChild = hasChildren && item.children.some((c) => c.active);
|
|
@@ -3571,36 +4131,53 @@ function RailNavItem({ item }) {
|
|
|
3571
4131
|
{
|
|
3572
4132
|
type: "button",
|
|
3573
4133
|
"data-tour": `modnav.${item.id}`,
|
|
3574
|
-
onClick: () => hasChildren ? setExpanded(!expanded) : item.onClick?.(),
|
|
4134
|
+
onClick: () => hasChildren && !collapsed ? setExpanded(!expanded) : item.onClick?.(),
|
|
4135
|
+
title: collapsed ? item.label : void 0,
|
|
3575
4136
|
className: cn(
|
|
3576
|
-
|
|
4137
|
+
// `px-2.5` NOS DOIS estados: centralizado, o ícone da tira ficava 2px
|
|
4138
|
+
// à direita do mesmo ícone com a coluna aberta, e todos eles davam um
|
|
4139
|
+
// pulinho lateral quando o ponteiro chegava. O recuo é o mesmo; o que
|
|
4140
|
+
// muda é só o rótulo aparecer.
|
|
4141
|
+
// ALTURA FIXA. Com `py-1.5` a linha media o que tinha dentro: 32px com
|
|
4142
|
+
// rótulo (a entrelinha do texto) e 28px só com o ícone — então cada
|
|
4143
|
+
// linha da tira caía num y diferente do da coluna aberta, e a lista
|
|
4144
|
+
// inteira escorregava quando o ponteiro chegava. `h-8` nos dois.
|
|
4145
|
+
"flex h-8 w-full items-center gap-2 rounded-md px-2.5 text-sm transition-colors",
|
|
3577
4146
|
isActive ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
3578
4147
|
),
|
|
3579
4148
|
children: [
|
|
3580
4149
|
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
3581
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left
|
|
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" }))
|
|
4150
|
+
!collapsed && /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: item.label }),
|
|
4151
|
+
!collapsed && item.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" }),
|
|
4152
|
+
!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
4153
|
]
|
|
3585
4154
|
}
|
|
3586
4155
|
),
|
|
3587
|
-
hasChildren && expanded && /* @__PURE__ */ jsx("div", { className: "
|
|
3588
|
-
|
|
3589
|
-
{
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
4156
|
+
hasChildren && expanded && !collapsed && /* @__PURE__ */ jsx("div", { className: "relative mt-0.5 text-muted-foreground/45", children: item.children.map((child, i) => {
|
|
4157
|
+
const activeIndex = item.children.findIndex((c) => c.active);
|
|
4158
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative h-8", children: [
|
|
4159
|
+
/* @__PURE__ */ jsx(NavChildConnector, { onPath: activeIndex >= 0 && i < activeIndex, active: !!child.active }),
|
|
4160
|
+
/* @__PURE__ */ jsxs(
|
|
4161
|
+
"button",
|
|
4162
|
+
{
|
|
4163
|
+
type: "button",
|
|
4164
|
+
"data-tour": `modnav.${child.id}`,
|
|
4165
|
+
onClick: child.onClick,
|
|
4166
|
+
className: cn(
|
|
4167
|
+
// `pl-11` passa da ponta da seta (~24px) com folga, para as
|
|
4168
|
+
// filhas lerem como UMA coluna indentada em vez de apertarem
|
|
4169
|
+
// a linha que aponta para elas.
|
|
4170
|
+
"flex h-8 w-full items-center rounded-button pl-11 pr-1 text-sm transition-colors",
|
|
4171
|
+
child.active ? "font-medium text-primary" : "text-muted-foreground hover:text-foreground"
|
|
4172
|
+
),
|
|
4173
|
+
children: [
|
|
4174
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-left", children: child.label }),
|
|
4175
|
+
child.premium && /* @__PURE__ */ jsx(PremiumBadge, { className: "ml-1" })
|
|
4176
|
+
]
|
|
4177
|
+
}
|
|
4178
|
+
)
|
|
4179
|
+
] }, child.id);
|
|
4180
|
+
}) })
|
|
3604
4181
|
] });
|
|
3605
4182
|
}
|
|
3606
4183
|
function defaultChildOf(item) {
|
|
@@ -3608,9 +4185,9 @@ function defaultChildOf(item) {
|
|
|
3608
4185
|
return kids.find((c) => c.defaultChild) ?? kids.find((c) => /(^|-)list$/i.test(c.id)) ?? kids.find((c) => !/(^|-)(new|novo|nova|create)$/i.test(c.id)) ?? kids[0];
|
|
3609
4186
|
}
|
|
3610
4187
|
function MobileTabs({ nav }) {
|
|
3611
|
-
const scrollRef =
|
|
3612
|
-
const [expandedId, setExpandedId] =
|
|
3613
|
-
|
|
4188
|
+
const scrollRef = React12.useRef(null);
|
|
4189
|
+
const [expandedId, setExpandedId] = React12.useState(null);
|
|
4190
|
+
React12.useEffect(() => {
|
|
3614
4191
|
const container = scrollRef.current;
|
|
3615
4192
|
if (!container) return;
|
|
3616
4193
|
const activeEl = container.querySelector('[data-active="true"]');
|
|
@@ -3683,12 +4260,12 @@ function MobileTabs({ nav }) {
|
|
|
3683
4260
|
})()
|
|
3684
4261
|
] });
|
|
3685
4262
|
}
|
|
3686
|
-
var BackStyleContext =
|
|
4263
|
+
var BackStyleContext = React12.createContext("link");
|
|
3687
4264
|
function BackStyleProvider({ style, children }) {
|
|
3688
4265
|
return /* @__PURE__ */ jsx(BackStyleContext.Provider, { value: style, children });
|
|
3689
4266
|
}
|
|
3690
4267
|
function useBackStyle() {
|
|
3691
|
-
return
|
|
4268
|
+
return React12.useContext(BackStyleContext);
|
|
3692
4269
|
}
|
|
3693
4270
|
function SubpageHeader({ title, subtitle, description, icon, onBack, parentLabel, actions, backStyle, inline }) {
|
|
3694
4271
|
const t = useTranslation();
|
|
@@ -3796,11 +4373,18 @@ function ShellSubpageHeader({
|
|
|
3796
4373
|
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "no-print flex shrink-0 items-center gap-2", children: actions }) })
|
|
3797
4374
|
] });
|
|
3798
4375
|
}
|
|
4376
|
+
function ModuleSubBand({ nav }) {
|
|
4377
|
+
useSubNavHost();
|
|
4378
|
+
const pubs = useSubNavPublished();
|
|
4379
|
+
const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
|
|
4380
|
+
const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
|
|
4381
|
+
kids.find((c) => c.active)?.id ?? kids[0]?.id;
|
|
4382
|
+
const own = [];
|
|
4383
|
+
const sections = own.length ? own : pubs.flatMap((p) => p.sections);
|
|
4384
|
+
if (sections.every((sec) => sec.items.length === 0)) return null;
|
|
4385
|
+
return /* @__PURE__ */ jsx(PageBand, { actions: /* @__PURE__ */ jsx(ViewBarHost, {}), children: /* @__PURE__ */ jsx(SubNavBand, { sections, "aria-label": own.length ? activeItem?.label : pubs[0]?.label }) });
|
|
4386
|
+
}
|
|
3799
4387
|
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
4388
|
const activeItem = nav.find((item) => item.active || item.children?.some((c) => c.active));
|
|
3805
4389
|
const tabs = nav.map((item) => ({
|
|
3806
4390
|
value: item.id,
|
|
@@ -3814,23 +4398,12 @@ function ModuleHeader({ nav }) {
|
|
|
3814
4398
|
const item = nav.find((n) => n.id === id);
|
|
3815
4399
|
if (!item) return;
|
|
3816
4400
|
const hasChildren = item.children && item.children.length > 0;
|
|
3817
|
-
if (hasChildren)
|
|
4401
|
+
if (hasChildren) defaultChildOf(item)?.onClick?.();
|
|
3818
4402
|
else item.onClick?.();
|
|
3819
4403
|
};
|
|
3820
4404
|
const kids = (activeItem?.children ?? []).filter((c) => c.kind !== "action");
|
|
3821
4405
|
const activeKid = kids.find((c) => c.active)?.id ?? kids[0]?.id;
|
|
3822
|
-
const
|
|
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;
|
|
4406
|
+
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
4407
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3835
4408
|
/* @__PURE__ */ jsx(
|
|
3836
4409
|
PageTabs,
|
|
@@ -3842,14 +4415,14 @@ function ModuleHeader({ nav }) {
|
|
|
3842
4415
|
actions: /* @__PURE__ */ jsx(ViewBarHost, {})
|
|
3843
4416
|
}
|
|
3844
4417
|
),
|
|
3845
|
-
|
|
4418
|
+
/* @__PURE__ */ jsx(SubNavBandHost, { leading: childNav, label: activeItem?.label })
|
|
3846
4419
|
] });
|
|
3847
4420
|
}
|
|
3848
4421
|
function ModulePage({ title: _title, subtitle, nav, children, className, headerAction, showHeader = true, sidebarFooter, navVariant, viewKey, direction, navFilterPlaceholder }) {
|
|
3849
4422
|
const ctxVariant = useModuleLayout();
|
|
3850
4423
|
const variant = navVariant ?? ctxVariant;
|
|
3851
|
-
const [navQuery, setNavQuery] =
|
|
3852
|
-
const filteredNav =
|
|
4424
|
+
const [navQuery, setNavQuery] = React12.useState("");
|
|
4425
|
+
const filteredNav = React12.useMemo(() => {
|
|
3853
4426
|
const q = navQuery.trim().toLowerCase();
|
|
3854
4427
|
if (!q) return nav;
|
|
3855
4428
|
const hit = (label) => label.toLowerCase().includes(q);
|
|
@@ -3861,6 +4434,16 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
|
|
|
3861
4434
|
}, [nav, navQuery]);
|
|
3862
4435
|
const transitionKey = viewKey ?? "view";
|
|
3863
4436
|
const onSubpage = useHasPageHeaderBack();
|
|
4437
|
+
const activeLabel = React12.useMemo(() => {
|
|
4438
|
+
if (onSubpage) return null;
|
|
4439
|
+
for (const item of nav) {
|
|
4440
|
+
const kid = item.children?.find((c) => c.active);
|
|
4441
|
+
if (kid) return kid.label === item.label ? item.label : `${item.label} \u203A ${kid.label}`;
|
|
4442
|
+
if (item.active) return item.label;
|
|
4443
|
+
}
|
|
4444
|
+
return null;
|
|
4445
|
+
}, [nav, onSubpage]);
|
|
4446
|
+
usePublishModuleViewLabel(activeLabel);
|
|
3864
4447
|
if (variant === "sidebar") {
|
|
3865
4448
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3866
4449
|
showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
|
|
@@ -3875,32 +4458,23 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
|
|
|
3875
4458
|
] });
|
|
3876
4459
|
}
|
|
3877
4460
|
return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0", className), children: [
|
|
3878
|
-
/* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
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
|
-
] }) }),
|
|
4461
|
+
/* @__PURE__ */ jsx(PageRail, { children: /* @__PURE__ */ jsx(
|
|
4462
|
+
RailColumn,
|
|
4463
|
+
{
|
|
4464
|
+
sections: [{ items: filteredNav }],
|
|
4465
|
+
search: navFilterPlaceholder ? { value: navQuery, onChange: setNavQuery, placeholder: navFilterPlaceholder } : void 0,
|
|
4466
|
+
footer: sidebarFooter
|
|
4467
|
+
}
|
|
4468
|
+
) }),
|
|
3896
4469
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
3897
4470
|
showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
|
|
3898
4471
|
!onSubpage && /* @__PURE__ */ jsx(MobileTabs, { nav }),
|
|
4472
|
+
!onSubpage && /* @__PURE__ */ jsx(ModuleSubBand, { nav }),
|
|
3899
4473
|
/* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
|
|
3900
4474
|
] })
|
|
3901
4475
|
] });
|
|
3902
4476
|
}
|
|
3903
4477
|
|
|
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-
|
|
3906
|
-
//# sourceMappingURL=chunk-
|
|
4478
|
+
export { AppShell, BackStyleProvider, BottomSheet, COLUMN_WIDTH, CollapsibleColumn, HeaderTabs, Hint, Modal, ModalBody, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, 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, useModalHost, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useModuleViewLabel, useNavTransition, usePageHeader, usePageHeaderClaimed, usePageHeaderHost, usePageTrail, usePageTrailParent, usePublishModuleViewLabel, useRailRow, useRegisterPageActions, useSaveBar, useSaveBarVisible, useSheetClose, useSheetDrag, useTrailBack };
|
|
4479
|
+
//# sourceMappingURL=chunk-63BB2CNP.js.map
|
|
4480
|
+
//# sourceMappingURL=chunk-63BB2CNP.js.map
|