@wealthx/shadcn 1.5.33 → 1.5.35
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/.turbo/turbo-build.log +72 -72
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-RSEVIQEO.mjs → chunk-E432NK23.mjs} +41 -36
- package/dist/{chunk-EEI4FLEE.mjs → chunk-WLELT6L7.mjs} +345 -272
- package/dist/components/ui/ai-conversations/index.js +417 -350
- package/dist/components/ui/ai-conversations/index.mjs +1 -1
- package/dist/components/ui/sidebar-nav.js +39 -34
- package/dist/components/ui/sidebar-nav.mjs +1 -1
- package/dist/index.js +4435 -4363
- package/dist/index.mjs +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ui/ai-conversations/bubble.tsx +240 -0
- package/src/components/ui/ai-conversations/index.tsx +9 -8
- package/src/components/ui/ai-conversations/thread.tsx +11 -163
- package/src/components/ui/sidebar-nav.tsx +96 -75
- package/src/styles/styles-css.ts +1 -1
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* Used by both Backoffice (Wealth Pro) and Frontend (WealthX app).
|
|
6
6
|
*
|
|
7
7
|
* Background: bg-brand-secondary (tenant dark navy — set via ThemeProvider).
|
|
8
|
-
* Text: text-brand-
|
|
8
|
+
* Text: text-brand-secondary-foreground (white on dark navy).
|
|
9
9
|
*
|
|
10
10
|
* - All icons must be Lucide icons (LucideIcon type).
|
|
11
11
|
* - Supports collapsible sub-items (accordion).
|
|
12
|
-
* -
|
|
12
|
+
* - Hover mode (default): sidebar is icon-only; hovering expands it temporarily.
|
|
13
|
+
* - Lock mode: clicking the Pin button keeps the sidebar expanded after mouse leaves.
|
|
13
14
|
* - metricsGroups: optional financial summary rows (Frontend sidebar only).
|
|
14
15
|
* - No internal navigation — consumers wire onNavigate / onLogout.
|
|
15
16
|
*/
|
|
@@ -19,8 +20,8 @@ import {
|
|
|
19
20
|
ChevronRight,
|
|
20
21
|
Info,
|
|
21
22
|
LogOut,
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
Pin,
|
|
24
|
+
PinOff,
|
|
24
25
|
} from "lucide-react";
|
|
25
26
|
import type { LucideIcon } from "lucide-react";
|
|
26
27
|
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
|
@@ -72,8 +73,6 @@ export interface SidebarNavProps {
|
|
|
72
73
|
items: SidebarNavItem[];
|
|
73
74
|
/** Display name for the current user */
|
|
74
75
|
userName?: string;
|
|
75
|
-
/** Whether the sidebar is in narrow (icon-only) mode */
|
|
76
|
-
collapsed?: boolean;
|
|
77
76
|
/**
|
|
78
77
|
* Optional logo URL rendered at the top of the sidebar.
|
|
79
78
|
* Hidden when collapsed (unless logoCollapsed is provided).
|
|
@@ -88,13 +87,21 @@ export interface SidebarNavProps {
|
|
|
88
87
|
logoCollapsed?: string;
|
|
89
88
|
/**
|
|
90
89
|
* Optional financial metric groups rendered between the user section and
|
|
91
|
-
* nav items. Hidden when collapsed. Used by the Frontend (WealthX app) sidebar.
|
|
90
|
+
* nav items. Hidden when sidebar is collapsed. Used by the Frontend (WealthX app) sidebar.
|
|
92
91
|
*/
|
|
93
92
|
metricsGroups?: SidebarNavMetricsGroup[];
|
|
94
93
|
onNavigate?: (href: string) => void;
|
|
95
94
|
onLogout?: () => void;
|
|
96
|
-
/**
|
|
97
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Initial locked (pinned) state. When true, sidebar starts expanded and stays
|
|
97
|
+
* open even without hover. Defaults to false (hover-to-expand mode).
|
|
98
|
+
*/
|
|
99
|
+
defaultLocked?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Called when the user toggles the Pin/Unpin button.
|
|
102
|
+
* Use to persist the preference (e.g. localStorage).
|
|
103
|
+
*/
|
|
104
|
+
onLockedChange?: (locked: boolean) => void;
|
|
98
105
|
className?: string;
|
|
99
106
|
}
|
|
100
107
|
|
|
@@ -105,7 +112,7 @@ function navIconCn(isActive: boolean): string {
|
|
|
105
112
|
"shrink-0 transition-colors",
|
|
106
113
|
isActive
|
|
107
114
|
? "text-primary"
|
|
108
|
-
: "text-brand-secondary-foreground/50 group-hover:text-brand-secondary-foreground"
|
|
115
|
+
: "text-brand-secondary-foreground/50 group-hover:text-brand-secondary-foreground"
|
|
109
116
|
);
|
|
110
117
|
}
|
|
111
118
|
|
|
@@ -147,7 +154,7 @@ function MetricsGroup({ group }: MetricsGroupProps) {
|
|
|
147
154
|
className={cn(
|
|
148
155
|
"text-sm truncate text-brand-secondary-foreground/80",
|
|
149
156
|
item.isNetItem &&
|
|
150
|
-
"font-semibold text-brand-secondary-foreground border-b-2 border-primary pb-px"
|
|
157
|
+
"font-semibold text-brand-secondary-foreground border-b-2 border-primary pb-px"
|
|
151
158
|
)}
|
|
152
159
|
>
|
|
153
160
|
{item.name}
|
|
@@ -163,7 +170,7 @@ function MetricsGroup({ group }: MetricsGroupProps) {
|
|
|
163
170
|
<span
|
|
164
171
|
className={cn(
|
|
165
172
|
"text-sm font-semibold tabular-nums shrink-0 text-brand-secondary-foreground",
|
|
166
|
-
item.isNetItem && item.value < 0 && "text-destructive"
|
|
173
|
+
item.isNetItem && item.value < 0 && "text-destructive"
|
|
167
174
|
)}
|
|
168
175
|
>
|
|
169
176
|
{formatCurrency(item.value, { showSign: item.isNetItem })}
|
|
@@ -204,8 +211,8 @@ function SidebarNavItemView({
|
|
|
204
211
|
"justify-start px-3 border-l-4",
|
|
205
212
|
item.isActive
|
|
206
213
|
? "bg-white/15 text-brand-secondary-foreground border-primary"
|
|
207
|
-
: "border-transparent"
|
|
208
|
-
)
|
|
214
|
+
: "border-transparent"
|
|
215
|
+
)
|
|
209
216
|
)}
|
|
210
217
|
>
|
|
211
218
|
<Icon
|
|
@@ -250,7 +257,7 @@ function CollapsibleNavItem({
|
|
|
250
257
|
className={cn(
|
|
251
258
|
"group h-auto w-full justify-center px-2 py-2.5 transition-colors",
|
|
252
259
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
253
|
-
hasActiveChild && "bg-white/15 text-brand-secondary-foreground"
|
|
260
|
+
hasActiveChild && "bg-white/15 text-brand-secondary-foreground"
|
|
254
261
|
)}
|
|
255
262
|
>
|
|
256
263
|
<Icon
|
|
@@ -276,7 +283,7 @@ function CollapsibleNavItem({
|
|
|
276
283
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
277
284
|
"border-l-4 border-transparent",
|
|
278
285
|
hasActiveChild &&
|
|
279
|
-
"bg-white/15 text-brand-secondary-foreground border-primary"
|
|
286
|
+
"bg-white/15 text-brand-secondary-foreground border-primary"
|
|
280
287
|
)}
|
|
281
288
|
>
|
|
282
289
|
<Icon
|
|
@@ -288,7 +295,7 @@ function CollapsibleNavItem({
|
|
|
288
295
|
<ChevronDown
|
|
289
296
|
className={cn(
|
|
290
297
|
"ml-auto shrink-0 text-brand-secondary-foreground/40 transition-transform duration-200",
|
|
291
|
-
"group-data-[panel-open]:rotate-180"
|
|
298
|
+
"group-data-[panel-open]:rotate-180"
|
|
292
299
|
)}
|
|
293
300
|
size={14}
|
|
294
301
|
strokeWidth={2}
|
|
@@ -308,7 +315,7 @@ function CollapsibleNavItem({
|
|
|
308
315
|
className={cn(
|
|
309
316
|
"h-auto w-full justify-start gap-2 py-1.5 pl-1 text-sm transition-colors",
|
|
310
317
|
"text-brand-secondary-foreground/50 hover:text-brand-secondary-foreground",
|
|
311
|
-
sub.isActive && "text-primary font-medium"
|
|
318
|
+
sub.isActive && "text-primary font-medium"
|
|
312
319
|
)}
|
|
313
320
|
>
|
|
314
321
|
<ChevronRight
|
|
@@ -318,7 +325,7 @@ function CollapsibleNavItem({
|
|
|
318
325
|
"shrink-0",
|
|
319
326
|
sub.isActive
|
|
320
327
|
? "text-primary"
|
|
321
|
-
: "text-brand-secondary-foreground/30"
|
|
328
|
+
: "text-brand-secondary-foreground/30"
|
|
322
329
|
)}
|
|
323
330
|
/>
|
|
324
331
|
<span className="truncate">{sub.title}</span>
|
|
@@ -337,48 +344,63 @@ function CollapsibleNavItem({
|
|
|
337
344
|
export function SidebarNav({
|
|
338
345
|
items,
|
|
339
346
|
userName = "Anonymous User",
|
|
340
|
-
collapsed = false,
|
|
341
347
|
logo,
|
|
342
348
|
logoCollapsed,
|
|
343
349
|
metricsGroups,
|
|
344
350
|
onNavigate,
|
|
345
351
|
onLogout,
|
|
346
|
-
|
|
352
|
+
defaultLocked = false,
|
|
353
|
+
onLockedChange,
|
|
347
354
|
className,
|
|
348
355
|
}: SidebarNavProps) {
|
|
356
|
+
const [isLocked, setIsLocked] = React.useState(defaultLocked);
|
|
357
|
+
const [isHovered, setIsHovered] = React.useState(false);
|
|
358
|
+
|
|
359
|
+
// Sidebar is expanded when pinned OR when the user is hovering over it.
|
|
360
|
+
const isExpanded = isLocked || isHovered;
|
|
361
|
+
|
|
349
362
|
const [userMenuOpen, setUserMenuOpen] = React.useState(false);
|
|
350
363
|
const navScrollRef = React.useRef<HTMLDivElement>(null);
|
|
351
364
|
const expandedScrollRef = React.useRef(0);
|
|
352
365
|
|
|
366
|
+
const handleLockToggle = () => {
|
|
367
|
+
const next = !isLocked;
|
|
368
|
+
setIsLocked(next);
|
|
369
|
+
onLockedChange?.(next);
|
|
370
|
+
};
|
|
371
|
+
|
|
353
372
|
React.useEffect(() => {
|
|
354
|
-
if (
|
|
355
|
-
}, [
|
|
373
|
+
if (!isExpanded) setUserMenuOpen(false);
|
|
374
|
+
}, [isExpanded]);
|
|
356
375
|
|
|
357
376
|
// Preserve nav items scroll position across collapse/expand transitions.
|
|
358
377
|
// Cleanup saves scrollTop before the DOM changes; setup restores it when expanding.
|
|
359
378
|
React.useLayoutEffect(() => {
|
|
360
379
|
const nav = navScrollRef.current;
|
|
361
380
|
if (!nav) return;
|
|
362
|
-
if (
|
|
381
|
+
if (isExpanded) {
|
|
363
382
|
nav.scrollTop = expandedScrollRef.current;
|
|
364
383
|
}
|
|
365
384
|
return () => {
|
|
366
|
-
if (
|
|
385
|
+
if (isExpanded && nav) {
|
|
367
386
|
expandedScrollRef.current = nav.scrollTop;
|
|
368
387
|
}
|
|
369
388
|
};
|
|
370
|
-
}, [
|
|
389
|
+
}, [isExpanded]);
|
|
371
390
|
|
|
372
391
|
return (
|
|
373
392
|
<TooltipProvider>
|
|
374
393
|
<nav
|
|
375
394
|
data-slot="sidebar-nav"
|
|
376
|
-
data-
|
|
395
|
+
data-expanded={isExpanded}
|
|
396
|
+
data-locked={isLocked}
|
|
397
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
398
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
377
399
|
className={cn(
|
|
378
400
|
"flex h-full flex-col bg-brand-secondary text-brand-secondary-foreground",
|
|
379
401
|
"transition-all duration-200 ease-in-out",
|
|
380
|
-
|
|
381
|
-
className
|
|
402
|
+
isExpanded ? "w-[279px]" : "w-14",
|
|
403
|
+
className
|
|
382
404
|
)}
|
|
383
405
|
>
|
|
384
406
|
{/* Logo — crossfade between full and icon variant */}
|
|
@@ -390,7 +412,7 @@ export function SidebarNav({
|
|
|
390
412
|
alt="Logo"
|
|
391
413
|
className={cn(
|
|
392
414
|
"h-8 w-auto object-contain object-left px-5 transition-opacity duration-200",
|
|
393
|
-
|
|
415
|
+
!isExpanded ? "opacity-0" : "opacity-100"
|
|
394
416
|
)}
|
|
395
417
|
/>
|
|
396
418
|
)}
|
|
@@ -400,7 +422,7 @@ export function SidebarNav({
|
|
|
400
422
|
alt="Logo"
|
|
401
423
|
className={cn(
|
|
402
424
|
"absolute inset-y-0 left-0 right-0 m-auto h-8 w-8 object-contain transition-opacity duration-200",
|
|
403
|
-
|
|
425
|
+
!isExpanded ? "opacity-100" : "opacity-0"
|
|
404
426
|
)}
|
|
405
427
|
/>
|
|
406
428
|
)}
|
|
@@ -412,7 +434,7 @@ export function SidebarNav({
|
|
|
412
434
|
{/* Expanded — in flow (defines height), no transition (overlay handles it) */}
|
|
413
435
|
<div
|
|
414
436
|
className={cn(
|
|
415
|
-
|
|
437
|
+
!isExpanded ? "opacity-0 pointer-events-none" : "opacity-100"
|
|
416
438
|
)}
|
|
417
439
|
>
|
|
418
440
|
<Accordion
|
|
@@ -424,7 +446,7 @@ export function SidebarNav({
|
|
|
424
446
|
<AccordionPrimitive.Trigger
|
|
425
447
|
className={cn(
|
|
426
448
|
"group flex h-auto w-full items-center justify-start gap-3 px-5 py-5 text-base transition-colors",
|
|
427
|
-
"text-brand-secondary-foreground hover:bg-white/10"
|
|
449
|
+
"text-brand-secondary-foreground hover:bg-white/10"
|
|
428
450
|
)}
|
|
429
451
|
>
|
|
430
452
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center font-semibold text-xs bg-primary text-primary-foreground">
|
|
@@ -449,7 +471,7 @@ export function SidebarNav({
|
|
|
449
471
|
onClick={onLogout}
|
|
450
472
|
className={cn(
|
|
451
473
|
"h-auto w-full justify-start gap-3 px-5 py-3 text-base",
|
|
452
|
-
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground transition-colors"
|
|
474
|
+
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground transition-colors"
|
|
453
475
|
)}
|
|
454
476
|
>
|
|
455
477
|
<LogOut
|
|
@@ -466,11 +488,11 @@ export function SidebarNav({
|
|
|
466
488
|
</div>
|
|
467
489
|
|
|
468
490
|
{/* Collapsed — absolute overlay, centered avatar */}
|
|
469
|
-
<NavTooltip label={userName} collapsed={
|
|
491
|
+
<NavTooltip label={userName} collapsed={!isExpanded}>
|
|
470
492
|
<div
|
|
471
493
|
className={cn(
|
|
472
494
|
"absolute inset-0 flex items-center justify-center transition-opacity duration-200",
|
|
473
|
-
|
|
495
|
+
!isExpanded ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
474
496
|
)}
|
|
475
497
|
>
|
|
476
498
|
<div className="flex h-8 w-8 shrink-0 items-center justify-center font-semibold text-xs bg-primary text-primary-foreground">
|
|
@@ -480,10 +502,10 @@ export function SidebarNav({
|
|
|
480
502
|
</NavTooltip>
|
|
481
503
|
</div>
|
|
482
504
|
|
|
483
|
-
{/* Financial metrics — animated in/out with sidebar
|
|
505
|
+
{/* Financial metrics — animated in/out with sidebar expand to prevent nav items jumping */}
|
|
484
506
|
{!!metricsGroups?.length && (
|
|
485
507
|
<Accordion
|
|
486
|
-
value={
|
|
508
|
+
value={isExpanded ? ["metrics"] : []}
|
|
487
509
|
onValueChange={() => {}}
|
|
488
510
|
>
|
|
489
511
|
<AccordionItem className="border-none" value="metrics">
|
|
@@ -503,55 +525,54 @@ export function SidebarNav({
|
|
|
503
525
|
<CollapsibleNavItem
|
|
504
526
|
key={item.href}
|
|
505
527
|
item={item}
|
|
506
|
-
collapsed={
|
|
528
|
+
collapsed={!isExpanded}
|
|
507
529
|
onNavigate={onNavigate}
|
|
508
530
|
/>
|
|
509
531
|
) : (
|
|
510
532
|
<SidebarNavItemView
|
|
511
533
|
key={item.href}
|
|
512
534
|
item={item}
|
|
513
|
-
collapsed={
|
|
535
|
+
collapsed={!isExpanded}
|
|
514
536
|
onNavigate={onNavigate}
|
|
515
537
|
/>
|
|
516
|
-
)
|
|
538
|
+
)
|
|
517
539
|
)}
|
|
518
540
|
</div>
|
|
519
541
|
|
|
520
|
-
{/*
|
|
521
|
-
|
|
522
|
-
<
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
542
|
+
{/* Pin / Unpin toggle — always visible */}
|
|
543
|
+
<div className="mt-auto border-t border-white/15 bg-white/10">
|
|
544
|
+
<NavTooltip
|
|
545
|
+
label={isLocked ? "Unpin sidebar" : "Pin sidebar open"}
|
|
546
|
+
collapsed={!isExpanded}
|
|
547
|
+
>
|
|
548
|
+
<Button
|
|
549
|
+
type="button"
|
|
550
|
+
variant="ghost"
|
|
551
|
+
onClick={handleLockToggle}
|
|
552
|
+
className={cn(
|
|
553
|
+
"h-12 w-full items-center gap-3 py-3 transition-colors",
|
|
554
|
+
"text-brand-secondary-foreground/80 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
555
|
+
isExpanded ? "justify-start px-3" : "justify-center px-2",
|
|
556
|
+
isLocked && "text-primary"
|
|
557
|
+
)}
|
|
526
558
|
>
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
"
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
<PanelLeftClose
|
|
545
|
-
size={24}
|
|
546
|
-
strokeWidth={1.75}
|
|
547
|
-
className="shrink-0"
|
|
548
|
-
/>
|
|
549
|
-
)}
|
|
550
|
-
{!collapsed && <span className="text-sm">Collapse</span>}
|
|
551
|
-
</Button>
|
|
552
|
-
</NavTooltip>
|
|
553
|
-
</div>
|
|
554
|
-
)}
|
|
559
|
+
{isLocked ? (
|
|
560
|
+
<Pin size={24} strokeWidth={1.75} className="shrink-0" />
|
|
561
|
+
) : (
|
|
562
|
+
<PinOff
|
|
563
|
+
size={24}
|
|
564
|
+
strokeWidth={1.75}
|
|
565
|
+
className="shrink-0 opacity-60"
|
|
566
|
+
/>
|
|
567
|
+
)}
|
|
568
|
+
{isExpanded && (
|
|
569
|
+
<span className="text-sm">
|
|
570
|
+
{isLocked ? "Pinned" : "Pin sidebar"}
|
|
571
|
+
</span>
|
|
572
|
+
)}
|
|
573
|
+
</Button>
|
|
574
|
+
</NavTooltip>
|
|
575
|
+
</div>
|
|
555
576
|
</nav>
|
|
556
577
|
</TooltipProvider>
|
|
557
578
|
);
|