@wealthx/shadcn 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +193 -149
- package/CHANGELOG.md +28 -0
- package/dist/{chunk-4Y6R4WEC.mjs → chunk-2A5RRQGG.mjs} +9 -22
- package/dist/{chunk-TS2ZX2VS.mjs → chunk-2UM72RJ7.mjs} +11 -15
- package/dist/{chunk-A56YQQHG.mjs → chunk-3NCUZIFP.mjs} +2 -2
- package/dist/chunk-3OYFOX3X.mjs +79 -0
- package/dist/{chunk-RP3SQYA3.mjs → chunk-3TTACBDP.mjs} +9 -4
- package/dist/chunk-4GAWMKMI.mjs +710 -0
- package/dist/{chunk-VGSESELX.mjs → chunk-5FQIKDKP.mjs} +5 -5
- package/dist/{chunk-K3JYD4IU.mjs → chunk-5IS7G74I.mjs} +11 -4
- package/dist/chunk-6AW4KJHE.mjs +235 -0
- package/dist/chunk-6CR5N2JW.mjs +302 -0
- package/dist/{chunk-XIRTEFKH.mjs → chunk-6DZEXFNB.mjs} +36 -8
- package/dist/chunk-6O6KD7CE.mjs +271 -0
- package/dist/chunk-7PV3IWCN.mjs +33 -0
- package/dist/{chunk-SPJ5KXW7.mjs → chunk-7S5AESZO.mjs} +5 -5
- package/dist/{chunk-RYCLWMZ7.mjs → chunk-ABFDMHOR.mjs} +9 -7
- package/dist/{chunk-SWGT756Z.mjs → chunk-AMQZRHEZ.mjs} +10 -4
- package/dist/{chunk-WAZD7NFU.mjs → chunk-BKNFWEH2.mjs} +6 -6
- package/dist/{chunk-CLIN5525.mjs → chunk-C7CQJNMR.mjs} +1 -1
- package/dist/{chunk-D4ILTPOG.mjs → chunk-CFMQP5QS.mjs} +5 -4
- package/dist/{chunk-VPBN3WOO.mjs → chunk-DGHAXJBN.mjs} +9 -7
- package/dist/chunk-DOEO3CDL.mjs +27 -0
- package/dist/{chunk-5MEWU56Z.mjs → chunk-DUJTAXMH.mjs} +11 -6
- package/dist/{chunk-GGM2UYGG.mjs → chunk-EBXQWIYG.mjs} +10 -4
- package/dist/chunk-EWRB4PAD.mjs +468 -0
- package/dist/{chunk-ZSHYDDRB.mjs → chunk-FAKPBKLT.mjs} +6 -2
- package/dist/{chunk-A6AAWBPF.mjs → chunk-GHC7LLUX.mjs} +13 -4
- package/dist/chunk-HBZLGDIN.mjs +507 -0
- package/dist/{chunk-SIZMLSRU.mjs → chunk-HISNT2MG.mjs} +8 -6
- package/dist/{chunk-CGH4DRNG.mjs → chunk-HVY6KCCF.mjs} +10 -7
- package/dist/chunk-I3RZS7V2.mjs +136 -0
- package/dist/chunk-IAE3F7DR.mjs +1962 -0
- package/dist/{chunk-UT4KJR7V.mjs → chunk-IHMFS7NZ.mjs} +35 -74
- package/dist/{chunk-PCPLO5HT.mjs → chunk-IOJRDS6V.mjs} +96 -14
- package/dist/{chunk-LHYCMLVA.mjs → chunk-JKGDCQTZ.mjs} +11 -4
- package/dist/{chunk-H45TKD34.mjs → chunk-JMHR3YGZ.mjs} +1 -1
- package/dist/{chunk-4MN6UQHG.mjs → chunk-K5A5L6T2.mjs} +17 -39
- package/dist/chunk-LV35NGVG.mjs +272 -0
- package/dist/{chunk-FZIXGLMV.mjs → chunk-M3FV7LOK.mjs} +5 -12
- package/dist/{chunk-FMAXJ2SI.mjs → chunk-MBON7YRJ.mjs} +1 -1
- package/dist/chunk-MIZQHHUO.mjs +441 -0
- package/dist/chunk-MLNEWRWV.mjs +449 -0
- package/dist/chunk-MN5NYQCL.mjs +29 -0
- package/dist/chunk-NL3ZO62D.mjs +31 -0
- package/dist/{chunk-Q76O3RIQ.mjs → chunk-NMOI6CQD.mjs} +1 -1
- package/dist/{chunk-P6AM5V7O.mjs → chunk-OODBHKG7.mjs} +1 -1
- package/dist/chunk-PBL4OQV2.mjs +283 -0
- package/dist/{chunk-Y4QFWRNR.mjs → chunk-PU4YZQXV.mjs} +17 -18
- package/dist/chunk-Q2BGOAMG.mjs +202 -0
- package/dist/chunk-QMY3AZJH.mjs +80 -0
- package/dist/{chunk-BL3DXM2X.mjs → chunk-QZ4RE6NA.mjs} +11 -4
- package/dist/{chunk-VACKZOMY.mjs → chunk-R3VSPKNP.mjs} +3 -3
- package/dist/{chunk-OPNQAVVH.mjs → chunk-RJI6GKVF.mjs} +8 -6
- package/dist/{chunk-WG6JGJXB.mjs → chunk-T4BJLT57.mjs} +1 -1
- package/dist/chunk-UMTOX62O.mjs +415 -0
- package/dist/{chunk-7MMXNK3C.mjs → chunk-VLARHE5V.mjs} +8 -6
- package/dist/{chunk-2I5S2AMY.mjs → chunk-XREGSKX3.mjs} +2 -2
- package/dist/{chunk-JNQORUPP.mjs → chunk-YJG55G2H.mjs} +14 -11
- package/dist/components/ui/add-column-modal.js +42 -14
- package/dist/components/ui/add-column-modal.mjs +5 -5
- package/dist/components/ui/add-lead-modal.js +42 -11
- package/dist/components/ui/add-lead-modal.mjs +3 -3
- package/dist/components/ui/advisor-card.js +530 -0
- package/dist/components/ui/advisor-card.mjs +15 -0
- package/dist/components/ui/ai-assistant-drawer.js +11 -10
- package/dist/components/ui/ai-assistant-drawer.mjs +3 -3
- package/dist/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog.mjs +2 -2
- package/dist/components/ui/appointment-action-dialogs.js +1160 -0
- package/dist/components/ui/appointment-action-dialogs.mjs +23 -0
- package/dist/components/ui/appointment-availability-settings.js +1590 -0
- package/dist/components/ui/appointment-availability-settings.mjs +23 -0
- package/dist/components/ui/appointment-book-dialog.js +1744 -0
- package/dist/components/ui/appointment-book-dialog.mjs +27 -0
- package/dist/components/ui/appointment-calendar-view.js +833 -0
- package/dist/components/ui/appointment-calendar-view.mjs +14 -0
- package/dist/components/ui/appointment-detail-sheet.js +1517 -0
- package/dist/components/ui/appointment-detail-sheet.mjs +24 -0
- package/dist/components/ui/appointment-gmail-connect.js +467 -0
- package/dist/components/ui/appointment-gmail-connect.mjs +14 -0
- package/dist/components/ui/appointment-mini-card.js +345 -0
- package/dist/components/ui/appointment-mini-card.mjs +11 -0
- package/dist/components/ui/appointment-time-slot-picker.js +311 -0
- package/dist/components/ui/appointment-time-slot-picker.mjs +13 -0
- package/dist/components/ui/appointment-upcoming-card.js +1268 -0
- package/dist/components/ui/appointment-upcoming-card.mjs +21 -0
- package/dist/components/ui/backoffice-alert-history-chart.js +11 -5
- package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -4
- package/dist/components/ui/backoffice-alerts-chart.js +786 -0
- package/dist/components/ui/backoffice-alerts-chart.mjs +19 -0
- package/dist/components/ui/backoffice-connections-chart.js +817 -0
- package/dist/components/ui/backoffice-connections-chart.mjs +19 -0
- package/dist/components/ui/backoffice-contact-history-chart.js +11 -5
- package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -4
- package/dist/components/ui/badge.js +6 -6
- package/dist/components/ui/badge.mjs +1 -1
- package/dist/components/ui/borrowing-capacity-line-chart.js +30 -21
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -4
- package/dist/components/ui/button.js +2 -2
- package/dist/components/ui/button.mjs +1 -1
- package/dist/components/ui/calendar.js +2 -2
- package/dist/components/ui/calendar.mjs +2 -2
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/card.mjs +1 -1
- package/dist/components/ui/cash-balance-line-chart.js +31 -23
- package/dist/components/ui/cash-balance-line-chart.mjs +5 -4
- package/dist/components/ui/cashflow-bar-chart.js +12 -5
- package/dist/components/ui/cashflow-bar-chart.mjs +5 -4
- package/dist/components/ui/chip.js +97 -18
- package/dist/components/ui/chip.mjs +3 -2
- package/dist/components/ui/color-picker.js +158 -28
- package/dist/components/ui/color-picker.mjs +3 -1
- package/dist/components/ui/data-table.js +140 -119
- package/dist/components/ui/data-table.mjs +3 -2
- package/dist/components/ui/date-picker.js +48 -27
- package/dist/components/ui/date-picker.mjs +4 -3
- package/dist/components/ui/dialog.js +37 -9
- package/dist/components/ui/dialog.mjs +2 -2
- package/dist/components/ui/expense-bar-chart.js +12 -5
- package/dist/components/ui/expense-bar-chart.mjs +5 -4
- package/dist/components/ui/field.mjs +2 -2
- package/dist/components/ui/financial-cards.js +322 -155
- package/dist/components/ui/financial-cards.mjs +5 -3
- package/dist/components/ui/financial-drawers.js +2 -2
- package/dist/components/ui/financial-drawers.mjs +3 -3
- package/dist/components/ui/financial-sections.js +14 -10
- package/dist/components/ui/financial-sections.mjs +6 -5
- package/dist/components/ui/income-bar-chart.js +12 -5
- package/dist/components/ui/income-bar-chart.mjs +5 -4
- package/dist/components/ui/input-group.js +2 -2
- package/dist/components/ui/input-group.mjs +2 -2
- package/dist/components/ui/kanban-column.js +52 -44
- package/dist/components/ui/kanban-column.mjs +7 -5
- package/dist/components/ui/opportunity-card.js +52 -44
- package/dist/components/ui/opportunity-card.mjs +6 -4
- package/dist/components/ui/opportunity-edit-modals.js +1367 -1263
- package/dist/components/ui/opportunity-edit-modals.mjs +8 -8
- package/dist/components/ui/opportunity-summary-tab.js +2744 -2157
- package/dist/components/ui/opportunity-summary-tab.mjs +14 -14
- package/dist/components/ui/page-header.js +92 -0
- package/dist/components/ui/page-header.mjs +8 -0
- package/dist/components/ui/page-top-bar.js +88 -0
- package/dist/components/ui/page-top-bar.mjs +8 -0
- package/dist/components/ui/pagination.js +303 -19
- package/dist/components/ui/pagination.mjs +11 -4
- package/dist/components/ui/pipeline-board.js +205 -191
- package/dist/components/ui/pipeline-board.mjs +9 -7
- package/dist/components/ui/pipeline-dialogs.js +114 -65
- package/dist/components/ui/pipeline-dialogs.mjs +7 -6
- package/dist/components/ui/pipeline-primitives.js +6 -6
- package/dist/components/ui/pipeline-primitives.mjs +2 -2
- package/dist/components/ui/property-cashflow-doughnut-chart.js +14 -12
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-debt-equity-doughnut-chart.js +14 -12
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-mobile-estimate-line-chart.js +16 -14
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -4
- package/dist/components/ui/sidebar-nav.js +426 -191
- package/dist/components/ui/sidebar-nav.mjs +5 -1
- package/dist/components/ui/stage-timeline.js +6 -6
- package/dist/components/ui/stage-timeline.mjs +3 -3
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -4
- package/dist/components/ui/transactions-income-expense-bar-chart.js +28 -12
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -4
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -4
- package/dist/index.js +12258 -8611
- package/dist/index.mjs +258 -190
- package/dist/styles.css +1 -1
- package/package.json +71 -1
- package/src/components/index.tsx +115 -9
- package/src/components/ui/add-column-modal.tsx +7 -7
- package/src/components/ui/add-lead-modal.tsx +6 -3
- package/src/components/ui/advisor-card.tsx +284 -0
- package/src/components/ui/ai-assistant-drawer.tsx +4 -3
- package/src/components/ui/appointment-action-dialogs.tsx +297 -0
- package/src/components/ui/appointment-availability-settings.tsx +645 -0
- package/src/components/ui/appointment-book-dialog.tsx +618 -0
- package/src/components/ui/appointment-calendar-view.tsx +510 -0
- package/src/components/ui/appointment-detail-sheet.tsx +415 -0
- package/src/components/ui/appointment-gmail-connect.tsx +188 -0
- package/src/components/ui/appointment-mini-card.tsx +104 -0
- package/src/components/ui/appointment-time-slot-picker.tsx +123 -0
- package/src/components/ui/appointment-upcoming-card.tsx +635 -0
- package/src/components/ui/backoffice-alert-history-chart.tsx +10 -2
- package/src/components/ui/backoffice-alerts-chart.tsx +312 -0
- package/src/components/ui/backoffice-connections-chart.tsx +339 -0
- package/src/components/ui/backoffice-contact-history-chart.tsx +10 -2
- package/src/components/ui/badge.tsx +12 -6
- package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -11
- package/src/components/ui/button.tsx +2 -2
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/cash-balance-line-chart.tsx +4 -23
- package/src/components/ui/cashflow-bar-chart.tsx +9 -2
- package/src/components/ui/chart-shared.tsx +4 -11
- package/src/components/ui/chip.tsx +23 -19
- package/src/components/ui/color-picker.tsx +4 -2
- package/src/components/ui/data-table.tsx +28 -74
- package/src/components/ui/date-picker.tsx +42 -37
- package/src/components/ui/dialog.tsx +72 -6
- package/src/components/ui/expense-bar-chart.tsx +11 -2
- package/src/components/ui/financial-cards.tsx +99 -10
- package/src/components/ui/income-bar-chart.tsx +11 -2
- package/src/components/ui/opportunity-card.tsx +10 -39
- package/src/components/ui/opportunity-edit-modals.tsx +98 -36
- package/src/components/ui/opportunity-summary-tab.tsx +548 -232
- package/src/components/ui/page-header.tsx +57 -0
- package/src/components/ui/page-top-bar.tsx +48 -0
- package/src/components/ui/pagination.tsx +171 -22
- package/src/components/ui/pipeline-board.tsx +12 -5
- package/src/components/ui/property-cashflow-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-debt-equity-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-mobile-estimate-line-chart.tsx +3 -1
- package/src/components/ui/sidebar-nav.tsx +213 -157
- package/src/components/ui/transactions-expense-categories-doughnut-chart.tsx +3 -1
- package/src/components/ui/transactions-income-expense-bar-chart.tsx +12 -9
- package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +3 -1
- package/src/lib/format-currency.ts +44 -0
- package/src/lib/format-date.ts +50 -0
- package/src/lib/opportunity-constants.ts +12 -0
- package/src/styles/globals.css +17 -15
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +14 -0
- package/dist/chunk-S4QRUQNW.mjs +0 -475
- package/dist/chunk-URGMJAE3.mjs +0 -1885
- package/dist/chunk-WNGWBVLV.mjs +0 -148
- package/dist/chunk-ZRSDX6OW.mjs +0 -385
- package/dist/{chunk-LLVQKSU3.mjs → chunk-GD4BJDJR.mjs} +3 -3
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
ChartLegendItem,
|
|
26
26
|
formatAbbrev,
|
|
27
27
|
} from "./chart-shared";
|
|
28
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
28
29
|
|
|
29
30
|
ChartJS.register(
|
|
30
31
|
CategoryScale,
|
|
@@ -123,14 +124,6 @@ const DASH_PATTERN: number[] = [6, 4];
|
|
|
123
124
|
// Helpers
|
|
124
125
|
// ---------------------------------------------------------------------------
|
|
125
126
|
|
|
126
|
-
function formatCurrencyFull(dollars: number): string {
|
|
127
|
-
return new Intl.NumberFormat("en-AU", {
|
|
128
|
-
style: "currency",
|
|
129
|
-
currency: "AUD",
|
|
130
|
-
maximumFractionDigits: 0,
|
|
131
|
-
}).format(dollars);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
127
|
/** "2025-01" or "2025-01-15" → "Jan '25" for x-axis ticks */
|
|
135
128
|
function formatDateLabel(iso: string): string {
|
|
136
129
|
const d = new Date(`${iso.slice(0, 7)}-01T00:00:00`);
|
|
@@ -246,7 +239,7 @@ export function BorrowingCapacityLineChart({
|
|
|
246
239
|
},
|
|
247
240
|
label: (ctx) => {
|
|
248
241
|
const dollars = ctx.parsed.y ?? 0;
|
|
249
|
-
return ` ${ctx.dataset.label}: ${
|
|
242
|
+
return ` ${ctx.dataset.label}: ${formatCurrency(dollars)}`;
|
|
250
243
|
},
|
|
251
244
|
},
|
|
252
245
|
},
|
|
@@ -319,12 +312,12 @@ export function BorrowingCapacityLineChart({
|
|
|
319
312
|
>
|
|
320
313
|
<CardHeader className="px-3 sm:px-6">
|
|
321
314
|
<div className="flex items-start justify-between gap-4">
|
|
322
|
-
<CardTitle className="text-
|
|
315
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
323
316
|
{title}
|
|
324
317
|
</CardTitle>
|
|
325
318
|
{kpiValue != null && (
|
|
326
319
|
<span className="shrink-0 text-xl font-bold tabular-nums">
|
|
327
|
-
{
|
|
320
|
+
{formatCurrency(kpiValue / 100)}
|
|
328
321
|
</span>
|
|
329
322
|
)}
|
|
330
323
|
</div>
|
|
@@ -23,13 +23,13 @@ const buttonVariants = cva(
|
|
|
23
23
|
destructive:
|
|
24
24
|
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
25
25
|
outline:
|
|
26
|
-
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
26
|
+
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground focus-visible:ring-border/50 dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
27
27
|
"outline-primary":
|
|
28
28
|
"border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50",
|
|
29
29
|
"outline-secondary":
|
|
30
30
|
"border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:ring-brand-secondary/30",
|
|
31
31
|
ghost:
|
|
32
|
-
"hover:bg-accent hover:text-accent-foreground hover:shadow-xs dark:hover:bg-accent/50",
|
|
32
|
+
"hover:bg-accent hover:text-accent-foreground hover:shadow-xs focus-visible:ring-border/50 dark:hover:bg-accent/50",
|
|
33
33
|
link: "text-primary underline-offset-4 hover:underline",
|
|
34
34
|
},
|
|
35
35
|
size: {
|
|
@@ -23,7 +23,7 @@ function CardHeader({ className, ...props }: CardHeaderProps): ReactElement {
|
|
|
23
23
|
return (
|
|
24
24
|
<div
|
|
25
25
|
className={cn(
|
|
26
|
-
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-
|
|
26
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-center gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
27
27
|
className,
|
|
28
28
|
)}
|
|
29
29
|
data-slot="card-header"
|
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
FALLBACK_PRIMARY,
|
|
22
22
|
FALLBACK_BG,
|
|
23
23
|
ChartLegendItem,
|
|
24
|
+
formatAbbrev,
|
|
24
25
|
} from "./chart-shared";
|
|
26
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
25
27
|
|
|
26
28
|
ChartJS.register(
|
|
27
29
|
CategoryScale,
|
|
@@ -36,27 +38,6 @@ ChartJS.register(
|
|
|
36
38
|
// Helpers
|
|
37
39
|
// ---------------------------------------------------------------------------
|
|
38
40
|
|
|
39
|
-
/** Abbreviate a dollar value: $1.2K, $4.5M, $1.1B */
|
|
40
|
-
function formatAbbrev(value: number): string {
|
|
41
|
-
const abs = Math.abs(value);
|
|
42
|
-
const sign = value < 0 ? "-" : "";
|
|
43
|
-
if (abs >= 1_000_000_000)
|
|
44
|
-
return `${sign}$${(abs / 1_000_000_000).toFixed(1)}B`;
|
|
45
|
-
if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(1)}M`;
|
|
46
|
-
if (abs >= 1_000) return `${sign}$${(abs / 1_000).toFixed(1)}K`;
|
|
47
|
-
return `${sign}$${abs.toFixed(0)}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Format a balance value for prominent display: $12,345.67 */
|
|
51
|
-
function formatBalanceFull(value: number): string {
|
|
52
|
-
const abs = Math.abs(value);
|
|
53
|
-
const sign = value < 0 ? "-" : "";
|
|
54
|
-
return `${sign}$${abs.toLocaleString(undefined, {
|
|
55
|
-
minimumFractionDigits: 2,
|
|
56
|
-
maximumFractionDigits: 2,
|
|
57
|
-
})}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
41
|
/** Format ISO date string to "MMM dd" label e.g. "Jan 15" */
|
|
61
42
|
function formatDateLabel(iso: string): string {
|
|
62
43
|
const d = new Date(iso);
|
|
@@ -244,12 +225,12 @@ export function CashBalanceLineChart({
|
|
|
244
225
|
>
|
|
245
226
|
<CardHeader className="px-3 sm:px-6">
|
|
246
227
|
<div className="flex flex-col gap-0.5">
|
|
247
|
-
<CardTitle className="text-
|
|
228
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
248
229
|
{title}
|
|
249
230
|
</CardTitle>
|
|
250
231
|
{showBalanceValue && latestValue !== null && (
|
|
251
232
|
<p className="text-2xl font-bold tabular-nums leading-tight">
|
|
252
|
-
{
|
|
233
|
+
{formatCurrency(latestValue, { decimals: 2 })}
|
|
253
234
|
</p>
|
|
254
235
|
)}
|
|
255
236
|
</div>
|
|
@@ -25,7 +25,14 @@ import {
|
|
|
25
25
|
ChartPeriodButton,
|
|
26
26
|
} from "./chart-shared";
|
|
27
27
|
|
|
28
|
-
ChartJS.register(
|
|
28
|
+
ChartJS.register(
|
|
29
|
+
CategoryScale,
|
|
30
|
+
LinearScale,
|
|
31
|
+
BarController,
|
|
32
|
+
BarElement,
|
|
33
|
+
Tooltip,
|
|
34
|
+
Legend,
|
|
35
|
+
);
|
|
29
36
|
|
|
30
37
|
// ---------------------------------------------------------------------------
|
|
31
38
|
// Types
|
|
@@ -313,7 +320,7 @@ export function CashflowBarChart({
|
|
|
313
320
|
style={{ maxWidth: width, fontFamily }}
|
|
314
321
|
>
|
|
315
322
|
<CardHeader className="px-3 sm:px-6">
|
|
316
|
-
<CardTitle className="text-
|
|
323
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
317
324
|
{title}
|
|
318
325
|
</CardTitle>
|
|
319
326
|
{showPeriodSelector && (
|
|
@@ -90,18 +90,11 @@ export const SEVERITY_COLORS = {
|
|
|
90
90
|
} as const;
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
93
|
+
* Re-export abbreviated currency formatter from shared lib.
|
|
94
|
+
* Kept as `formatAbbrev` for backward compatibility with existing chart consumers.
|
|
95
95
|
*/
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const sign = value < 0 ? "-" : "";
|
|
99
|
-
if (abs >= 1_000_000_000)
|
|
100
|
-
return `${sign}$${(abs / 1_000_000_000).toFixed(1)}B`;
|
|
101
|
-
if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(1)}M`;
|
|
102
|
-
if (abs >= 1_000) return `${sign}$${(abs / 1_000).toFixed(0)}K`;
|
|
103
|
-
return `${sign}$${abs.toFixed(0)}`;
|
|
104
|
-
}
|
|
96
|
+
import { formatCurrencyAbbrev as formatAbbrev } from "@/lib/format-currency";
|
|
97
|
+
export { formatAbbrev };
|
|
105
98
|
|
|
106
99
|
// ---------------------------------------------------------------------------
|
|
107
100
|
// Tooltip date format
|
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
// <Chip>Label</Chip>
|
|
8
8
|
// <Chip onRemove={() => handleRemove(id)}>Label</Chip>
|
|
9
9
|
// <Chip variant="outline" disabled onRemove={...}>Label</Chip>
|
|
10
|
-
import { type ReactElement } from "react"
|
|
11
|
-
import * as React from "react"
|
|
12
|
-
import { X } from "lucide-react"
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
10
|
+
import { type ReactElement } from "react";
|
|
11
|
+
import * as React from "react";
|
|
12
|
+
import { X } from "lucide-react";
|
|
13
|
+
import { Button } from "./button";
|
|
14
|
+
import type { VariantProps } from "class-variance-authority";
|
|
15
|
+
import { cn } from "@/lib/utils";
|
|
16
|
+
import { badgeVariants } from "@/components/ui/badge";
|
|
16
17
|
|
|
17
18
|
export interface ChipProps
|
|
18
|
-
extends React.ComponentProps<"span">,
|
|
19
|
-
VariantProps<typeof badgeVariants> {
|
|
19
|
+
extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {
|
|
20
20
|
/** When provided, renders a dismiss (×) button inside the chip. */
|
|
21
|
-
onRemove?: () => void
|
|
22
|
-
disabled?: boolean
|
|
21
|
+
onRemove?: () => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function Chip({
|
|
@@ -38,28 +38,32 @@ function Chip({
|
|
|
38
38
|
// extra right padding only when dismiss button is present
|
|
39
39
|
onRemove && "pr-1",
|
|
40
40
|
disabled && "pointer-events-none opacity-50",
|
|
41
|
-
className
|
|
41
|
+
className,
|
|
42
42
|
)}
|
|
43
43
|
data-slot="chip"
|
|
44
44
|
data-variant={variant}
|
|
45
45
|
{...props}
|
|
46
46
|
>
|
|
47
47
|
{children}
|
|
48
|
-
{onRemove ?
|
|
48
|
+
{onRemove ? (
|
|
49
|
+
<Button
|
|
50
|
+
type="button"
|
|
51
|
+
variant="ghost"
|
|
52
|
+
size="icon"
|
|
49
53
|
aria-label="Remove"
|
|
50
|
-
className="ml-0.5
|
|
54
|
+
className="ml-0.5 size-4 shrink-0 rounded-full p-0.5 opacity-60 hover:opacity-100 disabled:pointer-events-none"
|
|
51
55
|
data-slot="chip-remove"
|
|
52
56
|
disabled={disabled}
|
|
53
57
|
onClick={(e) => {
|
|
54
|
-
e.stopPropagation()
|
|
55
|
-
onRemove()
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
onRemove();
|
|
56
60
|
}}
|
|
57
|
-
type="button"
|
|
58
61
|
>
|
|
59
62
|
<X className="size-3" />
|
|
60
|
-
</
|
|
63
|
+
</Button>
|
|
64
|
+
) : null}
|
|
61
65
|
</span>
|
|
62
|
-
)
|
|
66
|
+
);
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
export { Chip }
|
|
69
|
+
export { Chip };
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
PopoverTrigger,
|
|
7
7
|
} from "@/components/ui/popover";
|
|
8
8
|
import { Input } from "@/components/ui/input";
|
|
9
|
+
import { Button } from "@/components/ui/button";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* ColorPicker — WealthX Design System
|
|
@@ -93,14 +94,15 @@ function ColorSwatch({
|
|
|
93
94
|
className,
|
|
94
95
|
}: ColorSwatchProps) {
|
|
95
96
|
return (
|
|
96
|
-
<
|
|
97
|
+
<Button
|
|
97
98
|
type="button"
|
|
99
|
+
variant="ghost"
|
|
98
100
|
title={color}
|
|
99
101
|
aria-label={`Select color ${color}`}
|
|
100
102
|
aria-pressed={selected}
|
|
101
103
|
onClick={() => onClick?.(color)}
|
|
102
104
|
className={cn(
|
|
103
|
-
"relative shrink-0 transition-all outline-none shadow-[inset_0_0_0_1px_rgba(0,0,0,0.12)]",
|
|
105
|
+
"relative shrink-0 p-0 transition-all outline-none shadow-[inset_0_0_0_1px_rgba(0,0,0,0.12)]",
|
|
104
106
|
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
105
107
|
size === "md" ? "size-7" : "size-5",
|
|
106
108
|
selected &&
|
|
@@ -35,10 +35,6 @@ import {
|
|
|
35
35
|
ArrowUpDown,
|
|
36
36
|
ArrowUp,
|
|
37
37
|
ArrowDown,
|
|
38
|
-
ChevronLeftIcon,
|
|
39
|
-
ChevronRightIcon,
|
|
40
|
-
ChevronsLeftIcon,
|
|
41
|
-
ChevronsRightIcon,
|
|
42
38
|
SlidersHorizontal,
|
|
43
39
|
} from "lucide-react";
|
|
44
40
|
import { cn } from "@/lib/utils";
|
|
@@ -60,6 +56,7 @@ import {
|
|
|
60
56
|
SelectTrigger,
|
|
61
57
|
SelectValue,
|
|
62
58
|
} from "@/components/ui/select";
|
|
59
|
+
import { PaginationNavButtons } from "@/components/ui/pagination";
|
|
63
60
|
import {
|
|
64
61
|
DropdownMenu,
|
|
65
62
|
DropdownMenuCheckboxItem,
|
|
@@ -291,32 +288,30 @@ function DataTablePagination<TData>({
|
|
|
291
288
|
}): ReactElement {
|
|
292
289
|
return (
|
|
293
290
|
<div
|
|
294
|
-
className="flex items-center
|
|
291
|
+
className="flex items-center gap-4 py-4"
|
|
295
292
|
data-slot="data-table-pagination"
|
|
296
293
|
>
|
|
297
|
-
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
</>
|
|
304
|
-
)}
|
|
305
|
-
</p>
|
|
294
|
+
{table.getFilteredSelectedRowModel().rows.length > 0 && (
|
|
295
|
+
<span className="text-body-small text-muted-foreground">
|
|
296
|
+
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
|
297
|
+
{table.getFilteredRowModel().rows.length} row(s) selected.
|
|
298
|
+
</span>
|
|
299
|
+
)}
|
|
306
300
|
|
|
307
|
-
<div className="flex items-center gap-6">
|
|
308
|
-
{/* Page size selector */}
|
|
301
|
+
<div className="ml-auto flex items-center gap-6">
|
|
309
302
|
<div className="flex items-center gap-2">
|
|
310
|
-
<
|
|
303
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
311
304
|
Rows per page
|
|
312
|
-
</
|
|
305
|
+
</span>
|
|
313
306
|
<Select
|
|
314
|
-
onValueChange={(value) =>
|
|
315
|
-
table.setPageSize(Number(value));
|
|
316
|
-
}}
|
|
307
|
+
onValueChange={(value) => table.setPageSize(Number(value))}
|
|
317
308
|
value={`${table.getState().pagination.pageSize}`}
|
|
318
309
|
>
|
|
319
|
-
<SelectTrigger
|
|
310
|
+
<SelectTrigger
|
|
311
|
+
aria-label="Rows per page"
|
|
312
|
+
className="w-[70px]"
|
|
313
|
+
size="sm"
|
|
314
|
+
>
|
|
320
315
|
<SelectValue
|
|
321
316
|
placeholder={`${table.getState().pagination.pageSize}`}
|
|
322
317
|
/>
|
|
@@ -331,59 +326,19 @@ function DataTablePagination<TData>({
|
|
|
331
326
|
</Select>
|
|
332
327
|
</div>
|
|
333
328
|
|
|
334
|
-
|
|
335
|
-
<p className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
329
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
336
330
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
|
337
331
|
{table.getPageCount()}
|
|
338
|
-
</
|
|
332
|
+
</span>
|
|
339
333
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
size="icon-sm"
|
|
349
|
-
variant="outline"
|
|
350
|
-
>
|
|
351
|
-
<ChevronsLeftIcon className="size-4" />
|
|
352
|
-
</Button>
|
|
353
|
-
<Button
|
|
354
|
-
aria-label="Go to previous page"
|
|
355
|
-
disabled={!table.getCanPreviousPage()}
|
|
356
|
-
onClick={() => {
|
|
357
|
-
table.previousPage();
|
|
358
|
-
}}
|
|
359
|
-
size="icon-sm"
|
|
360
|
-
variant="outline"
|
|
361
|
-
>
|
|
362
|
-
<ChevronLeftIcon className="size-4" />
|
|
363
|
-
</Button>
|
|
364
|
-
<Button
|
|
365
|
-
aria-label="Go to next page"
|
|
366
|
-
disabled={!table.getCanNextPage()}
|
|
367
|
-
onClick={() => {
|
|
368
|
-
table.nextPage();
|
|
369
|
-
}}
|
|
370
|
-
size="icon-sm"
|
|
371
|
-
variant="outline"
|
|
372
|
-
>
|
|
373
|
-
<ChevronRightIcon className="size-4" />
|
|
374
|
-
</Button>
|
|
375
|
-
<Button
|
|
376
|
-
aria-label="Go to last page"
|
|
377
|
-
disabled={!table.getCanNextPage()}
|
|
378
|
-
onClick={() => {
|
|
379
|
-
table.setPageIndex(table.getPageCount() - 1);
|
|
380
|
-
}}
|
|
381
|
-
size="icon-sm"
|
|
382
|
-
variant="outline"
|
|
383
|
-
>
|
|
384
|
-
<ChevronsRightIcon className="size-4" />
|
|
385
|
-
</Button>
|
|
386
|
-
</div>
|
|
334
|
+
<PaginationNavButtons
|
|
335
|
+
hasNext={table.getCanNextPage()}
|
|
336
|
+
hasPrev={table.getCanPreviousPage()}
|
|
337
|
+
onFirst={() => table.setPageIndex(0)}
|
|
338
|
+
onLast={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
339
|
+
onNext={() => table.nextPage()}
|
|
340
|
+
onPrev={() => table.previousPage()}
|
|
341
|
+
/>
|
|
387
342
|
</div>
|
|
388
343
|
</div>
|
|
389
344
|
);
|
|
@@ -494,8 +449,7 @@ function DataTable<TData, TValue>({
|
|
|
494
449
|
onColumnFiltersChange: (updater) => {
|
|
495
450
|
const next =
|
|
496
451
|
typeof updater === "function" ? updater(columnFilters) : updater;
|
|
497
|
-
if (controlledColumnFilters === undefined)
|
|
498
|
-
setInternalColumnFilters(next);
|
|
452
|
+
if (controlledColumnFilters === undefined) setInternalColumnFilters(next);
|
|
499
453
|
onColumnFiltersChangeProp?.(next);
|
|
500
454
|
},
|
|
501
455
|
onPaginationChange: (updater) => {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { type ReactElement } from "react"
|
|
2
|
-
import * as React from "react"
|
|
3
|
-
import { format } from "date-fns"
|
|
4
|
-
import { CalendarIcon } from "lucide-react"
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
import { Button } from "@/components/ui/button"
|
|
7
|
-
import {
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { format } from "date-fns";
|
|
4
|
+
import { CalendarIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Input } from "@/components/ui/input";
|
|
8
|
+
import { Calendar } from "@/components/ui/calendar";
|
|
8
9
|
import {
|
|
9
10
|
Popover,
|
|
10
11
|
PopoverContent,
|
|
11
12
|
PopoverTrigger,
|
|
12
|
-
} from "@/components/ui/popover"
|
|
13
|
+
} from "@/components/ui/popover";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* DatePicker — WealthX Design System
|
|
@@ -22,18 +23,18 @@ import {
|
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
25
|
export interface DatePickerProps {
|
|
25
|
-
value?: Date
|
|
26
|
-
onChange?: (date: Date | undefined) => void
|
|
27
|
-
placeholder?: string
|
|
26
|
+
value?: Date;
|
|
27
|
+
onChange?: (date: Date | undefined) => void;
|
|
28
|
+
placeholder?: string;
|
|
28
29
|
/** Show a time input below the calendar */
|
|
29
|
-
showTimePicker?: boolean
|
|
30
|
-
disabled?: boolean
|
|
31
|
-
className?: string
|
|
30
|
+
showTimePicker?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
className?: string;
|
|
32
33
|
/** Passed through to Calendar (e.g. fromYear, toYear, captionLayout) */
|
|
33
34
|
calendarProps?: Omit<
|
|
34
35
|
React.ComponentProps<typeof Calendar>,
|
|
35
36
|
"mode" | "selected" | "onSelect"
|
|
36
|
-
|
|
37
|
+
>;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
function DatePicker({
|
|
@@ -45,37 +46,37 @@ function DatePicker({
|
|
|
45
46
|
className,
|
|
46
47
|
calendarProps,
|
|
47
48
|
}: DatePickerProps): ReactElement {
|
|
48
|
-
const [open, setOpen] = React.useState(false)
|
|
49
|
+
const [open, setOpen] = React.useState(false);
|
|
49
50
|
|
|
50
51
|
function handleDaySelect(day: Date | undefined): void {
|
|
51
52
|
if (!day) {
|
|
52
|
-
onChange?.(undefined)
|
|
53
|
-
return
|
|
53
|
+
onChange?.(undefined);
|
|
54
|
+
return;
|
|
54
55
|
}
|
|
55
56
|
// Preserve existing time when selecting a new day
|
|
56
57
|
if (showTimePicker && value) {
|
|
57
|
-
day.setHours(value.getHours(), value.getMinutes())
|
|
58
|
+
day.setHours(value.getHours(), value.getMinutes());
|
|
58
59
|
}
|
|
59
|
-
onChange?.(day)
|
|
60
|
-
if (!showTimePicker) setOpen(false)
|
|
60
|
+
onChange?.(day);
|
|
61
|
+
if (!showTimePicker) setOpen(false);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
function handleTimeChange(e: React.ChangeEvent<HTMLInputElement>): void {
|
|
64
|
-
const [hours, minutes] = e.target.value.split(":").map(Number)
|
|
65
|
-
const next = value ? new Date(value) : new Date()
|
|
66
|
-
next.setHours(hours, minutes, 0, 0)
|
|
67
|
-
onChange?.(next)
|
|
65
|
+
const [hours, minutes] = e.target.value.split(":").map(Number);
|
|
66
|
+
const next = value ? new Date(value) : new Date();
|
|
67
|
+
next.setHours(hours, minutes, 0, 0);
|
|
68
|
+
onChange?.(next);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
const timeValue = value
|
|
71
72
|
? `${String(value.getHours()).padStart(2, "0")}:${String(value.getMinutes()).padStart(2, "0")}`
|
|
72
|
-
: ""
|
|
73
|
+
: "";
|
|
73
74
|
|
|
74
|
-
let displayValue: string | undefined
|
|
75
|
+
let displayValue: string | undefined;
|
|
75
76
|
if (value && showTimePicker) {
|
|
76
|
-
displayValue = format(value, "dd/MM/yyyy HH:mm")
|
|
77
|
+
displayValue = format(value, "dd/MM/yyyy HH:mm");
|
|
77
78
|
} else if (value) {
|
|
78
|
-
displayValue = format(value, "dd/MM/yyyy")
|
|
79
|
+
displayValue = format(value, "dd/MM/yyyy");
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
return (
|
|
@@ -85,7 +86,9 @@ function DatePicker({
|
|
|
85
86
|
<Button
|
|
86
87
|
className={cn(
|
|
87
88
|
"w-full justify-start rounded-none font-normal data-[empty=true]:text-muted-foreground",
|
|
88
|
-
|
|
89
|
+
// Show open/focus state when the popover is expanded
|
|
90
|
+
"aria-expanded:border-ring aria-expanded:ring-2 aria-expanded:ring-ring/20",
|
|
91
|
+
className,
|
|
89
92
|
)}
|
|
90
93
|
data-empty={!value}
|
|
91
94
|
data-slot="date-picker-trigger"
|
|
@@ -109,23 +112,25 @@ function DatePicker({
|
|
|
109
112
|
{...calendarProps}
|
|
110
113
|
className={cn(
|
|
111
114
|
"rounded-none border-0 shadow-none",
|
|
112
|
-
calendarProps?.className
|
|
115
|
+
calendarProps?.className,
|
|
113
116
|
)}
|
|
114
117
|
/>
|
|
115
|
-
{showTimePicker ?
|
|
118
|
+
{showTimePicker ? (
|
|
119
|
+
<div className="border-t border-border px-3 pb-3 pt-2">
|
|
116
120
|
<label className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
|
117
121
|
Time
|
|
118
|
-
<
|
|
119
|
-
className="mt-1.5 h-8
|
|
122
|
+
<Input
|
|
123
|
+
className="mt-1.5 h-8"
|
|
120
124
|
onChange={handleTimeChange}
|
|
121
125
|
type="time"
|
|
122
126
|
value={timeValue}
|
|
123
127
|
/>
|
|
124
128
|
</label>
|
|
125
|
-
</div>
|
|
129
|
+
</div>
|
|
130
|
+
) : null}
|
|
126
131
|
</PopoverContent>
|
|
127
132
|
</Popover>
|
|
128
|
-
)
|
|
133
|
+
);
|
|
129
134
|
}
|
|
130
135
|
|
|
131
|
-
export { DatePicker }
|
|
136
|
+
export { DatePicker };
|