@wealthx/shadcn 1.2.2 → 1.3.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/.turbo/turbo-build.log +200 -156
- package/CHANGELOG.md +22 -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-FNQXOAYJ.mjs +169 -0
- 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-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-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/{chunk-ZRSDX6OW.mjs → chunk-ZC45IGZO.mjs} +33 -30
- 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 +497 -0
- package/dist/components/ui/advisor-card.mjs +13 -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 +234 -95
- package/dist/components/ui/sidebar-nav.mjs +4 -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 +12899 -9343
- package/dist/index.mjs +256 -190
- package/dist/styles.css +1 -1
- package/package.json +71 -1
- package/src/components/index.tsx +114 -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 +227 -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 +36 -37
- 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-LLVQKSU3.mjs → chunk-GD4BJDJR.mjs} +3 -3
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PageHeader — WealthX Design System
|
|
6
|
+
*
|
|
7
|
+
* In-page heading block. Renders inside scrollable content — not part of
|
|
8
|
+
* the layout shell. Use for sections that need a visible title and optional
|
|
9
|
+
* description (e.g. "My Advisors", "How can we help?").
|
|
10
|
+
*
|
|
11
|
+
* For a sticky top-of-page bar with action buttons, use PageTopBar instead.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Types
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
export interface PageHeaderProps {
|
|
19
|
+
/** Main page / section title */
|
|
20
|
+
title: string;
|
|
21
|
+
/** Optional subtitle shown below the title */
|
|
22
|
+
description?: string;
|
|
23
|
+
/** Optional action elements rendered to the right of the title block */
|
|
24
|
+
actions?: React.ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Component
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
export function PageHeader({
|
|
33
|
+
title,
|
|
34
|
+
description,
|
|
35
|
+
actions,
|
|
36
|
+
className,
|
|
37
|
+
}: PageHeaderProps) {
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
data-slot="page-header"
|
|
41
|
+
className={cn("flex items-start justify-between gap-4", className)}
|
|
42
|
+
>
|
|
43
|
+
{/* Title + description */}
|
|
44
|
+
<div className="flex flex-col gap-0.5">
|
|
45
|
+
<h1 className="text-xl font-bold leading-tight">{title}</h1>
|
|
46
|
+
{description && (
|
|
47
|
+
<p className="text-sm text-muted-foreground">{description}</p>
|
|
48
|
+
)}
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
{/* Optional actions */}
|
|
52
|
+
{actions && (
|
|
53
|
+
<div className="flex shrink-0 items-center gap-2">{actions}</div>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PageTopBar — WealthX Design System
|
|
6
|
+
*
|
|
7
|
+
* Sticky top-of-page bar. Sits at the top of the main content area,
|
|
8
|
+
* separated from the content by a bottom border. Holds the page title
|
|
9
|
+
* and action buttons.
|
|
10
|
+
*
|
|
11
|
+
* Used by: Loan CRM, Contact, AI Builder, and other data-heavy pages.
|
|
12
|
+
* For an in-page title block with a description, use PageHeader instead.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Types
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
export interface PageTopBarProps {
|
|
20
|
+
/** Page title shown on the left */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Optional action elements rendered to the right */
|
|
23
|
+
actions?: React.ReactNode;
|
|
24
|
+
className?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Component
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export function PageTopBar({ title, actions, className }: PageTopBarProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
data-slot="page-top-bar"
|
|
35
|
+
className={cn(
|
|
36
|
+
"flex shrink-0 items-center justify-between gap-4",
|
|
37
|
+
"border-b border-border bg-background px-6 py-3",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{/* Title */}
|
|
42
|
+
<h1 className="text-lg font-semibold leading-tight">{title}</h1>
|
|
43
|
+
|
|
44
|
+
{/* Optional actions */}
|
|
45
|
+
{actions && <div className="flex items-center gap-2">{actions}</div>}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import { type ReactElement } from "react"
|
|
2
|
-
import * as React from "react"
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import * as React from "react";
|
|
3
3
|
import {
|
|
4
4
|
ChevronLeftIcon,
|
|
5
5
|
ChevronRightIcon,
|
|
6
|
+
ChevronsLeftIcon,
|
|
7
|
+
ChevronsRightIcon,
|
|
6
8
|
MoreHorizontalIcon,
|
|
7
|
-
} from "lucide-react"
|
|
8
|
-
import { cn } from "@/lib/utils"
|
|
9
|
-
import { buttonVariants,
|
|
9
|
+
} from "lucide-react";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
import { buttonVariants, Button } from "@/components/ui/button";
|
|
12
|
+
import {
|
|
13
|
+
Select,
|
|
14
|
+
SelectContent,
|
|
15
|
+
SelectItem,
|
|
16
|
+
SelectTrigger,
|
|
17
|
+
SelectValue,
|
|
18
|
+
} from "@/components/ui/select";
|
|
10
19
|
|
|
11
20
|
/**
|
|
12
21
|
* Pagination — WealthX Design System
|
|
@@ -16,7 +25,7 @@ import { buttonVariants, type Button } from "@/components/ui/button"
|
|
|
16
25
|
* WealthX overrides: none — ghost/outline variants match design system
|
|
17
26
|
*/
|
|
18
27
|
|
|
19
|
-
export type PaginationProps = React.ComponentProps<"nav"
|
|
28
|
+
export type PaginationProps = React.ComponentProps<"nav">;
|
|
20
29
|
|
|
21
30
|
function Pagination({ className, ...props }: PaginationProps): ReactElement {
|
|
22
31
|
return (
|
|
@@ -27,10 +36,10 @@ function Pagination({ className, ...props }: PaginationProps): ReactElement {
|
|
|
27
36
|
role="navigation"
|
|
28
37
|
{...props}
|
|
29
38
|
/>
|
|
30
|
-
)
|
|
39
|
+
);
|
|
31
40
|
}
|
|
32
41
|
|
|
33
|
-
export type PaginationContentProps = React.ComponentProps<"ul"
|
|
42
|
+
export type PaginationContentProps = React.ComponentProps<"ul">;
|
|
34
43
|
|
|
35
44
|
function PaginationContent({
|
|
36
45
|
className,
|
|
@@ -42,19 +51,19 @@ function PaginationContent({
|
|
|
42
51
|
data-slot="pagination-content"
|
|
43
52
|
{...props}
|
|
44
53
|
/>
|
|
45
|
-
)
|
|
54
|
+
);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
export type PaginationItemProps = React.ComponentProps<"li"
|
|
57
|
+
export type PaginationItemProps = React.ComponentProps<"li">;
|
|
49
58
|
|
|
50
59
|
function PaginationItem({ ...props }: PaginationItemProps): ReactElement {
|
|
51
|
-
return <li data-slot="pagination-item" {...props}
|
|
60
|
+
return <li data-slot="pagination-item" {...props} />;
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
export type PaginationLinkProps = {
|
|
55
|
-
isActive?: boolean
|
|
64
|
+
isActive?: boolean;
|
|
56
65
|
} & Pick<React.ComponentProps<typeof Button>, "size"> &
|
|
57
|
-
React.ComponentProps<"a"
|
|
66
|
+
React.ComponentProps<"a">;
|
|
58
67
|
|
|
59
68
|
function PaginationLink({
|
|
60
69
|
className,
|
|
@@ -71,16 +80,18 @@ function PaginationLink({
|
|
|
71
80
|
variant: isActive ? "outline" : "ghost",
|
|
72
81
|
size,
|
|
73
82
|
}),
|
|
74
|
-
className
|
|
83
|
+
className,
|
|
75
84
|
)}
|
|
76
85
|
data-active={isActive}
|
|
77
86
|
data-slot="pagination-link"
|
|
78
87
|
{...props}
|
|
79
88
|
/>
|
|
80
|
-
)
|
|
89
|
+
);
|
|
81
90
|
}
|
|
82
91
|
|
|
83
|
-
export type PaginationPreviousProps = React.ComponentProps<
|
|
92
|
+
export type PaginationPreviousProps = React.ComponentProps<
|
|
93
|
+
typeof PaginationLink
|
|
94
|
+
>;
|
|
84
95
|
|
|
85
96
|
function PaginationPrevious({
|
|
86
97
|
className,
|
|
@@ -96,10 +107,10 @@ function PaginationPrevious({
|
|
|
96
107
|
<ChevronLeftIcon />
|
|
97
108
|
<span className="hidden sm:block">Previous</span>
|
|
98
109
|
</PaginationLink>
|
|
99
|
-
)
|
|
110
|
+
);
|
|
100
111
|
}
|
|
101
112
|
|
|
102
|
-
export type PaginationNextProps = React.ComponentProps<typeof PaginationLink
|
|
113
|
+
export type PaginationNextProps = React.ComponentProps<typeof PaginationLink>;
|
|
103
114
|
|
|
104
115
|
function PaginationNext({
|
|
105
116
|
className,
|
|
@@ -115,10 +126,10 @@ function PaginationNext({
|
|
|
115
126
|
<span className="hidden sm:block">Next</span>
|
|
116
127
|
<ChevronRightIcon />
|
|
117
128
|
</PaginationLink>
|
|
118
|
-
)
|
|
129
|
+
);
|
|
119
130
|
}
|
|
120
131
|
|
|
121
|
-
export type PaginationEllipsisProps = React.ComponentProps<"span"
|
|
132
|
+
export type PaginationEllipsisProps = React.ComponentProps<"span">;
|
|
122
133
|
|
|
123
134
|
function PaginationEllipsis({
|
|
124
135
|
className,
|
|
@@ -134,7 +145,143 @@ function PaginationEllipsis({
|
|
|
134
145
|
<MoreHorizontalIcon className="size-4" />
|
|
135
146
|
<span className="sr-only">More pages</span>
|
|
136
147
|
</span>
|
|
137
|
-
)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type PaginationNavButtonsProps = {
|
|
152
|
+
hasPrev: boolean;
|
|
153
|
+
hasNext: boolean;
|
|
154
|
+
onFirst: () => void;
|
|
155
|
+
onPrev: () => void;
|
|
156
|
+
onNext: () => void;
|
|
157
|
+
onLast: () => void;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
function PaginationNavButtons({
|
|
161
|
+
hasPrev,
|
|
162
|
+
hasNext,
|
|
163
|
+
onFirst,
|
|
164
|
+
onPrev,
|
|
165
|
+
onNext,
|
|
166
|
+
onLast,
|
|
167
|
+
}: PaginationNavButtonsProps): ReactElement {
|
|
168
|
+
return (
|
|
169
|
+
<div className="flex items-center gap-1">
|
|
170
|
+
<Button
|
|
171
|
+
aria-label="Go to first page"
|
|
172
|
+
disabled={!hasPrev}
|
|
173
|
+
onClick={onFirst}
|
|
174
|
+
size="icon-sm"
|
|
175
|
+
variant="outline"
|
|
176
|
+
>
|
|
177
|
+
<ChevronsLeftIcon className="size-4" />
|
|
178
|
+
</Button>
|
|
179
|
+
<Button
|
|
180
|
+
aria-label="Go to previous page"
|
|
181
|
+
disabled={!hasPrev}
|
|
182
|
+
onClick={onPrev}
|
|
183
|
+
size="icon-sm"
|
|
184
|
+
variant="outline"
|
|
185
|
+
>
|
|
186
|
+
<ChevronLeftIcon className="size-4" />
|
|
187
|
+
</Button>
|
|
188
|
+
<Button
|
|
189
|
+
aria-label="Go to next page"
|
|
190
|
+
disabled={!hasNext}
|
|
191
|
+
onClick={onNext}
|
|
192
|
+
size="icon-sm"
|
|
193
|
+
variant="outline"
|
|
194
|
+
>
|
|
195
|
+
<ChevronRightIcon className="size-4" />
|
|
196
|
+
</Button>
|
|
197
|
+
<Button
|
|
198
|
+
aria-label="Go to last page"
|
|
199
|
+
disabled={!hasNext}
|
|
200
|
+
onClick={onLast}
|
|
201
|
+
size="icon-sm"
|
|
202
|
+
variant="outline"
|
|
203
|
+
>
|
|
204
|
+
<ChevronsRightIcon className="size-4" />
|
|
205
|
+
</Button>
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type TablePaginationProps = {
|
|
211
|
+
page: number;
|
|
212
|
+
pageCount: number;
|
|
213
|
+
pageSize: number;
|
|
214
|
+
pageSizeOptions?: number[];
|
|
215
|
+
onPageChange: (page: number) => void;
|
|
216
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
217
|
+
selectedCount?: number;
|
|
218
|
+
totalCount?: number;
|
|
219
|
+
className?: string;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
function TablePagination({
|
|
223
|
+
page,
|
|
224
|
+
pageCount,
|
|
225
|
+
pageSize,
|
|
226
|
+
pageSizeOptions = [10, 20, 30, 50],
|
|
227
|
+
onPageChange,
|
|
228
|
+
onPageSizeChange,
|
|
229
|
+
selectedCount,
|
|
230
|
+
totalCount,
|
|
231
|
+
className,
|
|
232
|
+
}: TablePaginationProps): ReactElement {
|
|
233
|
+
return (
|
|
234
|
+
<div
|
|
235
|
+
className={cn("flex items-center gap-4 py-4", className)}
|
|
236
|
+
data-slot="table-pagination"
|
|
237
|
+
>
|
|
238
|
+
{selectedCount != null && selectedCount > 0 && totalCount != null && (
|
|
239
|
+
<span className="text-body-small text-muted-foreground">
|
|
240
|
+
{selectedCount} of {totalCount} row(s) selected.
|
|
241
|
+
</span>
|
|
242
|
+
)}
|
|
243
|
+
|
|
244
|
+
<div className="ml-auto flex items-center gap-6">
|
|
245
|
+
<div className="flex items-center gap-2">
|
|
246
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
247
|
+
Rows per page
|
|
248
|
+
</span>
|
|
249
|
+
<Select
|
|
250
|
+
onValueChange={(value) => onPageSizeChange(Number(value))}
|
|
251
|
+
value={`${pageSize}`}
|
|
252
|
+
>
|
|
253
|
+
<SelectTrigger
|
|
254
|
+
aria-label="Rows per page"
|
|
255
|
+
className="w-[70px]"
|
|
256
|
+
size="sm"
|
|
257
|
+
>
|
|
258
|
+
<SelectValue />
|
|
259
|
+
</SelectTrigger>
|
|
260
|
+
<SelectContent>
|
|
261
|
+
{pageSizeOptions.map((size) => (
|
|
262
|
+
<SelectItem key={size} value={`${size}`}>
|
|
263
|
+
{size}
|
|
264
|
+
</SelectItem>
|
|
265
|
+
))}
|
|
266
|
+
</SelectContent>
|
|
267
|
+
</Select>
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
271
|
+
Page {page} of {pageCount}
|
|
272
|
+
</span>
|
|
273
|
+
|
|
274
|
+
<PaginationNavButtons
|
|
275
|
+
hasNext={page < pageCount}
|
|
276
|
+
hasPrev={page > 1}
|
|
277
|
+
onFirst={() => onPageChange(1)}
|
|
278
|
+
onLast={() => onPageChange(pageCount)}
|
|
279
|
+
onNext={() => onPageChange(page + 1)}
|
|
280
|
+
onPrev={() => onPageChange(page - 1)}
|
|
281
|
+
/>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
138
285
|
}
|
|
139
286
|
|
|
140
287
|
export {
|
|
@@ -145,4 +292,6 @@ export {
|
|
|
145
292
|
PaginationPrevious,
|
|
146
293
|
PaginationNext,
|
|
147
294
|
PaginationEllipsis,
|
|
148
|
-
|
|
295
|
+
PaginationNavButtons,
|
|
296
|
+
TablePagination,
|
|
297
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { RefreshCw, Search, X } from "lucide-react";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
3
4
|
import { cn } from "@/lib/utils";
|
|
4
5
|
import { Input } from "@/components/ui/input";
|
|
5
6
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
@@ -128,13 +129,16 @@ function Toolbar({
|
|
|
128
129
|
className="h-8 pl-8 text-sm"
|
|
129
130
|
/>
|
|
130
131
|
{searchValue && (
|
|
131
|
-
<
|
|
132
|
+
<Button
|
|
133
|
+
type="button"
|
|
134
|
+
variant="ghost"
|
|
135
|
+
size="icon"
|
|
132
136
|
onClick={() => onSearchChange("")}
|
|
133
|
-
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
|
137
|
+
className="absolute right-2 top-1/2 size-6 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
|
134
138
|
aria-label="Clear search"
|
|
135
139
|
>
|
|
136
140
|
<X className="size-3.5" />
|
|
137
|
-
</
|
|
141
|
+
</Button>
|
|
138
142
|
)}
|
|
139
143
|
</div>
|
|
140
144
|
|
|
@@ -163,13 +167,16 @@ function Toolbar({
|
|
|
163
167
|
|
|
164
168
|
{/* Refresh */}
|
|
165
169
|
{onRefresh && (
|
|
166
|
-
<
|
|
170
|
+
<Button
|
|
171
|
+
type="button"
|
|
172
|
+
variant="ghost"
|
|
173
|
+
size="icon"
|
|
167
174
|
onClick={onRefresh}
|
|
168
175
|
className="ml-auto text-muted-foreground hover:text-foreground"
|
|
169
176
|
aria-label="Refresh board"
|
|
170
177
|
>
|
|
171
178
|
<RefreshCw className="size-4" />
|
|
172
|
-
</
|
|
179
|
+
</Button>
|
|
173
180
|
)}
|
|
174
181
|
</div>
|
|
175
182
|
);
|
|
@@ -127,7 +127,9 @@ export function PropertyCashflowDoughnutChart({
|
|
|
127
127
|
style={{ maxWidth: width, fontFamily }}
|
|
128
128
|
>
|
|
129
129
|
<CardHeader className="px-3 sm:px-6">
|
|
130
|
-
<CardTitle className="text-
|
|
130
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
131
|
+
{title}
|
|
132
|
+
</CardTitle>
|
|
131
133
|
</CardHeader>
|
|
132
134
|
|
|
133
135
|
<CardContent className="px-3 sm:px-6">
|
|
@@ -124,7 +124,9 @@ export function PropertyDebtEquityDoughnutChart({
|
|
|
124
124
|
style={{ maxWidth: width, fontFamily }}
|
|
125
125
|
>
|
|
126
126
|
<CardHeader className="px-3 sm:px-6">
|
|
127
|
-
<CardTitle className="text-
|
|
127
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
128
|
+
{title}
|
|
129
|
+
</CardTitle>
|
|
128
130
|
</CardHeader>
|
|
129
131
|
|
|
130
132
|
<CardContent className="px-3 sm:px-6">
|
|
@@ -337,7 +337,9 @@ export function PropertyMobileEstimateLineChart({
|
|
|
337
337
|
style={{ maxWidth: width, fontFamily }}
|
|
338
338
|
>
|
|
339
339
|
<CardHeader className="px-3 sm:px-6">
|
|
340
|
-
<CardTitle className="text-
|
|
340
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
341
|
+
{title}
|
|
342
|
+
</CardTitle>
|
|
341
343
|
{showPeriodSelector && (
|
|
342
344
|
<CardAction>
|
|
343
345
|
<div className="flex gap-0.5 sm:gap-1">
|
|
@@ -24,6 +24,8 @@ import {
|
|
|
24
24
|
} from "lucide-react";
|
|
25
25
|
import type { LucideIcon } from "lucide-react";
|
|
26
26
|
import { cn } from "@/lib/utils";
|
|
27
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
28
|
+
import { Button } from "./button";
|
|
27
29
|
import {
|
|
28
30
|
Tooltip,
|
|
29
31
|
TooltipContent,
|
|
@@ -106,19 +108,6 @@ function getInitials(name: string): string {
|
|
|
106
108
|
.slice(0, 2);
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
function formatCurrency(value: number, isNetItem = false): string {
|
|
110
|
-
const abs = Math.abs(value);
|
|
111
|
-
const formatted = new Intl.NumberFormat("en-AU", {
|
|
112
|
-
style: "currency",
|
|
113
|
-
currency: "AUD",
|
|
114
|
-
minimumFractionDigits: 0,
|
|
115
|
-
maximumFractionDigits: 0,
|
|
116
|
-
}).format(abs);
|
|
117
|
-
if (!isNetItem) return formatted;
|
|
118
|
-
if (value > 0) return `+${formatted}`;
|
|
119
|
-
if (value < 0) return `-${formatted}`;
|
|
120
|
-
return formatted;
|
|
121
|
-
}
|
|
122
111
|
|
|
123
112
|
function navIconCn(isActive: boolean): string {
|
|
124
113
|
return cn(
|
|
@@ -186,7 +175,7 @@ function MetricsGroup({ group }: MetricsGroupProps) {
|
|
|
186
175
|
item.isNetItem && item.value < 0 && "text-destructive",
|
|
187
176
|
)}
|
|
188
177
|
>
|
|
189
|
-
{formatCurrency(item.value, item.isNetItem)}
|
|
178
|
+
{formatCurrency(item.value, { showSign: item.isNetItem })}
|
|
190
179
|
</span>
|
|
191
180
|
</div>
|
|
192
181
|
))}
|
|
@@ -211,16 +200,17 @@ function SidebarNavItemView({
|
|
|
211
200
|
|
|
212
201
|
return (
|
|
213
202
|
<NavTooltip label={item.title} collapsed={collapsed}>
|
|
214
|
-
<
|
|
203
|
+
<Button
|
|
215
204
|
type="button"
|
|
205
|
+
variant="ghost"
|
|
216
206
|
onClick={() => onNavigate?.(item.href)}
|
|
217
207
|
className={cn(
|
|
218
|
-
"group
|
|
208
|
+
"group h-auto w-full items-center gap-3 py-2.5 text-base font-medium transition-colors",
|
|
219
209
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
220
210
|
collapsed
|
|
221
211
|
? "justify-center px-2"
|
|
222
212
|
: cn(
|
|
223
|
-
"px-3 border-l-4",
|
|
213
|
+
"justify-start px-3 border-l-4",
|
|
224
214
|
item.isActive
|
|
225
215
|
? "bg-white/15 text-brand-secondary-foreground border-primary"
|
|
226
216
|
: "border-transparent",
|
|
@@ -233,7 +223,7 @@ function SidebarNavItemView({
|
|
|
233
223
|
strokeWidth={1.75}
|
|
234
224
|
/>
|
|
235
225
|
{!collapsed && <span className="truncate">{item.title}</span>}
|
|
236
|
-
</
|
|
226
|
+
</Button>
|
|
237
227
|
</NavTooltip>
|
|
238
228
|
);
|
|
239
229
|
}
|
|
@@ -262,11 +252,12 @@ function CollapsibleNavItem({
|
|
|
262
252
|
if (collapsed) {
|
|
263
253
|
return (
|
|
264
254
|
<NavTooltip label={item.title} collapsed={collapsed}>
|
|
265
|
-
<
|
|
255
|
+
<Button
|
|
266
256
|
type="button"
|
|
257
|
+
variant="ghost"
|
|
267
258
|
onClick={() => onNavigate?.(item.href)}
|
|
268
259
|
className={cn(
|
|
269
|
-
"group
|
|
260
|
+
"group h-auto w-full justify-center px-2 py-2.5 transition-colors",
|
|
270
261
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
271
262
|
hasActiveChild && "bg-white/15 text-brand-secondary-foreground",
|
|
272
263
|
)}
|
|
@@ -276,18 +267,19 @@ function CollapsibleNavItem({
|
|
|
276
267
|
size={18}
|
|
277
268
|
strokeWidth={1.75}
|
|
278
269
|
/>
|
|
279
|
-
</
|
|
270
|
+
</Button>
|
|
280
271
|
</NavTooltip>
|
|
281
272
|
);
|
|
282
273
|
}
|
|
283
274
|
|
|
284
275
|
return (
|
|
285
276
|
<div>
|
|
286
|
-
<
|
|
277
|
+
<Button
|
|
287
278
|
type="button"
|
|
279
|
+
variant="ghost"
|
|
288
280
|
onClick={() => setOpen((prev) => !prev)}
|
|
289
281
|
className={cn(
|
|
290
|
-
"group
|
|
282
|
+
"group h-auto w-full justify-start gap-3 px-3 py-2.5 text-base font-medium transition-colors",
|
|
291
283
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
292
284
|
"border-l-4 border-transparent",
|
|
293
285
|
hasActiveChild &&
|
|
@@ -308,17 +300,18 @@ function CollapsibleNavItem({
|
|
|
308
300
|
size={14}
|
|
309
301
|
strokeWidth={2}
|
|
310
302
|
/>
|
|
311
|
-
</
|
|
303
|
+
</Button>
|
|
312
304
|
|
|
313
305
|
{open && item.subItems && (
|
|
314
306
|
<div className="ml-9 border-l border-white/15 pl-3">
|
|
315
307
|
{item.subItems.map((sub) => (
|
|
316
|
-
<
|
|
308
|
+
<Button
|
|
317
309
|
key={sub.href}
|
|
318
310
|
type="button"
|
|
311
|
+
variant="ghost"
|
|
319
312
|
onClick={() => onNavigate?.(sub.href)}
|
|
320
313
|
className={cn(
|
|
321
|
-
"
|
|
314
|
+
"h-auto w-full justify-start gap-2 py-1.5 pl-1 text-sm transition-colors",
|
|
322
315
|
"text-brand-secondary-foreground/50 hover:text-brand-secondary-foreground",
|
|
323
316
|
sub.isActive && "text-primary font-medium",
|
|
324
317
|
)}
|
|
@@ -334,7 +327,7 @@ function CollapsibleNavItem({
|
|
|
334
327
|
)}
|
|
335
328
|
/>
|
|
336
329
|
<span className="truncate">{sub.title}</span>
|
|
337
|
-
</
|
|
330
|
+
</Button>
|
|
338
331
|
))}
|
|
339
332
|
</div>
|
|
340
333
|
)}
|
|
@@ -364,7 +357,10 @@ export function SidebarNav({
|
|
|
364
357
|
data-slot="sidebar-nav"
|
|
365
358
|
data-collapsed={collapsed}
|
|
366
359
|
className={cn(
|
|
367
|
-
|
|
360
|
+
// Force dark-mode CSS variable resolution — sidebar is always dark-backgrounded
|
|
361
|
+
// regardless of system theme, so semantic tokens (destructive, success, etc.)
|
|
362
|
+
// must use their dark-mode values to maintain WCAG contrast.
|
|
363
|
+
"dark flex h-full flex-col bg-brand-secondary text-brand-secondary-foreground",
|
|
368
364
|
"transition-all duration-200 ease-in-out",
|
|
369
365
|
collapsed ? "w-14" : "w-[279px]",
|
|
370
366
|
className,
|
|
@@ -395,11 +391,12 @@ export function SidebarNav({
|
|
|
395
391
|
{/* User section */}
|
|
396
392
|
<div className="border-b border-white/15">
|
|
397
393
|
<NavTooltip label={userName} collapsed={collapsed}>
|
|
398
|
-
<
|
|
394
|
+
<Button
|
|
399
395
|
type="button"
|
|
396
|
+
variant="ghost"
|
|
400
397
|
onClick={() => !collapsed && setUserMenuOpen((prev) => !prev)}
|
|
401
398
|
className={cn(
|
|
402
|
-
"group
|
|
399
|
+
"group h-auto w-full justify-start gap-3 px-5 py-5 text-base transition-colors",
|
|
403
400
|
"text-brand-secondary-foreground hover:bg-white/10",
|
|
404
401
|
collapsed && "justify-center px-2 py-4",
|
|
405
402
|
)}
|
|
@@ -422,17 +419,18 @@ export function SidebarNav({
|
|
|
422
419
|
/>
|
|
423
420
|
</>
|
|
424
421
|
)}
|
|
425
|
-
</
|
|
422
|
+
</Button>
|
|
426
423
|
</NavTooltip>
|
|
427
424
|
|
|
428
425
|
{/* Logout dropdown */}
|
|
429
426
|
{!collapsed && userMenuOpen && (
|
|
430
427
|
<div className="border-t border-white/15 bg-black/20">
|
|
431
|
-
<
|
|
428
|
+
<Button
|
|
432
429
|
type="button"
|
|
430
|
+
variant="ghost"
|
|
433
431
|
onClick={onLogout}
|
|
434
432
|
className={cn(
|
|
435
|
-
"
|
|
433
|
+
"h-auto w-full justify-start gap-3 px-5 py-3 text-base",
|
|
436
434
|
"text-brand-secondary-foreground/70 hover:bg-white/10 hover:text-brand-secondary-foreground transition-colors",
|
|
437
435
|
)}
|
|
438
436
|
>
|
|
@@ -442,7 +440,7 @@ export function SidebarNav({
|
|
|
442
440
|
className="shrink-0 text-destructive"
|
|
443
441
|
/>
|
|
444
442
|
<span>Logout</span>
|
|
445
|
-
</
|
|
443
|
+
</Button>
|
|
446
444
|
</div>
|
|
447
445
|
)}
|
|
448
446
|
</div>
|
|
@@ -484,11 +482,12 @@ export function SidebarNav({
|
|
|
484
482
|
label={collapsed ? "Expand" : "Collapse"}
|
|
485
483
|
collapsed={collapsed}
|
|
486
484
|
>
|
|
487
|
-
<
|
|
485
|
+
<Button
|
|
488
486
|
type="button"
|
|
487
|
+
variant="ghost"
|
|
489
488
|
onClick={() => onCollapsedChange(!collapsed)}
|
|
490
489
|
className={cn(
|
|
491
|
-
"
|
|
490
|
+
"h-auto w-full justify-start gap-3 px-3 py-3 transition-colors",
|
|
492
491
|
"text-brand-secondary-foreground/80 hover:bg-white/10 hover:text-brand-secondary-foreground",
|
|
493
492
|
collapsed && "justify-center px-2",
|
|
494
493
|
)}
|
|
@@ -507,7 +506,7 @@ export function SidebarNav({
|
|
|
507
506
|
/>
|
|
508
507
|
)}
|
|
509
508
|
{!collapsed && <span className="text-sm">Collapse</span>}
|
|
510
|
-
</
|
|
509
|
+
</Button>
|
|
511
510
|
</NavTooltip>
|
|
512
511
|
</div>
|
|
513
512
|
)}
|
|
@@ -129,7 +129,9 @@ export function TransactionsExpenseCategoriesDoughnutChart({
|
|
|
129
129
|
style={{ maxWidth: width, fontFamily }}
|
|
130
130
|
>
|
|
131
131
|
<CardHeader className="px-3 sm:px-6">
|
|
132
|
-
<CardTitle className="text-
|
|
132
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
133
|
+
{title}
|
|
134
|
+
</CardTitle>
|
|
133
135
|
</CardHeader>
|
|
134
136
|
|
|
135
137
|
<CardContent className="px-3 sm:px-6">
|