@fayz-ai/ui 0.15.0 → 0.17.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/analytics/context.d.ts +15 -1
- package/dist/analytics/context.d.ts.map +1 -1
- package/dist/analytics/index.d.ts +1 -1
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/{chunk-J7F3Z52K.js → chunk-DFOAKWYB.js} +4 -4
- package/dist/chunk-DFOAKWYB.js.map +1 -0
- package/dist/{chunk-KD2V3TAX.js → chunk-E44WOPCR.js} +61 -49
- package/dist/chunk-E44WOPCR.js.map +1 -0
- package/dist/{chunk-FFJ2C5YH.js → chunk-HKGTF2YA.js} +41 -16
- package/dist/chunk-HKGTF2YA.js.map +1 -0
- package/dist/{chunk-NA3GE4H3.js → chunk-OBIU37AX.js} +365 -252
- package/dist/chunk-OBIU37AX.js.map +1 -0
- package/dist/{chunk-SLWTKHNY.js → chunk-Z2ITFPGL.js} +380 -83
- package/dist/chunk-Z2ITFPGL.js.map +1 -0
- package/dist/{chunk-5KMAEQA3.js → chunk-ZLPYNHXH.js} +56 -21
- package/dist/chunk-ZLPYNHXH.js.map +1 -0
- package/dist/dashboard/OnboardingWidget.d.ts +7 -1
- package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
- package/dist/dashboard/SidebarOnboarding.d.ts +7 -1
- package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -3
- package/dist/hooks/useIsWide.d.ts +16 -0
- package/dist/hooks/useIsWide.d.ts.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +278 -10
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +25 -2
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +4 -0
- 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/Topbar.d.ts +5 -1
- package/dist/layout/Topbar.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 +3 -3
- package/dist/primitives/checkbox.d.ts +4 -0
- package/dist/primitives/checkbox.d.ts.map +1 -1
- package/dist/primitives/index.d.ts +3 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +4 -4
- package/dist/primitives/list-view.d.ts +5 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/modal.d.ts.map +1 -1
- package/dist/primitives/page-actions.d.ts +55 -0
- package/dist/primitives/page-actions.d.ts.map +1 -0
- package/dist/primitives/page-header.d.ts +5 -2
- package/dist/primitives/page-header.d.ts.map +1 -1
- package/dist/primitives/page-toolbar.d.ts.map +1 -1
- package/dist/primitives/refresh-button.d.ts.map +1 -1
- package/dist/primitives/row-actions.d.ts +11 -0
- package/dist/primitives/row-actions.d.ts.map +1 -0
- package/dist/primitives/whatsapp-icon.d.ts +7 -0
- package/dist/primitives/whatsapp-icon.d.ts.map +1 -0
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/layout.store.d.ts +1 -0
- package/dist/stores/layout.store.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +39 -5
- package/dist/stores/page-header.store.d.ts.map +1 -1
- package/dist/styles.css +188 -3
- package/dist/tour/TourSpotlight.d.ts +29 -0
- package/dist/tour/TourSpotlight.d.ts.map +1 -0
- package/dist/tour/index.d.ts +4 -0
- package/dist/tour/index.d.ts.map +1 -0
- package/dist/tour/tour.store.d.ts +22 -0
- package/dist/tour/tour.store.d.ts.map +1 -0
- package/dist/tour/types.d.ts +28 -0
- package/dist/tour/types.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-5KMAEQA3.js.map +0 -1
- package/dist/chunk-FFJ2C5YH.js.map +0 -1
- package/dist/chunk-J7F3Z52K.js.map +0 -1
- package/dist/chunk-KD2V3TAX.js.map +0 -1
- package/dist/chunk-NA3GE4H3.js.map +0 -1
- package/dist/chunk-SLWTKHNY.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useHasPageHeaderHost, usePageHeader, useLayoutStore, useRegisterPageActions,
|
|
1
|
+
import { useHasPageHeaderHost, usePageHeader, PageTitlePortal, useLayoutStore, useHasPageHeaderBack, useRegisterPageActions, usePageHeaderClaimed, usePageTitleSlotHost, useHasPageHeaderOutlet, useHasPageActions, usePageHeaderHost } from './chunk-HKGTF2YA.js';
|
|
2
2
|
import { cn } from './chunk-OKZ6WQB3.js';
|
|
3
3
|
import { ICON_MAP } from './chunk-4GK6IHOI.js';
|
|
4
|
-
import * as
|
|
4
|
+
import * as React2 from 'react';
|
|
5
5
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
6
|
-
import { X, Loader2, ArrowLeft, Search, Bell, PanelLeft, PanelLeftClose, Menu, Crown, ChevronDown, ChevronRight, ChevronLeft, ExternalLink, CreditCard, Sparkles, Home, Plus,
|
|
6
|
+
import { X, Loader2, ArrowLeft, Search, Bell, PanelLeft, PanelLeftClose, Menu, Crown, ChevronDown, ChevronRight, ChevronLeft, ExternalLink, CreditCard, Sparkles, Home, Plus, UserCog, Settings, LogOut } from 'lucide-react';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import { useTranslation, useNavReferrer, routeModule, navHistoryBack } from '@fayz-ai/core';
|
|
9
9
|
import * as Popover from '@radix-ui/react-popover';
|
|
@@ -29,19 +29,19 @@ var Sheet = DialogPrimitive.Root;
|
|
|
29
29
|
var SheetTrigger = DialogPrimitive.Trigger;
|
|
30
30
|
var SheetClose = DialogPrimitive.Close;
|
|
31
31
|
var SheetPortal = DialogPrimitive.Portal;
|
|
32
|
-
var SheetOverlay =
|
|
32
|
+
var SheetOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
33
33
|
DialogPrimitive.Overlay,
|
|
34
34
|
{
|
|
35
35
|
ref,
|
|
36
36
|
className: cn(
|
|
37
|
-
"saas-sheet-overlay fixed inset-0 z-
|
|
37
|
+
"saas-sheet-overlay fixed inset-0 z-[100] bg-black/40 backdrop-blur-[2px]",
|
|
38
38
|
className
|
|
39
39
|
),
|
|
40
40
|
...props
|
|
41
41
|
}
|
|
42
42
|
));
|
|
43
43
|
SheetOverlay.displayName = "SheetOverlay";
|
|
44
|
-
var SheetContent =
|
|
44
|
+
var SheetContent = React2.forwardRef(({ className, children, width, hideClose, overlay = "blur", onPointerDownOutside, onInteractOutside, ...props }, ref) => /* @__PURE__ */ jsxs(SheetPortal, { children: [
|
|
45
45
|
/* @__PURE__ */ jsx(SheetOverlay, { className: overlay === "none" ? "bg-transparent backdrop-blur-0" : overlay === "dim" ? "backdrop-blur-0" : void 0 }),
|
|
46
46
|
/* @__PURE__ */ jsxs(
|
|
47
47
|
DialogPrimitive.Content,
|
|
@@ -62,7 +62,7 @@ var SheetContent = React7.forwardRef(({ className, children, width, hideClose, o
|
|
|
62
62
|
onInteractOutside?.(e);
|
|
63
63
|
},
|
|
64
64
|
className: cn(
|
|
65
|
-
"fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-
|
|
65
|
+
"fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-[100] flex flex-col border-l bg-card shadow-2xl outline-none",
|
|
66
66
|
"w-full",
|
|
67
67
|
width ?? "max-w-md",
|
|
68
68
|
className
|
|
@@ -99,7 +99,7 @@ function SheetFooter({ className, ...props }) {
|
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
SheetFooter.displayName = "SheetFooter";
|
|
102
|
-
var SheetTitle =
|
|
102
|
+
var SheetTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
103
103
|
DialogPrimitive.Title,
|
|
104
104
|
{
|
|
105
105
|
ref,
|
|
@@ -108,7 +108,7 @@ var SheetTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
108
108
|
}
|
|
109
109
|
));
|
|
110
110
|
SheetTitle.displayName = "SheetTitle";
|
|
111
|
-
var SheetDescription =
|
|
111
|
+
var SheetDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
112
112
|
DialogPrimitive.Description,
|
|
113
113
|
{
|
|
114
114
|
ref,
|
|
@@ -127,8 +127,8 @@ function SheetBody({ className, ...props }) {
|
|
|
127
127
|
);
|
|
128
128
|
}
|
|
129
129
|
SheetBody.displayName = "SheetBody";
|
|
130
|
-
var SaveBarApiContext =
|
|
131
|
-
var SaveBarStateContext =
|
|
130
|
+
var SaveBarApiContext = React2.createContext(null);
|
|
131
|
+
var SaveBarStateContext = React2.createContext({ visible: false, saving: false });
|
|
132
132
|
var _saveBarVisible = false;
|
|
133
133
|
var _saveBarSubs = /* @__PURE__ */ new Set();
|
|
134
134
|
function setSaveBarVisibleSignal(v) {
|
|
@@ -137,7 +137,7 @@ function setSaveBarVisibleSignal(v) {
|
|
|
137
137
|
_saveBarSubs.forEach((fn) => fn());
|
|
138
138
|
}
|
|
139
139
|
function useSaveBarVisible() {
|
|
140
|
-
return
|
|
140
|
+
return React2.useSyncExternalStore(
|
|
141
141
|
(cb) => {
|
|
142
142
|
_saveBarSubs.add(cb);
|
|
143
143
|
return () => {
|
|
@@ -149,15 +149,15 @@ function useSaveBarVisible() {
|
|
|
149
149
|
);
|
|
150
150
|
}
|
|
151
151
|
function SaveBarProvider({ children }) {
|
|
152
|
-
const [state, setState] =
|
|
153
|
-
const handlers =
|
|
154
|
-
const api =
|
|
155
|
-
const backStack =
|
|
156
|
-
const backApi =
|
|
157
|
-
|
|
152
|
+
const [state, setState] = React2.useState({ visible: false, saving: false });
|
|
153
|
+
const handlers = React2.useRef({});
|
|
154
|
+
const api = React2.useMemo(() => ({ setState, handlers }), []);
|
|
155
|
+
const backStack = React2.useRef([]);
|
|
156
|
+
const backApi = React2.useMemo(() => ({ stack: backStack }), []);
|
|
157
|
+
React2.useEffect(() => {
|
|
158
158
|
setSaveBarVisibleSignal(state.visible);
|
|
159
159
|
}, [state.visible]);
|
|
160
|
-
|
|
160
|
+
React2.useEffect(() => {
|
|
161
161
|
function onKey(e) {
|
|
162
162
|
if (state.visible && !state.saving) {
|
|
163
163
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
@@ -185,7 +185,7 @@ function SaveBarProvider({ children }) {
|
|
|
185
185
|
}, [state.visible, state.saving]);
|
|
186
186
|
return /* @__PURE__ */ jsx(SaveBarApiContext.Provider, { value: api, children: /* @__PURE__ */ jsx(BackNavApiContext.Provider, { value: backApi, children: /* @__PURE__ */ jsx(SaveBarStateContext.Provider, { value: state, children }) }) });
|
|
187
187
|
}
|
|
188
|
-
var BackNavApiContext =
|
|
188
|
+
var BackNavApiContext = React2.createContext(null);
|
|
189
189
|
function isEditableTarget(target) {
|
|
190
190
|
const el = target;
|
|
191
191
|
if (!el || !el.tagName) return false;
|
|
@@ -193,12 +193,12 @@ function isEditableTarget(target) {
|
|
|
193
193
|
return tag === "input" || tag === "textarea" || tag === "select" || el.isContentEditable;
|
|
194
194
|
}
|
|
195
195
|
function useBackHandler(onBack) {
|
|
196
|
-
const api =
|
|
197
|
-
const ref =
|
|
198
|
-
|
|
196
|
+
const api = React2.useContext(BackNavApiContext);
|
|
197
|
+
const ref = React2.useRef(onBack);
|
|
198
|
+
React2.useEffect(() => {
|
|
199
199
|
ref.current = onBack;
|
|
200
200
|
});
|
|
201
|
-
|
|
201
|
+
React2.useEffect(() => {
|
|
202
202
|
if (!api) return;
|
|
203
203
|
const stack = api.stack.current;
|
|
204
204
|
stack.push(ref);
|
|
@@ -209,23 +209,23 @@ function useBackHandler(onBack) {
|
|
|
209
209
|
}, [api]);
|
|
210
210
|
}
|
|
211
211
|
function useSaveBar({ dirty, saving = false, onSave, onDiscard, message, saveLabel, discardLabel }) {
|
|
212
|
-
const api =
|
|
213
|
-
|
|
212
|
+
const api = React2.useContext(SaveBarApiContext);
|
|
213
|
+
React2.useEffect(() => {
|
|
214
214
|
if (api) api.handlers.current = { onSave, onDiscard };
|
|
215
215
|
});
|
|
216
|
-
|
|
216
|
+
React2.useEffect(() => {
|
|
217
217
|
if (!api) return;
|
|
218
218
|
api.setState({ visible: dirty, saving, message, saveLabel, discardLabel });
|
|
219
219
|
return () => api.setState((s) => ({ ...s, visible: false }));
|
|
220
220
|
}, [api, dirty, saving, message, saveLabel, discardLabel]);
|
|
221
221
|
}
|
|
222
222
|
function SaveBar({ className }) {
|
|
223
|
-
const state =
|
|
224
|
-
const api =
|
|
223
|
+
const state = React2.useContext(SaveBarStateContext);
|
|
224
|
+
const api = React2.useContext(SaveBarApiContext);
|
|
225
225
|
const t = useTranslation();
|
|
226
|
-
const [rendered, setRendered] =
|
|
227
|
-
const [closing, setClosing] =
|
|
228
|
-
|
|
226
|
+
const [rendered, setRendered] = React2.useState(state.visible);
|
|
227
|
+
const [closing, setClosing] = React2.useState(false);
|
|
228
|
+
React2.useEffect(() => {
|
|
229
229
|
if (state.visible) {
|
|
230
230
|
setRendered(true);
|
|
231
231
|
setClosing(false);
|
|
@@ -241,40 +241,52 @@ function SaveBar({ className }) {
|
|
|
241
241
|
}, [state.visible, rendered]);
|
|
242
242
|
if (!api || !rendered) return null;
|
|
243
243
|
const { saving, message, saveLabel, discardLabel } = state;
|
|
244
|
-
return /* @__PURE__ */ jsx(
|
|
245
|
-
"
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
/* @__PURE__ */ jsx(
|
|
254
|
-
"button",
|
|
255
|
-
{
|
|
256
|
-
type: "button",
|
|
257
|
-
disabled: saving,
|
|
258
|
-
onClick: () => api.handlers.current.onDiscard?.(),
|
|
259
|
-
className: "rounded-full px-3 py-1.5 text-sm font-medium text-background/70 transition-colors hover:bg-background/10 hover:text-background disabled:opacity-50",
|
|
260
|
-
children: discardLabel ?? t("common.discard")
|
|
261
|
-
}
|
|
244
|
+
return /* @__PURE__ */ jsx(
|
|
245
|
+
"div",
|
|
246
|
+
{
|
|
247
|
+
className: cn(
|
|
248
|
+
// Above the tab bar (z-50), below a full-screen sheet (z-60), and lifted
|
|
249
|
+
// clear of the bar's height so its actions are not sitting under it.
|
|
250
|
+
"pointer-events-none fixed inset-x-0 z-[55] flex justify-center px-4",
|
|
251
|
+
"bottom-[calc(var(--fz-bottom-bar,0px)+1.25rem)]",
|
|
252
|
+
className
|
|
262
253
|
),
|
|
263
|
-
/* @__PURE__ */ jsxs(
|
|
264
|
-
"
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
254
|
+
children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
255
|
+
"pointer-events-auto flex items-center gap-5 rounded-full bg-foreground py-2 pl-5 pr-2 text-background shadow-xl ring-1 ring-black/5 duration-200",
|
|
256
|
+
closing ? "animate-out fade-out slide-out-to-bottom-2" : "animate-in fade-in slide-in-from-bottom-2"
|
|
257
|
+
), children: [
|
|
258
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm font-medium", children: [
|
|
259
|
+
/* @__PURE__ */ jsx("span", { className: "h-2 w-2 shrink-0 rounded-full bg-amber-400" }),
|
|
260
|
+
message ?? t("saveBar.unsaved")
|
|
261
|
+
] }),
|
|
262
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
263
|
+
/* @__PURE__ */ jsx(
|
|
264
|
+
"button",
|
|
265
|
+
{
|
|
266
|
+
type: "button",
|
|
267
|
+
disabled: saving,
|
|
268
|
+
onClick: () => api.handlers.current.onDiscard?.(),
|
|
269
|
+
className: "rounded-full px-3 py-1.5 text-sm font-medium text-background/70 transition-colors hover:bg-background/10 hover:text-background disabled:opacity-50",
|
|
270
|
+
children: discardLabel ?? t("common.discard")
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
/* @__PURE__ */ jsxs(
|
|
274
|
+
"button",
|
|
275
|
+
{
|
|
276
|
+
type: "button",
|
|
277
|
+
disabled: saving,
|
|
278
|
+
onClick: () => api.handlers.current.onSave?.(),
|
|
279
|
+
className: "inline-flex items-center rounded-full bg-background px-4 py-1.5 text-sm font-semibold text-foreground transition-colors hover:bg-background/90 disabled:opacity-60",
|
|
280
|
+
children: [
|
|
281
|
+
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }),
|
|
282
|
+
saveLabel ?? t("common.save")
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
)
|
|
286
|
+
] })
|
|
287
|
+
] })
|
|
288
|
+
}
|
|
289
|
+
);
|
|
278
290
|
}
|
|
279
291
|
function useCrossModuleBack(onBack, parentLabel) {
|
|
280
292
|
const currentPath = typeof window !== "undefined" ? (window.location.hash ? window.location.hash.slice(1) : window.location.pathname) || "/" : "/";
|
|
@@ -289,10 +301,14 @@ function useCrossModuleBack(onBack, parentLabel) {
|
|
|
289
301
|
function PageHeaderCrumb({
|
|
290
302
|
title,
|
|
291
303
|
parentLabel,
|
|
292
|
-
onBack
|
|
304
|
+
onBack,
|
|
305
|
+
headingLevel = "h2"
|
|
293
306
|
}) {
|
|
307
|
+
const Heading = headingLevel;
|
|
308
|
+
const asHeading = typeof title === "string" && title !== "";
|
|
294
309
|
if (!onBack) {
|
|
295
|
-
|
|
310
|
+
if (!title) return null;
|
|
311
|
+
return asHeading ? /* @__PURE__ */ jsx(Heading, { className: "min-w-0 truncate text-lg font-semibold", children: title }) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-lg font-semibold", children: title });
|
|
296
312
|
}
|
|
297
313
|
return /* @__PURE__ */ jsxs("nav", { className: "flex min-w-0 items-center gap-1.5 text-sm text-muted-foreground", children: [
|
|
298
314
|
/* @__PURE__ */ jsxs(
|
|
@@ -313,6 +329,11 @@ function PageHeaderCrumb({
|
|
|
313
329
|
// Title still waiting on data: a pulsing bar, otherwise the line
|
|
314
330
|
// appears from nowhere and shoves the rest when the record lands.
|
|
315
331
|
/* @__PURE__ */ jsx("span", { className: "inline-block h-4 w-24 animate-pulse rounded bg-muted align-middle" })
|
|
332
|
+
) : asHeading ? (
|
|
333
|
+
// A heading, not a span, when it IS the screen's name: a subpage
|
|
334
|
+
// that only ever renders a breadcrumb was leaving the page with no
|
|
335
|
+
// heading for a screen reader to land on.
|
|
336
|
+
/* @__PURE__ */ jsx(Heading, { className: "min-w-0 truncate font-medium text-foreground", children: title })
|
|
316
337
|
) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate font-medium text-foreground", children: title })
|
|
317
338
|
] })
|
|
318
339
|
] });
|
|
@@ -321,7 +342,7 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
|
|
|
321
342
|
const hasHost = useHasPageHeaderHost();
|
|
322
343
|
const { onBack: effectiveOnBack, parentLabel: effectiveParent } = useCrossModuleBack(onBack, parentLabel);
|
|
323
344
|
useBackHandler(effectiveOnBack);
|
|
324
|
-
const node =
|
|
345
|
+
const node = React2.useMemo(() => /* @__PURE__ */ jsx(
|
|
325
346
|
PageHeaderCrumb,
|
|
326
347
|
{
|
|
327
348
|
title,
|
|
@@ -329,21 +350,21 @@ function PageHeader({ title, onBack, parentLabel, backLabel }) {
|
|
|
329
350
|
onBack: effectiveOnBack
|
|
330
351
|
}
|
|
331
352
|
), [effectiveOnBack, effectiveParent, backLabel, title]);
|
|
332
|
-
usePageHeader(hasHost
|
|
333
|
-
if (hasHost) return
|
|
353
|
+
usePageHeader(hasHost, { back: !!effectiveOnBack });
|
|
354
|
+
if (hasHost) return /* @__PURE__ */ jsx(PageTitlePortal, { children: node });
|
|
334
355
|
return /* @__PURE__ */ jsx("div", { className: "mb-4", children: node });
|
|
335
356
|
}
|
|
336
357
|
var GUTTER_PX = 8;
|
|
337
358
|
var CLOSE_DELAY_MS = 140;
|
|
338
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ?
|
|
359
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? React2.useLayoutEffect : React2.useEffect;
|
|
339
360
|
function iconOf(name) {
|
|
340
361
|
if (!name) return null;
|
|
341
362
|
return ICON_MAP[name] ?? null;
|
|
342
363
|
}
|
|
343
|
-
var RailFlyoutContext =
|
|
364
|
+
var RailFlyoutContext = React2.createContext(null);
|
|
344
365
|
var RailFlyoutProvider = RailFlyoutContext.Provider;
|
|
345
366
|
function useRailRow(content) {
|
|
346
|
-
const flyout =
|
|
367
|
+
const flyout = React2.useContext(RailFlyoutContext);
|
|
347
368
|
if (!flyout || !content) return {};
|
|
348
369
|
return flyout.rowProps(content);
|
|
349
370
|
}
|
|
@@ -353,19 +374,19 @@ function useRailFlyout({
|
|
|
353
374
|
activeRoute,
|
|
354
375
|
onNavigate
|
|
355
376
|
}) {
|
|
356
|
-
const [state, setState] =
|
|
357
|
-
const [pos, setPos] =
|
|
358
|
-
const [animate, setAnimate] =
|
|
359
|
-
const panelRef =
|
|
360
|
-
const closeTimer =
|
|
361
|
-
const lastContent =
|
|
362
|
-
const cancelClose =
|
|
377
|
+
const [state, setState] = React2.useState(null);
|
|
378
|
+
const [pos, setPos] = React2.useState({ top: 0, arrow: 20 });
|
|
379
|
+
const [animate, setAnimate] = React2.useState(false);
|
|
380
|
+
const panelRef = React2.useRef(null);
|
|
381
|
+
const closeTimer = React2.useRef(null);
|
|
382
|
+
const lastContent = React2.useRef(null);
|
|
383
|
+
const cancelClose = React2.useCallback(() => {
|
|
363
384
|
if (closeTimer.current) {
|
|
364
385
|
clearTimeout(closeTimer.current);
|
|
365
386
|
closeTimer.current = null;
|
|
366
387
|
}
|
|
367
388
|
}, []);
|
|
368
|
-
const show =
|
|
389
|
+
const show = React2.useCallback(
|
|
369
390
|
(anchor, content2) => {
|
|
370
391
|
if (!enabled) return;
|
|
371
392
|
cancelClose();
|
|
@@ -373,19 +394,19 @@ function useRailFlyout({
|
|
|
373
394
|
},
|
|
374
395
|
[enabled, cancelClose]
|
|
375
396
|
);
|
|
376
|
-
const hide =
|
|
397
|
+
const hide = React2.useCallback(() => {
|
|
377
398
|
cancelClose();
|
|
378
399
|
closeTimer.current = setTimeout(() => setState(null), CLOSE_DELAY_MS);
|
|
379
400
|
}, [cancelClose]);
|
|
380
|
-
const dismiss =
|
|
401
|
+
const dismiss = React2.useCallback(() => {
|
|
381
402
|
cancelClose();
|
|
382
403
|
setState(null);
|
|
383
404
|
}, [cancelClose]);
|
|
384
|
-
|
|
385
|
-
|
|
405
|
+
React2.useEffect(() => () => cancelClose(), [cancelClose]);
|
|
406
|
+
React2.useEffect(() => {
|
|
386
407
|
if (!enabled) dismiss();
|
|
387
408
|
}, [enabled, dismiss]);
|
|
388
|
-
const reposition =
|
|
409
|
+
const reposition = React2.useCallback(() => {
|
|
389
410
|
const rail = railRef.current;
|
|
390
411
|
const anchor = state?.anchor;
|
|
391
412
|
if (!rail || !anchor) return;
|
|
@@ -400,7 +421,7 @@ function useRailFlyout({
|
|
|
400
421
|
setPos({ top, arrow });
|
|
401
422
|
}, [railRef, state]);
|
|
402
423
|
useIsomorphicLayoutEffect(reposition, [reposition, state?.content.key]);
|
|
403
|
-
|
|
424
|
+
React2.useEffect(() => {
|
|
404
425
|
if (!state) return;
|
|
405
426
|
const rail = railRef.current;
|
|
406
427
|
const onScroll = () => reposition();
|
|
@@ -412,7 +433,7 @@ function useRailFlyout({
|
|
|
412
433
|
};
|
|
413
434
|
}, [state, railRef, reposition]);
|
|
414
435
|
const visible = !!state;
|
|
415
|
-
|
|
436
|
+
React2.useEffect(() => {
|
|
416
437
|
if (!visible) {
|
|
417
438
|
setAnimate(false);
|
|
418
439
|
return;
|
|
@@ -420,7 +441,7 @@ function useRailFlyout({
|
|
|
420
441
|
const id = requestAnimationFrame(() => setAnimate(true));
|
|
421
442
|
return () => cancelAnimationFrame(id);
|
|
422
443
|
}, [visible]);
|
|
423
|
-
|
|
444
|
+
React2.useEffect(() => {
|
|
424
445
|
if (!visible) return;
|
|
425
446
|
const onKey = (event) => {
|
|
426
447
|
if (event.key === "Escape") dismiss();
|
|
@@ -428,7 +449,7 @@ function useRailFlyout({
|
|
|
428
449
|
window.addEventListener("keydown", onKey);
|
|
429
450
|
return () => window.removeEventListener("keydown", onKey);
|
|
430
451
|
}, [visible, dismiss]);
|
|
431
|
-
const rowProps =
|
|
452
|
+
const rowProps = React2.useCallback(
|
|
432
453
|
(content2) => ({
|
|
433
454
|
onMouseEnter: (event) => show(event.currentTarget, content2),
|
|
434
455
|
onFocus: (event) => show(event.currentTarget, content2),
|
|
@@ -545,7 +566,7 @@ function FlyoutBody({
|
|
|
545
566
|
] });
|
|
546
567
|
}
|
|
547
568
|
var RAIL_PUSH_MS = 260;
|
|
548
|
-
var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ?
|
|
569
|
+
var useIsomorphicLayoutEffect2 = typeof window !== "undefined" ? React2.useLayoutEffect : React2.useEffect;
|
|
549
570
|
function getIcon(name) {
|
|
550
571
|
return ICON_MAP[name] ?? Home;
|
|
551
572
|
}
|
|
@@ -601,6 +622,7 @@ function NavItem({
|
|
|
601
622
|
item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: cn("rounded-full bg-primary px-2 py-0.5 text-xs font-semibold text-primary-foreground", !isExternal && !item.premium && "ml-auto"), children: item.badge })
|
|
602
623
|
] })
|
|
603
624
|
] });
|
|
625
|
+
const anchor = `nav.${item.route}`;
|
|
604
626
|
return isExternal ? /* @__PURE__ */ jsx("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className, ...hoverProps, children: inner }) : /* @__PURE__ */ jsx(
|
|
605
627
|
"button",
|
|
606
628
|
{
|
|
@@ -609,6 +631,7 @@ function NavItem({
|
|
|
609
631
|
onNavigate(item.route);
|
|
610
632
|
},
|
|
611
633
|
className,
|
|
634
|
+
"data-tour": anchor,
|
|
612
635
|
...hoverProps,
|
|
613
636
|
children: inner
|
|
614
637
|
}
|
|
@@ -645,7 +668,7 @@ function NavGroup({
|
|
|
645
668
|
flyout
|
|
646
669
|
}) {
|
|
647
670
|
const isChildActive = item.children?.some((c) => c.route === activeRoute);
|
|
648
|
-
const [open, setOpen] =
|
|
671
|
+
const [open, setOpen] = React2.useState(() => isChildActive ?? false);
|
|
649
672
|
const Icon = getIcon(item.icon);
|
|
650
673
|
if (collapsed) {
|
|
651
674
|
const hoverProps = flyout?.rowProps(flyoutContentOf(item));
|
|
@@ -656,6 +679,7 @@ function NavGroup({
|
|
|
656
679
|
flyout?.dismiss();
|
|
657
680
|
onNavigate(item.route);
|
|
658
681
|
},
|
|
682
|
+
"data-tour": `nav.${item.route}`,
|
|
659
683
|
className: cn(
|
|
660
684
|
"flex w-full items-center justify-center rounded-button px-2 py-2 text-sm font-medium transition-colors",
|
|
661
685
|
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
@@ -719,7 +743,7 @@ function NavGroup({
|
|
|
719
743
|
child.premium && /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3 shrink-0 text-amber-500", "aria-hidden": true })
|
|
720
744
|
] });
|
|
721
745
|
const row = childExternal ? /* @__PURE__ */ jsx("a", { href: child.href, target: "_blank", rel: "noopener noreferrer", className: childClass, children: childInner }) : /* @__PURE__ */ jsx("button", { onClick: () => onNavigate(child.route), className: childClass, children: childInner });
|
|
722
|
-
if (!childConnector) return /* @__PURE__ */ jsx(
|
|
746
|
+
if (!childConnector) return /* @__PURE__ */ jsx(React2.Fragment, { children: row }, child.id);
|
|
723
747
|
const activeIndex = item.children.findIndex((c) => c.route === activeRoute);
|
|
724
748
|
const onPath = activeIndex >= 0 && childIndex < activeIndex;
|
|
725
749
|
return (
|
|
@@ -781,9 +805,9 @@ function NavGroup({
|
|
|
781
805
|
] });
|
|
782
806
|
}
|
|
783
807
|
function withCollapsed(slot, collapsed) {
|
|
784
|
-
if (!
|
|
808
|
+
if (!React2.isValidElement(slot)) return slot;
|
|
785
809
|
if (typeof slot.type === "string") return slot;
|
|
786
|
-
return
|
|
810
|
+
return React2.cloneElement(slot, { collapsed });
|
|
787
811
|
}
|
|
788
812
|
function Sidebar({
|
|
789
813
|
navigation,
|
|
@@ -812,7 +836,7 @@ function Sidebar({
|
|
|
812
836
|
const currentPath = currentPathProp;
|
|
813
837
|
const setCommandPaletteOpen = useLayoutStore((s) => s.setCommandPaletteOpen);
|
|
814
838
|
const activeRoute = resolveActiveRoute(navigation, currentPath);
|
|
815
|
-
const railRef =
|
|
839
|
+
const railRef = React2.useRef(null);
|
|
816
840
|
const flyout = useRailFlyout({
|
|
817
841
|
enabled: collapsed,
|
|
818
842
|
railRef,
|
|
@@ -861,10 +885,10 @@ function Sidebar({
|
|
|
861
885
|
mainItems.length > 0 && renderSection(mainItems, sectionLabels?.main),
|
|
862
886
|
secondaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-6", children: renderSection(secondaryItems, sectionLabels?.secondary) })
|
|
863
887
|
] });
|
|
864
|
-
const [outgoing, setOutgoing] =
|
|
865
|
-
const lastBodyRef =
|
|
866
|
-
const lastKeyRef =
|
|
867
|
-
const timerRef =
|
|
888
|
+
const [outgoing, setOutgoing] = React2.useState(null);
|
|
889
|
+
const lastBodyRef = React2.useRef(null);
|
|
890
|
+
const lastKeyRef = React2.useRef(navKey);
|
|
891
|
+
const timerRef = React2.useRef(null);
|
|
868
892
|
useIsomorphicLayoutEffect2(() => {
|
|
869
893
|
if (lastKeyRef.current !== navKey) {
|
|
870
894
|
const previousBody = lastBodyRef.current;
|
|
@@ -877,7 +901,7 @@ function Sidebar({
|
|
|
877
901
|
}
|
|
878
902
|
lastBodyRef.current = navBody;
|
|
879
903
|
});
|
|
880
|
-
|
|
904
|
+
React2.useEffect(() => () => {
|
|
881
905
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
882
906
|
}, []);
|
|
883
907
|
return (
|
|
@@ -1022,34 +1046,41 @@ function Sidebar({
|
|
|
1022
1046
|
// it the padded/bordered wrapper shows as a blank block.
|
|
1023
1047
|
/* @__PURE__ */ jsx("div", { className: cn("space-y-2 p-2 empty:hidden", !borderless && "border-t border-sidebar-border"), children: footerContent }),
|
|
1024
1048
|
withCollapsed(orgSwitcher, collapsed),
|
|
1025
|
-
/* @__PURE__ */ jsx(
|
|
1026
|
-
"
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1049
|
+
/* @__PURE__ */ jsx(
|
|
1050
|
+
"div",
|
|
1051
|
+
{
|
|
1052
|
+
className: cn("py-2 pr-2", !borderless && "border-t border-sidebar-border"),
|
|
1053
|
+
style: drawer ? { paddingBottom: "calc(0.5rem + env(safe-area-inset-bottom))" } : void 0,
|
|
1054
|
+
children: /* @__PURE__ */ jsxs("div", { className: cn(
|
|
1055
|
+
"flex items-center rounded-button",
|
|
1056
|
+
collapsed ? "flex-col gap-1" : "gap-1"
|
|
1057
|
+
), children: [
|
|
1058
|
+
userMenuSlot,
|
|
1059
|
+
!collapsed && /* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
1060
|
+
notificationSlot ?? /* @__PURE__ */ jsxs(
|
|
1061
|
+
"button",
|
|
1062
|
+
{
|
|
1063
|
+
className: "fz-tap relative inline-flex shrink-0 items-center justify-center rounded-button p-2 text-sidebar-muted transition-colors hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground",
|
|
1064
|
+
"aria-label": unreadCount > 0 ? `${unreadCount} unread notifications` : "Notifications",
|
|
1065
|
+
children: [
|
|
1066
|
+
/* @__PURE__ */ jsx(Bell, { className: "h-4 w-4" }),
|
|
1067
|
+
unreadCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute right-1 top-1 h-2 w-2 rounded-full bg-destructive" })
|
|
1068
|
+
]
|
|
1069
|
+
}
|
|
1070
|
+
),
|
|
1071
|
+
!drawer && /* @__PURE__ */ jsx(
|
|
1072
|
+
"button",
|
|
1073
|
+
{
|
|
1074
|
+
onClick: onToggle,
|
|
1075
|
+
className: "fz-tap inline-flex shrink-0 items-center justify-center rounded-button p-2 text-sidebar-muted transition-colors hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground",
|
|
1076
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
1077
|
+
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
1078
|
+
children: collapsed ? /* @__PURE__ */ jsx(PanelLeft, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(PanelLeftClose, { className: "h-4 w-4" })
|
|
1079
|
+
}
|
|
1080
|
+
)
|
|
1081
|
+
] })
|
|
1082
|
+
}
|
|
1083
|
+
),
|
|
1053
1084
|
flyout.panel
|
|
1054
1085
|
]
|
|
1055
1086
|
}
|
|
@@ -1066,7 +1097,7 @@ function TopbarUserMenu({
|
|
|
1066
1097
|
onBilling,
|
|
1067
1098
|
userMenuExtras
|
|
1068
1099
|
}) {
|
|
1069
|
-
const [open, setOpen] =
|
|
1100
|
+
const [open, setOpen] = React2.useState(false);
|
|
1070
1101
|
if (!user) return null;
|
|
1071
1102
|
const initial = (user.fullName?.trim()?.[0] ?? user.email?.[0] ?? "?").toUpperCase();
|
|
1072
1103
|
const item = (label, onClick, Icon) => onClick ? /* @__PURE__ */ jsxs(
|
|
@@ -1150,7 +1181,7 @@ function getIcon2(name) {
|
|
|
1150
1181
|
return ICON_MAP[name] ?? Home;
|
|
1151
1182
|
}
|
|
1152
1183
|
function NavDropdown({ item, currentPath, onNavigate }) {
|
|
1153
|
-
const [open, setOpen] =
|
|
1184
|
+
const [open, setOpen] = React2.useState(false);
|
|
1154
1185
|
const Icon = getIcon2(item.icon);
|
|
1155
1186
|
const isChildActive = item.children?.some(
|
|
1156
1187
|
(child) => currentPath === child.route || currentPath.startsWith(child.route + "/")
|
|
@@ -1208,6 +1239,7 @@ function Topbar({
|
|
|
1208
1239
|
logo,
|
|
1209
1240
|
user,
|
|
1210
1241
|
onMenuClick,
|
|
1242
|
+
hideMobileChrome,
|
|
1211
1243
|
orgSwitcher,
|
|
1212
1244
|
leftContent,
|
|
1213
1245
|
rightContent,
|
|
@@ -1231,7 +1263,7 @@ function Topbar({
|
|
|
1231
1263
|
onNavigate?.(route);
|
|
1232
1264
|
};
|
|
1233
1265
|
return /* @__PURE__ */ jsxs("header", { "data-print": "hide", className: "sticky top-0 z-50 w-full shrink-0", children: [
|
|
1234
|
-
/* @__PURE__ */ jsx("div", { className: "border-b border-sidebar-border bg-sidebar text-sidebar-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex h-14 w-full items-center justify-between px-4 md:px-6", children: [
|
|
1266
|
+
/* @__PURE__ */ jsx("div", { className: cn("border-b border-sidebar-border bg-sidebar text-sidebar-foreground", hideMobileChrome && "hidden md:block"), children: /* @__PURE__ */ jsxs("div", { className: "flex h-14 w-full items-center justify-between px-4 md:px-6", children: [
|
|
1235
1267
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
|
|
1236
1268
|
onMenuClick && /* @__PURE__ */ jsx(
|
|
1237
1269
|
"button",
|
|
@@ -1316,24 +1348,27 @@ function Topbar({
|
|
|
1316
1348
|
}) }) }) })
|
|
1317
1349
|
] });
|
|
1318
1350
|
}
|
|
1319
|
-
var ModuleHeaderSlotContext =
|
|
1351
|
+
var ModuleHeaderSlotContext = React2.createContext(null);
|
|
1320
1352
|
function useModuleHeaderSlot() {
|
|
1321
|
-
return
|
|
1353
|
+
return React2.useContext(ModuleHeaderSlotContext);
|
|
1322
1354
|
}
|
|
1323
|
-
var ModuleHeaderActionsSlotContext =
|
|
1355
|
+
var ModuleHeaderActionsSlotContext = React2.createContext(null);
|
|
1324
1356
|
function useModuleHeaderActionsSlot() {
|
|
1325
|
-
return
|
|
1357
|
+
return React2.useContext(ModuleHeaderActionsSlotContext);
|
|
1326
1358
|
}
|
|
1327
|
-
var PageRailSlotContext =
|
|
1359
|
+
var PageRailSlotContext = React2.createContext(null);
|
|
1328
1360
|
function usePageRailSlot() {
|
|
1329
|
-
return
|
|
1361
|
+
return React2.useContext(PageRailSlotContext);
|
|
1362
|
+
}
|
|
1363
|
+
function bottomNavReachesAll(items) {
|
|
1364
|
+
return !!items?.some((i) => "kind" in i && i.kind === "more");
|
|
1330
1365
|
}
|
|
1331
1366
|
function ShellPageTitle({
|
|
1332
1367
|
title,
|
|
1333
1368
|
back
|
|
1334
1369
|
}) {
|
|
1335
1370
|
if (!title && !back) return null;
|
|
1336
|
-
return /* @__PURE__ */ jsx(PageHeaderCrumb, { title, parentLabel: back?.label, onBack: back?.onBack });
|
|
1371
|
+
return /* @__PURE__ */ jsx(PageHeaderCrumb, { title, parentLabel: back?.label, onBack: back?.onBack, headingLevel: "h1" });
|
|
1337
1372
|
}
|
|
1338
1373
|
function SidebarLayout({
|
|
1339
1374
|
navigation = [],
|
|
@@ -1362,6 +1397,7 @@ function SidebarLayout({
|
|
|
1362
1397
|
unreadCount = 0,
|
|
1363
1398
|
searchLabel,
|
|
1364
1399
|
hasBottomNav = false,
|
|
1400
|
+
barOwnsNav = false,
|
|
1365
1401
|
mobileHeader = "minimal",
|
|
1366
1402
|
sidebarSectionLabels,
|
|
1367
1403
|
sidebarNavKey,
|
|
@@ -1370,16 +1406,19 @@ function SidebarLayout({
|
|
|
1370
1406
|
railOpen
|
|
1371
1407
|
}) {
|
|
1372
1408
|
const sidebarCollapsed = useLayoutStore((s) => s.sidebarCollapsed);
|
|
1373
|
-
const
|
|
1409
|
+
const pageHeaderClaimed = usePageHeaderClaimed();
|
|
1410
|
+
const setTitleSlot = usePageTitleSlotHost();
|
|
1374
1411
|
usePageHeaderHost();
|
|
1375
1412
|
const setSidebarCollapsed = useLayoutStore((s) => s.setSidebarCollapsed);
|
|
1376
|
-
const
|
|
1377
|
-
const
|
|
1378
|
-
const [
|
|
1379
|
-
const [
|
|
1413
|
+
const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
1414
|
+
const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
1415
|
+
const [headerSlot, setHeaderSlot] = React2.useState(null);
|
|
1416
|
+
const [actionsSlot, setActionsSlot] = React2.useState(null);
|
|
1417
|
+
const [pageRailSlot, setPageRailSlot] = React2.useState(null);
|
|
1380
1418
|
const hasPageActions = useHasPageActions();
|
|
1381
1419
|
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(
|
|
1382
|
-
"shell-enter flex
|
|
1420
|
+
"shell-enter fz-viewport-h flex overflow-hidden bg-background",
|
|
1421
|
+
hasBottomNav && "fz-has-bottom-bar",
|
|
1383
1422
|
// Frame mode: the inset gap around the framed card takes the sidebar (menu)
|
|
1384
1423
|
// color, so the white card reads as a panel floating on the same tone as the
|
|
1385
1424
|
// left menu. The card's own md:m-2 margin reveals this behind it.
|
|
@@ -1437,7 +1476,7 @@ function SidebarLayout({
|
|
|
1437
1476
|
mobileHeader !== "minimal" && !hasPageActions && "hidden md:flex"
|
|
1438
1477
|
), children: [
|
|
1439
1478
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
1440
|
-
!
|
|
1479
|
+
!barOwnsNav && /* @__PURE__ */ jsx(
|
|
1441
1480
|
"button",
|
|
1442
1481
|
{
|
|
1443
1482
|
onClick: () => setMobileMenuOpen(true),
|
|
@@ -1446,7 +1485,8 @@ function SidebarLayout({
|
|
|
1446
1485
|
children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
|
|
1447
1486
|
}
|
|
1448
1487
|
),
|
|
1449
|
-
|
|
1488
|
+
!pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: pageTitle, back: pageBack }),
|
|
1489
|
+
/* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" }),
|
|
1450
1490
|
topbarStart,
|
|
1451
1491
|
/* @__PURE__ */ jsx("div", { ref: setHeaderSlot, className: "flex min-w-0 flex-1 items-center" })
|
|
1452
1492
|
] }),
|
|
@@ -1499,6 +1539,7 @@ function TopbarLayout({
|
|
|
1499
1539
|
billingLabel,
|
|
1500
1540
|
userMenuExtras,
|
|
1501
1541
|
userMenuSlot,
|
|
1542
|
+
drawerUserMenuSlot,
|
|
1502
1543
|
orgSwitcher,
|
|
1503
1544
|
frame,
|
|
1504
1545
|
currentPath,
|
|
@@ -1507,19 +1548,23 @@ function TopbarLayout({
|
|
|
1507
1548
|
pageTitle,
|
|
1508
1549
|
pageBack,
|
|
1509
1550
|
notificationSlot,
|
|
1510
|
-
|
|
1551
|
+
unreadCount = 0,
|
|
1552
|
+
hasBottomNav = false,
|
|
1553
|
+
barOwnsNav = false
|
|
1511
1554
|
}) {
|
|
1512
|
-
const
|
|
1513
|
-
const
|
|
1514
|
-
const [
|
|
1515
|
-
const [
|
|
1516
|
-
const
|
|
1555
|
+
const mobileMenuOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
1556
|
+
const setMobileMenuOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
1557
|
+
const [headerSlot, setHeaderSlot] = React2.useState(null);
|
|
1558
|
+
const [actionsSlot, setActionsSlot] = React2.useState(null);
|
|
1559
|
+
const [pageRailSlot, setPageRailSlot] = React2.useState(null);
|
|
1560
|
+
const rawClaimed = usePageHeaderClaimed();
|
|
1561
|
+
const setTitleSlot = usePageTitleSlotHost();
|
|
1517
1562
|
const hasOutlet = useHasPageHeaderOutlet();
|
|
1518
1563
|
const hasPageActions = useHasPageActions();
|
|
1519
1564
|
usePageHeaderHost();
|
|
1520
|
-
const
|
|
1565
|
+
const pageHeaderClaimed = hasOutlet ? false : rawClaimed;
|
|
1521
1566
|
const showTitle = !hasOutlet && !!pageTitle;
|
|
1522
|
-
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: "shell-enter relative flex
|
|
1567
|
+
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("shell-enter fz-viewport-h relative flex flex-col overflow-hidden bg-background", hasBottomNav && "fz-has-bottom-bar"), children: [
|
|
1523
1568
|
/* @__PURE__ */ jsx(
|
|
1524
1569
|
Topbar,
|
|
1525
1570
|
{
|
|
@@ -1542,19 +1587,30 @@ function TopbarLayout({
|
|
|
1542
1587
|
topbarEnd,
|
|
1543
1588
|
notificationSlot
|
|
1544
1589
|
] }) : void 0,
|
|
1545
|
-
onMenuClick:
|
|
1590
|
+
onMenuClick: barOwnsNav ? void 0 : () => setMobileMenuOpen(true),
|
|
1591
|
+
hideMobileChrome: barOwnsNav
|
|
1546
1592
|
}
|
|
1547
1593
|
),
|
|
1548
1594
|
/* @__PURE__ */ jsx("main", { className: cn("flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", frame && "md:bg-sidebar md:p-2"), children: /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 min-h-0 flex-1 overflow-hidden", frame && "md:rounded-xl md:border md:border-border md:bg-content"), children: [
|
|
1549
1595
|
/* @__PURE__ */ jsx("div", { ref: setPageRailSlot, className: "flex shrink-0 empty:hidden" }),
|
|
1550
1596
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 min-h-0 flex-1 flex-col overflow-hidden", children: [
|
|
1551
|
-
(
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1597
|
+
(pageHeaderClaimed || pageBack || hasPageActions || barOwnsNav) && /* @__PURE__ */ jsxs(
|
|
1598
|
+
"div",
|
|
1599
|
+
{
|
|
1600
|
+
className: cn(
|
|
1601
|
+
"flex min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-2",
|
|
1602
|
+
!(pageHeaderClaimed || pageBack || hasPageActions) && "md:hidden"
|
|
1603
|
+
),
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
1606
|
+
!pageHeaderClaimed && /* @__PURE__ */ jsx(ShellPageTitle, { title: showTitle ? pageTitle : void 0, back: pageBack }),
|
|
1607
|
+
/* @__PURE__ */ jsx("div", { ref: setTitleSlot, className: "flex min-w-0 items-center empty:hidden" }),
|
|
1608
|
+
/* @__PURE__ */ jsx("div", { ref: setHeaderSlot, className: "flex min-w-0 flex-1 items-center" })
|
|
1609
|
+
] }),
|
|
1610
|
+
/* @__PURE__ */ jsx("div", { ref: setActionsSlot, className: "flex shrink-0 items-center gap-2" })
|
|
1611
|
+
]
|
|
1612
|
+
}
|
|
1613
|
+
),
|
|
1558
1614
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pb-16 md:pb-0", children })
|
|
1559
1615
|
] })
|
|
1560
1616
|
] }) }),
|
|
@@ -1572,7 +1628,9 @@ function TopbarLayout({
|
|
|
1572
1628
|
onSettings,
|
|
1573
1629
|
onBilling,
|
|
1574
1630
|
orgSwitcher,
|
|
1575
|
-
userMenuSlot: user ? /* @__PURE__ */ jsx(DrawerUserRow, { user }) : void 0,
|
|
1631
|
+
userMenuSlot: drawerUserMenuSlot ?? (user ? /* @__PURE__ */ jsx(DrawerUserRow, { user }) : void 0),
|
|
1632
|
+
notificationSlot,
|
|
1633
|
+
unreadCount,
|
|
1576
1634
|
onClose: () => setMobileMenuOpen(false)
|
|
1577
1635
|
}
|
|
1578
1636
|
)
|
|
@@ -1589,9 +1647,10 @@ function MinimalLayout({
|
|
|
1589
1647
|
logo,
|
|
1590
1648
|
user: _user,
|
|
1591
1649
|
children,
|
|
1592
|
-
headerEnd
|
|
1650
|
+
headerEnd,
|
|
1651
|
+
hasBottomNav = false
|
|
1593
1652
|
}) {
|
|
1594
|
-
return /* @__PURE__ */ jsxs("div", { className: "shell-enter
|
|
1653
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("shell-enter fz-viewport-h flex flex-col", hasBottomNav && "fz-has-bottom-bar"), children: [
|
|
1595
1654
|
/* @__PURE__ */ jsxs("header", { className: "flex h-14 shrink-0 items-center justify-between border-b border-border bg-card px-4 md:px-6", children: [
|
|
1596
1655
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: logo ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: "App" }) }),
|
|
1597
1656
|
headerEnd && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: headerEnd })
|
|
@@ -1600,23 +1659,23 @@ function MinimalLayout({
|
|
|
1600
1659
|
] });
|
|
1601
1660
|
}
|
|
1602
1661
|
function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
|
|
1603
|
-
const [visible, setVisible] =
|
|
1604
|
-
|
|
1662
|
+
const [visible, setVisible] = React2.useState(false);
|
|
1663
|
+
React2.useEffect(() => {
|
|
1605
1664
|
const id = requestAnimationFrame(() => setVisible(true));
|
|
1606
1665
|
return () => cancelAnimationFrame(id);
|
|
1607
1666
|
}, []);
|
|
1608
|
-
const close =
|
|
1667
|
+
const close = React2.useCallback(() => {
|
|
1609
1668
|
setVisible(false);
|
|
1610
1669
|
window.setTimeout(onClose, 250);
|
|
1611
1670
|
}, [onClose]);
|
|
1612
|
-
|
|
1671
|
+
React2.useEffect(() => {
|
|
1613
1672
|
const previous = document.body.style.overflow;
|
|
1614
1673
|
document.body.style.overflow = "hidden";
|
|
1615
1674
|
return () => {
|
|
1616
1675
|
document.body.style.overflow = previous;
|
|
1617
1676
|
};
|
|
1618
1677
|
}, []);
|
|
1619
|
-
|
|
1678
|
+
React2.useEffect(() => {
|
|
1620
1679
|
const onKey = (e) => {
|
|
1621
1680
|
if (e.key === "Escape") close();
|
|
1622
1681
|
};
|
|
@@ -1659,19 +1718,7 @@ function MobileOverlay({ onClose, onNavigate, ...sidebarProps }) {
|
|
|
1659
1718
|
)
|
|
1660
1719
|
] });
|
|
1661
1720
|
}
|
|
1662
|
-
var
|
|
1663
|
-
Home: Home,
|
|
1664
|
-
Receipt,
|
|
1665
|
-
ArrowLeftRight,
|
|
1666
|
-
Calendar,
|
|
1667
|
-
CreditCard: CreditCard,
|
|
1668
|
-
Settings: Settings,
|
|
1669
|
-
Menu: Menu,
|
|
1670
|
-
MessageCircle,
|
|
1671
|
-
Wallet,
|
|
1672
|
-
PiggyBank,
|
|
1673
|
-
Plus
|
|
1674
|
-
};
|
|
1721
|
+
var bottomNavIcon = (name, fallback = Home) => (name ? ICON_MAP[name] : void 0) ?? fallback;
|
|
1675
1722
|
function FloatingProfileAvatar({ user, onClick }) {
|
|
1676
1723
|
if (!user) return null;
|
|
1677
1724
|
const label = user.fullName || user.email;
|
|
@@ -1697,43 +1744,80 @@ function MobileBottomNav({
|
|
|
1697
1744
|
items,
|
|
1698
1745
|
currentPath,
|
|
1699
1746
|
onNavigate,
|
|
1700
|
-
onAction
|
|
1747
|
+
onAction,
|
|
1748
|
+
onMore,
|
|
1749
|
+
onAssistant,
|
|
1750
|
+
assistantOpen,
|
|
1751
|
+
moreOpen,
|
|
1752
|
+
retracted
|
|
1701
1753
|
}) {
|
|
1702
1754
|
const path = currentPath ?? "";
|
|
1703
|
-
return /* @__PURE__ */ jsx(
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1755
|
+
return /* @__PURE__ */ jsx(
|
|
1756
|
+
"nav",
|
|
1757
|
+
{
|
|
1758
|
+
"aria-label": "Navega\xE7\xE3o principal",
|
|
1759
|
+
"aria-hidden": retracted || void 0,
|
|
1760
|
+
className: cn(
|
|
1761
|
+
"fz-safe-b fixed inset-x-0 bottom-0 z-50 flex min-h-16 items-stretch justify-around border-t border-border bg-background md:hidden",
|
|
1762
|
+
"motion-safe:transition-transform motion-safe:duration-200 motion-safe:ease-out",
|
|
1763
|
+
retracted && "pointer-events-none translate-y-full"
|
|
1764
|
+
),
|
|
1765
|
+
children: items.map((item, i) => {
|
|
1766
|
+
if ("kind" in item && item.kind === "action") {
|
|
1767
|
+
const ActionIcon = bottomNavIcon(item.icon, Plus);
|
|
1768
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-start justify-center", children: /* @__PURE__ */ jsx(
|
|
1769
|
+
"button",
|
|
1770
|
+
{
|
|
1771
|
+
type: "button",
|
|
1772
|
+
onClick: () => onAction?.(item.id),
|
|
1773
|
+
"aria-label": item.label ?? "Add",
|
|
1774
|
+
className: "-mt-6 flex h-14 w-14 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg shadow-primary/30 ring-4 ring-background transition-transform active:scale-95",
|
|
1775
|
+
children: /* @__PURE__ */ jsx(ActionIcon, { className: "h-6 w-6" })
|
|
1776
|
+
}
|
|
1777
|
+
) }, item.id);
|
|
1714
1778
|
}
|
|
1715
|
-
|
|
1779
|
+
const isMore = "kind" in item && item.kind === "more";
|
|
1780
|
+
const isAssistant = "kind" in item && item.kind === "assistant";
|
|
1781
|
+
const label = isMore ? item.label ?? "Mais" : isAssistant ? item.label ?? "IA" : item.label;
|
|
1782
|
+
const Icon = bottomNavIcon(
|
|
1783
|
+
item.icon,
|
|
1784
|
+
isMore ? Menu : isAssistant ? Sparkles : Home
|
|
1785
|
+
);
|
|
1786
|
+
const route = isMore || isAssistant ? void 0 : item.route;
|
|
1787
|
+
const isActive = isMore ? !!moreOpen : isAssistant ? !!assistantOpen : route === "/" ? path === "/" || path === "" : !!route && (path === route || path.startsWith(route + "/"));
|
|
1788
|
+
return /* @__PURE__ */ jsxs(
|
|
1789
|
+
"button",
|
|
1790
|
+
{
|
|
1791
|
+
type: "button",
|
|
1792
|
+
onClick: () => isMore ? onMore?.() : isAssistant ? onAssistant?.() : onNavigate?.(route),
|
|
1793
|
+
"aria-current": isActive && route ? "page" : void 0,
|
|
1794
|
+
"aria-expanded": isMore || isAssistant ? isActive : void 0,
|
|
1795
|
+
className: cn(
|
|
1796
|
+
// min-h-[44px] is the floor a finger needs; the bar was letting
|
|
1797
|
+
// content decide and landing around 40.
|
|
1798
|
+
"relative flex min-h-[44px] flex-1 flex-col items-center justify-center gap-0.5 px-1 py-2 transition-colors",
|
|
1799
|
+
isActive ? "text-primary" : "text-muted-foreground"
|
|
1800
|
+
),
|
|
1801
|
+
children: [
|
|
1802
|
+
/* @__PURE__ */ jsx(
|
|
1803
|
+
"span",
|
|
1804
|
+
{
|
|
1805
|
+
"aria-hidden": true,
|
|
1806
|
+
className: cn(
|
|
1807
|
+
"absolute inset-x-3 top-0 h-0.5 rounded-full transition-opacity",
|
|
1808
|
+
isActive ? "bg-primary opacity-100" : "opacity-0"
|
|
1809
|
+
)
|
|
1810
|
+
}
|
|
1811
|
+
),
|
|
1812
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 shrink-0" }),
|
|
1813
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-[11px] leading-tight", children: label })
|
|
1814
|
+
]
|
|
1815
|
+
},
|
|
1816
|
+
isMore ? "more" : isAssistant ? "assistant" : `${route}-${i}`
|
|
1817
|
+
);
|
|
1818
|
+
})
|
|
1716
1819
|
}
|
|
1717
|
-
|
|
1718
|
-
const Icon = BOTTOM_NAV_ICONS[item.icon] ?? Home;
|
|
1719
|
-
return /* @__PURE__ */ jsxs(
|
|
1720
|
-
"button",
|
|
1721
|
-
{
|
|
1722
|
-
type: "button",
|
|
1723
|
-
onClick: () => onNavigate?.(item.route),
|
|
1724
|
-
className: cn(
|
|
1725
|
-
"flex flex-1 flex-col items-center justify-center gap-0.5 px-1 py-1 transition-colors",
|
|
1726
|
-
isActive ? "text-primary" : "text-muted-foreground"
|
|
1727
|
-
),
|
|
1728
|
-
"aria-current": isActive ? "page" : void 0,
|
|
1729
|
-
children: [
|
|
1730
|
-
/* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" }),
|
|
1731
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs", children: item.label })
|
|
1732
|
-
]
|
|
1733
|
-
},
|
|
1734
|
-
item.route
|
|
1735
|
-
);
|
|
1736
|
-
}) });
|
|
1820
|
+
);
|
|
1737
1821
|
}
|
|
1738
1822
|
function AppShell({
|
|
1739
1823
|
variant,
|
|
@@ -1762,8 +1846,11 @@ function AppShell({
|
|
|
1762
1846
|
sidebarFooterContent,
|
|
1763
1847
|
bottomNav,
|
|
1764
1848
|
onBottomNavAction,
|
|
1849
|
+
onAssistantToggle,
|
|
1850
|
+
assistantOpen,
|
|
1765
1851
|
mobileHeader = "minimal",
|
|
1766
1852
|
userMenuSlot,
|
|
1853
|
+
drawerUserMenuSlot,
|
|
1767
1854
|
notificationSlot,
|
|
1768
1855
|
unreadCount = 0,
|
|
1769
1856
|
searchLabel,
|
|
@@ -1780,13 +1867,26 @@ function AppShell({
|
|
|
1780
1867
|
rightRailResizeLabel
|
|
1781
1868
|
}) {
|
|
1782
1869
|
const hasBottomNav = !!bottomNav?.length;
|
|
1870
|
+
const barOwnsNav = bottomNavReachesAll(bottomNav);
|
|
1871
|
+
const pageClaimedBack = useHasPageHeaderBack();
|
|
1872
|
+
const barRetracted = !!pageBack || pageClaimedBack;
|
|
1873
|
+
const mobileDrawerOpen = useLayoutStore((st) => st.mobileDrawerOpen);
|
|
1874
|
+
const setMobileDrawerOpen = useLayoutStore((st) => st.setMobileDrawerOpen);
|
|
1875
|
+
React2.useEffect(() => {
|
|
1876
|
+
setMobileDrawerOpen(false);
|
|
1877
|
+
}, [currentPath]);
|
|
1783
1878
|
const bottomBar = hasBottomNav ? /* @__PURE__ */ jsx(
|
|
1784
1879
|
MobileBottomNav,
|
|
1785
1880
|
{
|
|
1786
1881
|
items: bottomNav,
|
|
1787
1882
|
currentPath,
|
|
1788
1883
|
onNavigate,
|
|
1789
|
-
onAction: onBottomNavAction
|
|
1884
|
+
onAction: onBottomNavAction,
|
|
1885
|
+
onMore: () => setMobileDrawerOpen(!mobileDrawerOpen),
|
|
1886
|
+
moreOpen: mobileDrawerOpen,
|
|
1887
|
+
onAssistant: onAssistantToggle,
|
|
1888
|
+
assistantOpen,
|
|
1889
|
+
retracted: barRetracted
|
|
1790
1890
|
}
|
|
1791
1891
|
) : null;
|
|
1792
1892
|
const floatingAvatar = mobileHeader === "transparent" && user ? /* @__PURE__ */ jsx(FloatingProfileAvatar, { user, onClick: onProfile }) : null;
|
|
@@ -1820,7 +1920,8 @@ function AppShell({
|
|
|
1820
1920
|
notificationSlot,
|
|
1821
1921
|
unreadCount,
|
|
1822
1922
|
searchLabel,
|
|
1823
|
-
hasBottomNav,
|
|
1923
|
+
hasBottomNav: hasBottomNav && !barRetracted,
|
|
1924
|
+
barOwnsNav,
|
|
1824
1925
|
mobileHeader,
|
|
1825
1926
|
sidebarSectionLabels,
|
|
1826
1927
|
sidebarNavKey,
|
|
@@ -1847,6 +1948,7 @@ function AppShell({
|
|
|
1847
1948
|
billingLabel,
|
|
1848
1949
|
userMenuExtras,
|
|
1849
1950
|
userMenuSlot,
|
|
1951
|
+
drawerUserMenuSlot,
|
|
1850
1952
|
orgSwitcher,
|
|
1851
1953
|
frame: contentFrame,
|
|
1852
1954
|
currentPath,
|
|
@@ -1855,13 +1957,14 @@ function AppShell({
|
|
|
1855
1957
|
pageTitle,
|
|
1856
1958
|
pageBack,
|
|
1857
1959
|
notificationSlot,
|
|
1858
|
-
hasBottomNav,
|
|
1960
|
+
hasBottomNav: hasBottomNav && !barRetracted,
|
|
1961
|
+
barOwnsNav,
|
|
1859
1962
|
children
|
|
1860
1963
|
}
|
|
1861
1964
|
);
|
|
1862
1965
|
break;
|
|
1863
1966
|
case "minimal":
|
|
1864
|
-
layoutElement = /* @__PURE__ */ jsx(MinimalLayout, { logo, user, headerEnd: topbarEnd, children });
|
|
1967
|
+
layoutElement = /* @__PURE__ */ jsx(MinimalLayout, { logo, user, headerEnd: topbarEnd, hasBottomNav: hasBottomNav && !barRetracted, children });
|
|
1865
1968
|
break;
|
|
1866
1969
|
default: {
|
|
1867
1970
|
return null;
|
|
@@ -1897,13 +2000,13 @@ function SplitWithRightRail({
|
|
|
1897
2000
|
maxWidth = 720,
|
|
1898
2001
|
resizeLabel = "Resize panel"
|
|
1899
2002
|
}) {
|
|
1900
|
-
const [width, setWidth] =
|
|
1901
|
-
const [dragging, setDragging] =
|
|
1902
|
-
const clamp =
|
|
2003
|
+
const [width, setWidth] = React2.useState(defaultWidth);
|
|
2004
|
+
const [dragging, setDragging] = React2.useState(false);
|
|
2005
|
+
const clamp = React2.useCallback(
|
|
1903
2006
|
(value) => Math.min(maxWidth, Math.max(minWidth, value)),
|
|
1904
2007
|
[minWidth, maxWidth]
|
|
1905
2008
|
);
|
|
1906
|
-
|
|
2009
|
+
React2.useEffect(() => {
|
|
1907
2010
|
if (!dragging) return;
|
|
1908
2011
|
const onMove = (event) => {
|
|
1909
2012
|
event.preventDefault();
|
|
@@ -1925,7 +2028,7 @@ function SplitWithRightRail({
|
|
|
1925
2028
|
document.body.style.cursor = previousCursor;
|
|
1926
2029
|
};
|
|
1927
2030
|
}, [dragging, clamp]);
|
|
1928
|
-
|
|
2031
|
+
React2.useEffect(() => {
|
|
1929
2032
|
if (dragging) return;
|
|
1930
2033
|
onWidthChange?.(width);
|
|
1931
2034
|
}, [dragging]);
|
|
@@ -1935,7 +2038,7 @@ function SplitWithRightRail({
|
|
|
1935
2038
|
// chrome, next to the menu — painting them page-white put a bright strip
|
|
1936
2039
|
// between the dark chrome and the rail, which read as a seam rather than
|
|
1937
2040
|
// as space.
|
|
1938
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex
|
|
2041
|
+
/* @__PURE__ */ jsxs("div", { className: cn("fz-viewport-h flex w-full overflow-hidden bg-sidebar", !frame && "md:bg-background"), children: [
|
|
1939
2042
|
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children }),
|
|
1940
2043
|
/* @__PURE__ */ jsxs(
|
|
1941
2044
|
"div",
|
|
@@ -2075,12 +2178,12 @@ function PageTabs({ actions, className, ...props }) {
|
|
|
2075
2178
|
}
|
|
2076
2179
|
);
|
|
2077
2180
|
}
|
|
2078
|
-
var NavTransitionContext =
|
|
2181
|
+
var NavTransitionContext = React2.createContext("slide");
|
|
2079
2182
|
function NavTransitionProvider({ value, children }) {
|
|
2080
2183
|
return /* @__PURE__ */ jsx(NavTransitionContext.Provider, { value, children });
|
|
2081
2184
|
}
|
|
2082
2185
|
function useNavTransition() {
|
|
2083
|
-
return
|
|
2186
|
+
return React2.useContext(NavTransitionContext);
|
|
2084
2187
|
}
|
|
2085
2188
|
function resolveTransitionClass(transition, direction) {
|
|
2086
2189
|
if (transition === "none") return "";
|
|
@@ -2115,15 +2218,15 @@ function PremiumBadge({ className }) {
|
|
|
2115
2218
|
const tip = t("upgrade.badgeTooltip");
|
|
2116
2219
|
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 }) });
|
|
2117
2220
|
}
|
|
2118
|
-
var ModuleLayoutContext =
|
|
2221
|
+
var ModuleLayoutContext = React2.createContext("rail");
|
|
2119
2222
|
function ModuleLayoutProvider({ variant, children }) {
|
|
2120
2223
|
return /* @__PURE__ */ jsx(ModuleLayoutContext.Provider, { value: variant, children });
|
|
2121
2224
|
}
|
|
2122
2225
|
function useModuleLayout() {
|
|
2123
|
-
return
|
|
2226
|
+
return React2.useContext(ModuleLayoutContext);
|
|
2124
2227
|
}
|
|
2125
2228
|
function RailNavItem({ item }) {
|
|
2126
|
-
const [expanded, setExpanded] =
|
|
2229
|
+
const [expanded, setExpanded] = React2.useState(true);
|
|
2127
2230
|
const Icon = item.icon ? ICON_MAP[item.icon] ?? null : null;
|
|
2128
2231
|
const hasChildren = item.children && item.children.length > 0;
|
|
2129
2232
|
const hasActiveChild = hasChildren && item.children.some((c) => c.active);
|
|
@@ -2164,10 +2267,14 @@ function RailNavItem({ item }) {
|
|
|
2164
2267
|
)) })
|
|
2165
2268
|
] });
|
|
2166
2269
|
}
|
|
2270
|
+
function defaultChildOf(item) {
|
|
2271
|
+
const kids = item.children ?? [];
|
|
2272
|
+
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];
|
|
2273
|
+
}
|
|
2167
2274
|
function MobileTabs({ nav }) {
|
|
2168
|
-
const scrollRef =
|
|
2169
|
-
const [expandedId, setExpandedId] =
|
|
2170
|
-
|
|
2275
|
+
const scrollRef = React2.useRef(null);
|
|
2276
|
+
const [expandedId, setExpandedId] = React2.useState(null);
|
|
2277
|
+
React2.useEffect(() => {
|
|
2171
2278
|
const container = scrollRef.current;
|
|
2172
2279
|
if (!container) return;
|
|
2173
2280
|
const activeEl = container.querySelector('[data-active="true"]');
|
|
@@ -2189,6 +2296,7 @@ function MobileTabs({ nav }) {
|
|
|
2189
2296
|
"data-active": isActive || void 0,
|
|
2190
2297
|
onClick: () => {
|
|
2191
2298
|
if (hasChildren) {
|
|
2299
|
+
if (!isExpanded) defaultChildOf(item)?.onClick?.();
|
|
2192
2300
|
setExpandedId(isExpanded ? null : item.id);
|
|
2193
2301
|
} else {
|
|
2194
2302
|
item.onClick?.();
|
|
@@ -2196,11 +2304,15 @@ function MobileTabs({ nav }) {
|
|
|
2196
2304
|
}
|
|
2197
2305
|
},
|
|
2198
2306
|
className: cn(
|
|
2199
|
-
|
|
2307
|
+
// This strip is the most-tapped control in most modules and it
|
|
2308
|
+
// was 28px tall — a third under the comfortable minimum. Height
|
|
2309
|
+
// and text step up on touch; the desktop rail is unaffected.
|
|
2310
|
+
"flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-4 text-sm font-medium transition-colors",
|
|
2311
|
+
"min-h-[2.75rem] active:scale-[0.98]",
|
|
2200
2312
|
isActive ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"
|
|
2201
2313
|
),
|
|
2202
2314
|
children: [
|
|
2203
|
-
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3" }),
|
|
2315
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
|
|
2204
2316
|
item.label,
|
|
2205
2317
|
item.premium && /* @__PURE__ */ jsx(PremiumBadge, {}),
|
|
2206
2318
|
hasChildren && /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-2.5 w-2.5 transition-transform", isExpanded && "rotate-180") })
|
|
@@ -2234,12 +2346,12 @@ function MobileTabs({ nav }) {
|
|
|
2234
2346
|
})()
|
|
2235
2347
|
] });
|
|
2236
2348
|
}
|
|
2237
|
-
var BackStyleContext =
|
|
2349
|
+
var BackStyleContext = React2.createContext("link");
|
|
2238
2350
|
function BackStyleProvider({ style, children }) {
|
|
2239
2351
|
return /* @__PURE__ */ jsx(BackStyleContext.Provider, { value: style, children });
|
|
2240
2352
|
}
|
|
2241
2353
|
function useBackStyle() {
|
|
2242
|
-
return
|
|
2354
|
+
return React2.useContext(BackStyleContext);
|
|
2243
2355
|
}
|
|
2244
2356
|
function SubpageHeader({ title, subtitle, icon, onBack, parentLabel, actions, backStyle, inline }) {
|
|
2245
2357
|
const t = useTranslation();
|
|
@@ -2331,15 +2443,16 @@ function ShellSubpageHeader({
|
|
|
2331
2443
|
parentLabel,
|
|
2332
2444
|
actions
|
|
2333
2445
|
}) {
|
|
2334
|
-
usePageHeader(
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2446
|
+
usePageHeader(true, { back: !!onBack });
|
|
2447
|
+
const crumb = /* @__PURE__ */ jsx(PageTitlePortal, { children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2448
|
+
Icon && !onBack && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
2449
|
+
/* @__PURE__ */ jsx(PageHeaderCrumb, { title, parentLabel, onBack })
|
|
2450
|
+
] }) });
|
|
2451
|
+
if (!actions) return crumb;
|
|
2452
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2453
|
+
crumb,
|
|
2454
|
+
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx("div", { className: "no-print flex shrink-0 items-center gap-2", children: actions }) })
|
|
2455
|
+
] });
|
|
2343
2456
|
}
|
|
2344
2457
|
function ModuleHeader({ nav }) {
|
|
2345
2458
|
function defaultChild(item) {
|
|
@@ -2389,12 +2502,12 @@ function ModulePage({ title: _title, subtitle, nav, children, className, headerA
|
|
|
2389
2502
|
] }) }),
|
|
2390
2503
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
2391
2504
|
showHeader && headerAction && /* @__PURE__ */ jsx(PageHeaderActions, { children: headerAction }),
|
|
2392
|
-
/* @__PURE__ */ jsx(MobileTabs, { nav }),
|
|
2505
|
+
!onSubpage && /* @__PURE__ */ jsx(MobileTabs, { nav }),
|
|
2393
2506
|
/* @__PURE__ */ jsx(PageTransition, { transitionKey, direction, children })
|
|
2394
2507
|
] })
|
|
2395
2508
|
] });
|
|
2396
2509
|
}
|
|
2397
2510
|
|
|
2398
|
-
export { AppShell, BackStyleProvider, HeaderTabs, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageRail, PageTabs, PageTransition, RailNavItem, SaveBar, SaveBarProvider, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SubpageHeader, Topbar, useBackHandler, useBackStyle, useCrossModuleBack, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition, useRailRow, useSaveBar, useSaveBarVisible };
|
|
2399
|
-
//# sourceMappingURL=chunk-
|
|
2400
|
-
//# sourceMappingURL=chunk-
|
|
2511
|
+
export { AppShell, BackStyleProvider, HeaderTabs, ModuleLayoutProvider, ModulePage, NavTransitionProvider, PageHeader, PageHeaderActions, PageHeaderCrumb, PageRail, PageTabs, PageTransition, RailNavItem, SaveBar, SaveBarProvider, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SubpageHeader, Topbar, bottomNavReachesAll, useBackHandler, useBackStyle, useCrossModuleBack, useModuleHeaderActionsSlot, useModuleHeaderSlot, useModuleLayout, useNavTransition, useRailRow, useSaveBar, useSaveBarVisible };
|
|
2512
|
+
//# sourceMappingURL=chunk-OBIU37AX.js.map
|
|
2513
|
+
//# sourceMappingURL=chunk-OBIU37AX.js.map
|