@wealthx/shadcn 1.5.42 → 1.5.43
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 +215 -210
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-5FHBC6DY.mjs → chunk-33WZ5NCW.mjs} +1 -1
- package/dist/{chunk-C35JMOII.mjs → chunk-3G6JUYRE.mjs} +4 -4
- package/dist/{chunk-LBXIYS34.mjs → chunk-4PVCJ3JD.mjs} +1 -1
- package/dist/{chunk-EHQL64B7.mjs → chunk-4SUXTO2Z.mjs} +4 -4
- package/dist/{chunk-BAONSY54.mjs → chunk-5RYH7SOQ.mjs} +1 -1
- package/dist/{chunk-3C4DZTGA.mjs → chunk-5XD7A7YC.mjs} +1 -1
- package/dist/{chunk-5DAQU3B6.mjs → chunk-66JXT7NY.mjs} +1 -1
- package/dist/{chunk-NGKTJRFN.mjs → chunk-6DO4EGT2.mjs} +2 -2
- package/dist/{chunk-C7ZTZTEW.mjs → chunk-6XJWL2E5.mjs} +1 -1
- package/dist/{chunk-FQUT5XD6.mjs → chunk-A4UP4QFB.mjs} +1 -1
- package/dist/{chunk-USIRKDYQ.mjs → chunk-BFCX7ADE.mjs} +1 -1
- package/dist/{chunk-XGRSPFFC.mjs → chunk-CQHKU24Z.mjs} +1 -1
- package/dist/{chunk-HONTZFLO.mjs → chunk-DP4ER6TJ.mjs} +1 -1
- package/dist/{chunk-VLVEZHFE.mjs → chunk-EFSLAMHI.mjs} +4 -4
- package/dist/{chunk-FYZBGWYR.mjs → chunk-FVSOFXJQ.mjs} +1 -1
- package/dist/{chunk-JUMEIPII.mjs → chunk-G2MOZZPE.mjs} +8 -8
- package/dist/{chunk-D3HKFRQO.mjs → chunk-GQWKBESP.mjs} +8 -5
- package/dist/{chunk-MD66TGX7.mjs → chunk-GXDKWCMV.mjs} +1 -1
- package/dist/{chunk-77L3UPBW.mjs → chunk-H7NOUDU3.mjs} +5 -5
- package/dist/{chunk-4LLTZ45R.mjs → chunk-HOXTEU5K.mjs} +8 -7
- package/dist/{chunk-ZA37ZWZW.mjs → chunk-IXW77PMI.mjs} +7 -7
- package/dist/{chunk-XHZONBL4.mjs → chunk-JLEQU5BO.mjs} +1 -1
- package/dist/{chunk-6UKOJLXO.mjs → chunk-JSFWRD7K.mjs} +4 -4
- package/dist/{chunk-7PTRHNUV.mjs → chunk-JY3FUGNL.mjs} +1 -1
- package/dist/{chunk-3ZU5BH6X.mjs → chunk-KEOAPKJO.mjs} +3 -3
- package/dist/{chunk-4QTHK7ML.mjs → chunk-KWYFJQV6.mjs} +1 -1
- package/dist/{chunk-FGMDBJCF.mjs → chunk-LDPCSE7J.mjs} +4 -4
- package/dist/chunk-LFWNKXZU.mjs +109 -0
- package/dist/{chunk-IRZWYTGV.mjs → chunk-M32YSAWL.mjs} +8 -7
- package/dist/{chunk-LLAGF6BA.mjs → chunk-MUB2G36A.mjs} +1 -1
- package/dist/{chunk-DQNNP6I4.mjs → chunk-NIETQFJQ.mjs} +1 -1
- package/dist/{chunk-RUX3OLVZ.mjs → chunk-OTFG57ZF.mjs} +1 -1
- package/dist/{chunk-OKIWXOJL.mjs → chunk-OWTW5WAJ.mjs} +1 -1
- package/dist/{chunk-WWIWRNBK.mjs → chunk-P7NSCTAW.mjs} +1 -1
- package/dist/{chunk-BZWQU52U.mjs → chunk-QZREZL2F.mjs} +1 -1
- package/dist/{chunk-E432NK23.mjs → chunk-RBQ4BZUV.mjs} +6 -6
- package/dist/{chunk-I2EKKSEF.mjs → chunk-RKBLVNDC.mjs} +4 -7
- package/dist/{chunk-LHQACMZY.mjs → chunk-SPPQFW32.mjs} +106 -50
- package/dist/{chunk-OSSS56CB.mjs → chunk-SUXJWKRI.mjs} +4 -4
- package/dist/{chunk-SCGCGVDN.mjs → chunk-SZXIPE5J.mjs} +1 -1
- package/dist/{chunk-VVURVETY.mjs → chunk-TOQRA2TD.mjs} +1 -1
- package/dist/{chunk-GYWOD2YI.mjs → chunk-TZSDYQFH.mjs} +4 -4
- package/dist/{chunk-S7SBLNX4.mjs → chunk-UB3WG6I4.mjs} +1 -1
- package/dist/{chunk-PGJRZHN7.mjs → chunk-UVZ3JWFG.mjs} +1 -1
- package/dist/{chunk-UD5UF5OC.mjs → chunk-W7OPFKTZ.mjs} +4 -4
- package/dist/{chunk-YEWNFK5S.mjs → chunk-WLXP4OOF.mjs} +5 -5
- package/dist/{chunk-ORMC3TV3.mjs → chunk-XYXYTTNW.mjs} +1 -1
- package/dist/{chunk-CZOGJC76.mjs → chunk-YACFZWRR.mjs} +7 -7
- package/dist/{chunk-UTCW5YUX.mjs → chunk-YPATB6YQ.mjs} +9 -9
- package/dist/{chunk-BZGFW6L7.mjs → chunk-YWJAIPUA.mjs} +1 -1
- package/dist/{chunk-MHBQJVHE.mjs → chunk-Z65BGSHI.mjs} +5 -5
- package/dist/{chunk-PCULNQWA.mjs → chunk-ZGSFRUVI.mjs} +3 -3
- package/dist/{chunk-7NQKFPXE.mjs → chunk-ZRYG6ICN.mjs} +1 -1
- package/dist/{chunk-ZFKAYRFQ.mjs → chunk-ZUHFYW65.mjs} +1 -1
- package/dist/components/ui/about-you-form.mjs +2 -2
- package/dist/components/ui/account-list-carousel.mjs +2 -2
- package/dist/components/ui/add-column-modal.mjs +4 -4
- package/dist/components/ui/add-lead-modal.mjs +4 -4
- package/dist/components/ui/advisor-card.mjs +2 -2
- package/dist/components/ui/ai-assistant-drawer.mjs +2 -2
- package/dist/components/ui/ai-builder/index.mjs +4 -4
- package/dist/components/ui/ai-conversations/index.mjs +4 -4
- package/dist/components/ui/alert-dialog.mjs +3 -3
- package/dist/components/ui/applicant-expenses-section.mjs +1 -1
- package/dist/components/ui/appointment-action-dialogs.mjs +5 -5
- package/dist/components/ui/appointment-availability-settings.mjs +4 -4
- package/dist/components/ui/appointment-book-dialog.mjs +4 -4
- package/dist/components/ui/appointment-detail-sheet.mjs +6 -6
- package/dist/components/ui/appointment-upcoming-card.mjs +4 -4
- package/dist/components/ui/asset-accordion.mjs +7 -7
- package/dist/components/ui/assets-liabilities-side-card.js +19 -66
- package/dist/components/ui/assets-liabilities-side-card.mjs +22 -69
- package/dist/components/ui/backoffice-alert-history-chart.js +1 -1
- package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -5
- package/dist/components/ui/backoffice-alert-matching-chart.js +1 -1
- package/dist/components/ui/backoffice-alert-matching-chart.mjs +5 -5
- package/dist/components/ui/backoffice-alerts-chart.js +1 -1
- package/dist/components/ui/backoffice-alerts-chart.mjs +5 -5
- package/dist/components/ui/backoffice-connections-chart.js +1 -1
- package/dist/components/ui/backoffice-connections-chart.mjs +5 -5
- package/dist/components/ui/backoffice-contact-history-chart.js +1 -1
- package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -5
- package/dist/components/ui/backoffice-contact-matching-chart.js +1 -1
- package/dist/components/ui/backoffice-contact-matching-chart.mjs +5 -5
- package/dist/components/ui/backoffice-signup-steps.mjs +4 -4
- package/dist/components/ui/bank-statement-generate-dialog.mjs +4 -4
- package/dist/components/ui/bank-statement-pdf-viewer.mjs +4 -4
- package/dist/components/ui/borrowing-capacity-atoms.js +3 -6
- package/dist/components/ui/borrowing-capacity-atoms.mjs +2 -2
- package/dist/components/ui/borrowing-capacity-card.js +5 -5
- package/dist/components/ui/borrowing-capacity-card.mjs +6 -6
- package/dist/components/ui/borrowing-capacity-line-chart.js +5 -5
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -5
- package/dist/components/ui/calculator-section.mjs +4 -4
- package/dist/components/ui/cash-balance-line-chart.js +102 -46
- package/dist/components/ui/cash-balance-line-chart.mjs +5 -5
- package/dist/components/ui/cashflow-bar-chart.js +7 -4
- package/dist/components/ui/cashflow-bar-chart.mjs +5 -5
- package/dist/components/ui/category-edit-dialog.mjs +4 -4
- package/dist/components/ui/color-picker.mjs +2 -2
- package/dist/components/ui/contact-alert-dialog/index.mjs +4 -4
- package/dist/components/ui/create-contact-modal.mjs +4 -4
- package/dist/components/ui/csv-import-modal.mjs +4 -4
- package/dist/components/ui/dashboard-expense-categories.js +96 -63
- package/dist/components/ui/dashboard-expense-categories.mjs +101 -66
- package/dist/components/ui/dashboard-transactions-table.js +37 -44
- package/dist/components/ui/dashboard-transactions-table.mjs +45 -52
- package/dist/components/ui/data-table.mjs +2 -2
- package/dist/components/ui/date-picker.mjs +2 -2
- package/dist/components/ui/debt-accordion.mjs +7 -7
- package/dist/components/ui/delete-contact-component.mjs +4 -4
- package/dist/components/ui/dialog.mjs +3 -3
- package/dist/components/ui/document-checklist-template.mjs +2 -2
- package/dist/components/ui/expense-bar-chart.js +8 -7
- package/dist/components/ui/expense-bar-chart.mjs +5 -5
- package/dist/components/ui/expense-categories-bar.js +261 -0
- package/dist/components/ui/expense-categories-bar.mjs +12 -0
- package/dist/components/ui/expense-work-details.js +8 -7
- package/dist/components/ui/expense-work-details.mjs +7 -7
- package/dist/components/ui/file-preview-dialog.mjs +4 -4
- package/dist/components/ui/financial-cards.mjs +2 -2
- package/dist/components/ui/financial-drawers.mjs +2 -2
- package/dist/components/ui/financial-sections.mjs +3 -3
- package/dist/components/ui/frontend-signup-steps.mjs +2 -2
- package/dist/components/ui/income-bar-chart.js +8 -7
- package/dist/components/ui/income-bar-chart.mjs +5 -5
- package/dist/components/ui/income-sources-card.mjs +1 -1
- package/dist/components/ui/income-summary-component.mjs +1 -1
- package/dist/components/ui/income-work-details.js +8 -7
- package/dist/components/ui/income-work-details.mjs +6 -6
- package/dist/components/ui/incoming-outgoings-card.js +2 -2
- package/dist/components/ui/incoming-outgoings-card.mjs +3 -3
- package/dist/components/ui/interest-rate-section.mjs +1 -1
- package/dist/components/ui/kanban-column.mjs +5 -5
- package/dist/components/ui/loan-application-cards.mjs +3 -3
- package/dist/components/ui/loan-financials.mjs +3 -3
- package/dist/components/ui/money-input-with-slider.mjs +2 -2
- package/dist/components/ui/opportunity-card.mjs +4 -4
- package/dist/components/ui/opportunity-edit-modals.mjs +4 -4
- package/dist/components/ui/opportunity-summary-tab.mjs +8 -8
- package/dist/components/ui/pagination.mjs +2 -2
- package/dist/components/ui/pipeline-board.mjs +6 -6
- package/dist/components/ui/pipeline-chart.mjs +2 -2
- package/dist/components/ui/pipeline-dialogs.mjs +4 -4
- package/dist/components/ui/policy-ai/index.mjs +2 -2
- package/dist/components/ui/property-asset-card.mjs +4 -4
- package/dist/components/ui/property-cashflow-doughnut-chart.js +3 -3
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -5
- package/dist/components/ui/property-debt-equity-doughnut-chart.js +3 -3
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -5
- package/dist/components/ui/property-list-carousel.mjs +2 -2
- package/dist/components/ui/property-mobile-estimate-line-chart.js +4 -4
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -5
- package/dist/components/ui/property-report-dialog.mjs +5 -5
- package/dist/components/ui/resource-center/index.mjs +4 -4
- package/dist/components/ui/review-alerts-dialog.mjs +4 -4
- package/dist/components/ui/savings-goal-modal.mjs +7 -7
- package/dist/components/ui/scenario-drawer.mjs +4 -4
- package/dist/components/ui/scenario-list.js +4 -7
- package/dist/components/ui/scenario-list.mjs +5 -5
- package/dist/components/ui/share-details-dialog.mjs +4 -4
- package/dist/components/ui/sidebar-nav.mjs +4 -4
- package/dist/components/ui/signup-form-primitives.mjs +2 -2
- package/dist/components/ui/stage-timeline.mjs +1 -1
- package/dist/components/ui/support-agent/index.mjs +2 -2
- package/dist/components/ui/top-three-product.mjs +1 -1
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +3 -3
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -5
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -5
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +4 -4
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -5
- package/dist/components/ui/transactions-summary-block.js +13 -0
- package/dist/components/ui/transactions-summary-block.mjs +13 -0
- package/dist/index.js +2092 -1935
- package/dist/index.mjs +138 -134
- package/dist/lib/format-currency.js +54 -0
- package/dist/lib/format-currency.mjs +9 -0
- package/dist/styles.css +1 -1
- package/package.json +6 -1
- package/src/component-descriptions/assets-liabilities-side-card.md +19 -0
- package/src/component-descriptions/pipeline-chart.md +17 -0
- package/src/components/index.tsx +6 -0
- package/src/components/ui/assets-liabilities-side-card.tsx +43 -83
- package/src/components/ui/borrowing-capacity-atoms.tsx +4 -7
- package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -4
- package/src/components/ui/cash-balance-line-chart.tsx +123 -42
- package/src/components/ui/cashflow-bar-chart.tsx +7 -4
- package/src/components/ui/chart-shared.tsx +4 -4
- package/src/components/ui/dashboard-expense-categories.tsx +136 -60
- package/src/components/ui/dashboard-transactions-table.tsx +42 -28
- package/src/components/ui/expense-bar-chart.tsx +32 -19
- package/src/components/ui/expense-categories-bar.tsx +178 -0
- package/src/components/ui/income-bar-chart.tsx +32 -19
- package/src/components/ui/incoming-outgoings-card.tsx +2 -2
- package/src/components/ui/property-mobile-estimate-line-chart.tsx +4 -4
- package/src/components/ui/scenario-list.tsx +2 -2
- package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +7 -5
- package/src/components/ui/transactions-summary-block.tsx +39 -6
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +2 -0
- package/dist/{chunk-CEYEK3TI.mjs → chunk-B4R62ID3.mjs} +3 -3
- package/dist/{chunk-7LN5OGC2.mjs → chunk-E3VAK4EB.mjs} +3 -3
- package/dist/{chunk-EY36WDCF.mjs → chunk-EEZFXE3P.mjs} +3 -3
- package/dist/{chunk-T5FRVEJQ.mjs → chunk-JTMN36BK.mjs} +3 -3
- /package/dist/{chunk-MN5NYQCL.mjs → chunk-XQDTFNVL.mjs} +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Info } from "lucide-react";
|
|
3
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ExpenseCategoriesBar — WealthX Design System
|
|
9
|
+
*
|
|
10
|
+
* Horizontal stacked percentage bar for categorical breakdowns.
|
|
11
|
+
* Used for both expense categories (`color="secondary"`, default)
|
|
12
|
+
* and income sources (`color="primary"`).
|
|
13
|
+
*
|
|
14
|
+
* - `color="secondary"` (default): segments use `--brand-secondary` (dark navy)
|
|
15
|
+
* - `color="primary"`: segments use `--primary` (tenant green)
|
|
16
|
+
*
|
|
17
|
+
* Hovering a segment shows a tooltip with the category name, icon, and amount.
|
|
18
|
+
*
|
|
19
|
+
* Mirrors the FE component at
|
|
20
|
+
* `frontend/src/components/ExpenseCategoriesBar/index.tsx`
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export interface ExpenseCategoryPart {
|
|
26
|
+
id: string;
|
|
27
|
+
title: string;
|
|
28
|
+
/** Fraction of total (0–1). Used to size the segment. */
|
|
29
|
+
percentage: number;
|
|
30
|
+
/** Absolute amount in AUD. Shown in the hover tooltip. */
|
|
31
|
+
amount: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ExpenseCategoriesBarProps {
|
|
35
|
+
/** Main heading above the bar (e.g. "Expense Categories"). Omit to hide the header row entirely. */
|
|
36
|
+
title?: string;
|
|
37
|
+
/** Secondary label shown next to the title (e.g. date range or period) */
|
|
38
|
+
subtitle?: string;
|
|
39
|
+
/** Text shown in the info-icon tooltip next to the subtitle */
|
|
40
|
+
tooltipText?: string;
|
|
41
|
+
/** Ordered list of category segments */
|
|
42
|
+
parts?: ExpenseCategoryPart[];
|
|
43
|
+
/** Icon node for each segment, indexed to match `parts` */
|
|
44
|
+
icons?: React.ReactNode[];
|
|
45
|
+
/**
|
|
46
|
+
* Bar segment colour scheme.
|
|
47
|
+
* - `"secondary"` (default) — `--brand-secondary` (dark navy); used for expenses
|
|
48
|
+
* - `"primary"` — `--primary` (tenant green); used for income sources
|
|
49
|
+
*/
|
|
50
|
+
color?: "primary" | "secondary";
|
|
51
|
+
className?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ─── Component ───────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
export function ExpenseCategoriesBar({
|
|
57
|
+
title,
|
|
58
|
+
subtitle,
|
|
59
|
+
tooltipText,
|
|
60
|
+
parts = [],
|
|
61
|
+
icons = [],
|
|
62
|
+
color = "secondary",
|
|
63
|
+
className,
|
|
64
|
+
}: ExpenseCategoriesBarProps) {
|
|
65
|
+
const [hoveredIndex, setHoveredIndex] = useState(-1);
|
|
66
|
+
|
|
67
|
+
const segmentBase = color === "primary" ? "bg-primary" : "bg-brand-secondary";
|
|
68
|
+
const segmentHover =
|
|
69
|
+
color === "primary"
|
|
70
|
+
? "border-primary/50 bg-primary/60"
|
|
71
|
+
: "border-brand-secondary/50 bg-brand-secondary/60";
|
|
72
|
+
// Use *-foreground tokens so icons/text on a primary/secondary background
|
|
73
|
+
// always have sufficient contrast — avoids hardcoded colours that fail on
|
|
74
|
+
// custom tenant themes.
|
|
75
|
+
const iconDefault =
|
|
76
|
+
color === "primary"
|
|
77
|
+
? "[&_svg]:stroke-primary-foreground [&_svg]:text-primary-foreground"
|
|
78
|
+
: "[&_svg]:stroke-brand-secondary-foreground [&_svg]:text-brand-secondary-foreground";
|
|
79
|
+
const iconHovered = "[&_svg]:stroke-foreground [&_svg]:text-foreground";
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className={cn("flex flex-col", className)}>
|
|
83
|
+
{/* ── Header ── */}
|
|
84
|
+
{(title || subtitle) && (
|
|
85
|
+
<div className="flex items-baseline gap-2">
|
|
86
|
+
{title && (
|
|
87
|
+
<p className="m-0 overflow-hidden text-ellipsis whitespace-nowrap text-[22px] font-normal leading-tight">
|
|
88
|
+
{title}
|
|
89
|
+
</p>
|
|
90
|
+
)}
|
|
91
|
+
{subtitle && (
|
|
92
|
+
<div className="flex min-w-0 items-center gap-1">
|
|
93
|
+
<span className="whitespace-nowrap text-sm text-muted-foreground">
|
|
94
|
+
{subtitle}
|
|
95
|
+
</span>
|
|
96
|
+
{tooltipText && (
|
|
97
|
+
<Tooltip>
|
|
98
|
+
<TooltipTrigger
|
|
99
|
+
render={
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
className="flex items-center text-muted-foreground transition-colors hover:text-foreground"
|
|
103
|
+
/>
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
<Info className="size-4" />
|
|
107
|
+
</TooltipTrigger>
|
|
108
|
+
<TooltipContent side="top">{tooltipText}</TooltipContent>
|
|
109
|
+
</Tooltip>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{/* ── Bar ── */}
|
|
117
|
+
<div
|
|
118
|
+
className="mt-4 mb-6 flex h-8 w-full gap-px"
|
|
119
|
+
onMouseLeave={() => setHoveredIndex(-1)}
|
|
120
|
+
>
|
|
121
|
+
{parts.length === 0 ? (
|
|
122
|
+
<div className="grow bg-muted" />
|
|
123
|
+
) : (
|
|
124
|
+
parts.map((part, index) => {
|
|
125
|
+
const isHovered = hoveredIndex === index;
|
|
126
|
+
const showIcon = part.percentage > 0.01;
|
|
127
|
+
const icon = icons[index];
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Tooltip key={part.id} open={isHovered}>
|
|
131
|
+
<TooltipTrigger
|
|
132
|
+
render={
|
|
133
|
+
<div
|
|
134
|
+
className={cn(
|
|
135
|
+
"relative border border-transparent transition-colors duration-200",
|
|
136
|
+
segmentBase,
|
|
137
|
+
isHovered && segmentHover,
|
|
138
|
+
)}
|
|
139
|
+
style={{
|
|
140
|
+
flexGrow: Math.max(part.percentage, 0.0001) * 10,
|
|
141
|
+
}}
|
|
142
|
+
onMouseEnter={() => setHoveredIndex(index)}
|
|
143
|
+
/>
|
|
144
|
+
}
|
|
145
|
+
>
|
|
146
|
+
{showIcon && icon && (
|
|
147
|
+
<div
|
|
148
|
+
className={cn(
|
|
149
|
+
"absolute left-2 top-0 bottom-0 flex items-center [&_svg]:size-4",
|
|
150
|
+
isHovered ? iconHovered : iconDefault,
|
|
151
|
+
)}
|
|
152
|
+
>
|
|
153
|
+
{icon}
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
</TooltipTrigger>
|
|
157
|
+
|
|
158
|
+
<TooltipContent side="top">
|
|
159
|
+
<div className="flex flex-col gap-1.5 min-w-[120px]">
|
|
160
|
+
<div className="flex items-center gap-2">
|
|
161
|
+
{icon && <span className="[&_svg]:size-4">{icon}</span>}
|
|
162
|
+
<span className="text-sm font-semibold leading-tight line-clamp-2">
|
|
163
|
+
{part.title}
|
|
164
|
+
</span>
|
|
165
|
+
</div>
|
|
166
|
+
<span className="self-end text-sm font-bold">
|
|
167
|
+
{formatCurrency(part.amount)}
|
|
168
|
+
</span>
|
|
169
|
+
</div>
|
|
170
|
+
</TooltipContent>
|
|
171
|
+
</Tooltip>
|
|
172
|
+
);
|
|
173
|
+
})
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
@@ -88,6 +88,12 @@ export interface IncomeBarChartProps {
|
|
|
88
88
|
className?: string;
|
|
89
89
|
/** Show skeleton loading state instead of the chart */
|
|
90
90
|
isLoading?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Show the internal period selector buttons (3M / 6M / 12M).
|
|
93
|
+
* Set to `false` when the chart is driven by an external period control.
|
|
94
|
+
* Defaults to `true`.
|
|
95
|
+
*/
|
|
96
|
+
showPeriodSelector?: boolean;
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
// ---------------------------------------------------------------------------
|
|
@@ -111,6 +117,7 @@ export function IncomeBarChart({
|
|
|
111
117
|
width = "100%",
|
|
112
118
|
className,
|
|
113
119
|
isLoading = false,
|
|
120
|
+
showPeriodSelector = true,
|
|
114
121
|
}: IncomeBarChartProps) {
|
|
115
122
|
const periods = CHART_PERIODS[granularity];
|
|
116
123
|
const [period, setPeriod] = useState<IncomePeriod>(defaultPeriod);
|
|
@@ -216,7 +223,7 @@ export function IncomeBarChart({
|
|
|
216
223
|
stacked: true,
|
|
217
224
|
grid: { display: false },
|
|
218
225
|
border: { display: false },
|
|
219
|
-
ticks: { font: { size:
|
|
226
|
+
ticks: { font: { size: 12 }, color: FALLBACK_TICK },
|
|
220
227
|
},
|
|
221
228
|
y: {
|
|
222
229
|
display: showYAxis,
|
|
@@ -224,7 +231,7 @@ export function IncomeBarChart({
|
|
|
224
231
|
grid: { display: false },
|
|
225
232
|
border: { display: false },
|
|
226
233
|
ticks: {
|
|
227
|
-
font: { size:
|
|
234
|
+
font: { size: 12 },
|
|
228
235
|
color: FALLBACK_TICK,
|
|
229
236
|
maxTicksLimit: 5,
|
|
230
237
|
padding: 8,
|
|
@@ -241,23 +248,29 @@ export function IncomeBarChart({
|
|
|
241
248
|
className={cn("w-full py-4 sm:py-6 gap-2", className)}
|
|
242
249
|
style={{ maxWidth: width, fontFamily }}
|
|
243
250
|
>
|
|
244
|
-
|
|
245
|
-
<
|
|
246
|
-
{title
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
251
|
+
{(title || showPeriodSelector) && (
|
|
252
|
+
<CardHeader className="px-3 sm:px-6">
|
|
253
|
+
{title && (
|
|
254
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
255
|
+
{title}
|
|
256
|
+
</CardTitle>
|
|
257
|
+
)}
|
|
258
|
+
{showPeriodSelector && (
|
|
259
|
+
<CardAction>
|
|
260
|
+
<div className="flex gap-0.5 sm:gap-1">
|
|
261
|
+
{periods.map((p) => (
|
|
262
|
+
<ChartPeriodButton
|
|
263
|
+
key={p}
|
|
264
|
+
period={p}
|
|
265
|
+
active={period === p}
|
|
266
|
+
onClick={() => setPeriod(p)}
|
|
267
|
+
/>
|
|
268
|
+
))}
|
|
269
|
+
</div>
|
|
270
|
+
</CardAction>
|
|
271
|
+
)}
|
|
272
|
+
</CardHeader>
|
|
273
|
+
)}
|
|
261
274
|
|
|
262
275
|
<CardContent className="px-3 sm:px-6">
|
|
263
276
|
{isLoading ? (
|
|
@@ -75,7 +75,7 @@ export function IncomingOutgoingsCard({
|
|
|
75
75
|
return (
|
|
76
76
|
<div key={item.label} className="flex flex-col gap-1">
|
|
77
77
|
<div className="flex items-center justify-between gap-2">
|
|
78
|
-
<span className="flex items-center gap-1.5 text-sm text-foreground">
|
|
78
|
+
<span className="flex items-center gap-1.5 text-sm font-medium text-foreground">
|
|
79
79
|
{Icon && (
|
|
80
80
|
<Icon
|
|
81
81
|
size={16}
|
|
@@ -85,7 +85,7 @@ export function IncomingOutgoingsCard({
|
|
|
85
85
|
)}
|
|
86
86
|
{item.label}
|
|
87
87
|
</span>
|
|
88
|
-
<span className="shrink-0 text-sm font-
|
|
88
|
+
<span className="shrink-0 text-sm font-semibold text-foreground">
|
|
89
89
|
{formatCurrency(item.value)}
|
|
90
90
|
</span>
|
|
91
91
|
</div>
|
|
@@ -309,7 +309,7 @@ export function PropertyMobileEstimateLineChart({
|
|
|
309
309
|
maxRotation: 0,
|
|
310
310
|
minRotation: 0,
|
|
311
311
|
color: FALLBACK_TICK,
|
|
312
|
-
font: { size:
|
|
312
|
+
font: { size: 12, family: fontFamily },
|
|
313
313
|
maxTicksLimit: 12,
|
|
314
314
|
},
|
|
315
315
|
},
|
|
@@ -322,13 +322,13 @@ export function PropertyMobileEstimateLineChart({
|
|
|
322
322
|
padding: 8,
|
|
323
323
|
maxTicksLimit: 5,
|
|
324
324
|
color: FALLBACK_TICK,
|
|
325
|
-
font: { size:
|
|
325
|
+
font: { size: 12, family: fontFamily },
|
|
326
326
|
callback: (v) => formatAbbrev(Number(v)),
|
|
327
327
|
},
|
|
328
328
|
},
|
|
329
329
|
},
|
|
330
330
|
}),
|
|
331
|
-
[showXAxis, showYAxis, sliced],
|
|
331
|
+
[showXAxis, showYAxis, sliced, fontFamily],
|
|
332
332
|
);
|
|
333
333
|
|
|
334
334
|
return (
|
|
@@ -337,7 +337,7 @@ export function PropertyMobileEstimateLineChart({
|
|
|
337
337
|
style={{ maxWidth: width, fontFamily }}
|
|
338
338
|
>
|
|
339
339
|
<CardHeader className="px-3 sm:px-6">
|
|
340
|
-
<CardTitle className="text-xs font-semibold uppercase tracking-
|
|
340
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
|
341
341
|
{title}
|
|
342
342
|
</CardTitle>
|
|
343
343
|
{showPeriodSelector && (
|
|
@@ -35,7 +35,7 @@ export interface ScenarioListProps {
|
|
|
35
35
|
onDelete?: (id: string) => void;
|
|
36
36
|
/** Called when the Add button is clicked */
|
|
37
37
|
onAdd?: () => void;
|
|
38
|
-
/** Label for the add button (default: "
|
|
38
|
+
/** Label for the add button (default: "Add New Scenario") */
|
|
39
39
|
addLabel?: string;
|
|
40
40
|
/**
|
|
41
41
|
* Maximum number of scenarios allowed. When `scenarios.length >= maxScenarios`
|
|
@@ -60,7 +60,7 @@ export function ScenarioList({
|
|
|
60
60
|
onEdit,
|
|
61
61
|
onDelete,
|
|
62
62
|
onAdd,
|
|
63
|
-
addLabel = "
|
|
63
|
+
addLabel = "Add New Scenario",
|
|
64
64
|
maxScenarios,
|
|
65
65
|
isDraggable = true,
|
|
66
66
|
onReorder,
|
|
@@ -128,11 +128,13 @@ export function TransactionsLiabilitiesBreakdownChart({
|
|
|
128
128
|
className={cn("w-full py-4 sm:py-6 gap-2", className)}
|
|
129
129
|
style={{ maxWidth: width, fontFamily }}
|
|
130
130
|
>
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
131
|
+
{title && (
|
|
132
|
+
<CardHeader className="px-3 sm:px-6">
|
|
133
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
134
|
+
{title}
|
|
135
|
+
</CardTitle>
|
|
136
|
+
</CardHeader>
|
|
137
|
+
)}
|
|
136
138
|
|
|
137
139
|
<CardContent className="px-3 sm:px-6">
|
|
138
140
|
{isLoading ? (
|
|
@@ -4,29 +4,40 @@ import { cn } from "@/lib/utils";
|
|
|
4
4
|
/**
|
|
5
5
|
* Section header block used above each chart on the Money (Transactions) page.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* optional period text and footnote beneath.
|
|
7
|
+
* Two layout variants:
|
|
9
8
|
*
|
|
10
|
-
*
|
|
9
|
+
* `layout="vertical"` (default)
|
|
11
10
|
* ┌─────────────────────────────────────────┐
|
|
12
11
|
* │ $37,085 [optional action] │
|
|
13
12
|
* │ Cash Balance │
|
|
14
13
|
* │ 30 Days Total │
|
|
15
14
|
* │ (Based on connected bank transactions) │
|
|
16
15
|
* └─────────────────────────────────────────┘
|
|
16
|
+
*
|
|
17
|
+
* `layout="horizontal"`
|
|
18
|
+
* ┌─────────────────────────────────────────┐
|
|
19
|
+
* │ CASH BALANCE $37,085 │
|
|
20
|
+
* │ (Based on connected bank transactions) │
|
|
21
|
+
* └─────────────────────────────────────────┘
|
|
17
22
|
*/
|
|
18
23
|
|
|
19
24
|
export interface TransactionsSummaryBlockProps {
|
|
20
|
-
/** Pre-formatted total value — e.g. "$37,085" — displayed prominently
|
|
25
|
+
/** Pre-formatted total value — e.g. "$37,085" — displayed prominently */
|
|
21
26
|
value: string;
|
|
22
27
|
/** Section label — e.g. "Cash Balance", "Income", "Expense" */
|
|
23
28
|
label: string;
|
|
24
|
-
/** Period text — e.g. "30 Days Total" */
|
|
29
|
+
/** Period text — e.g. "30 Days Total" (vertical layout only) */
|
|
25
30
|
period?: string;
|
|
26
31
|
/** Small footnote — e.g. "(Based on connected bank transactions)" */
|
|
27
32
|
footnote?: string;
|
|
28
|
-
/** Optional trailing element — e.g. a Button for "Set Goal" */
|
|
33
|
+
/** Optional trailing element — e.g. a Button for "Set Goal" (vertical layout only) */
|
|
29
34
|
action?: React.ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* Layout variant.
|
|
37
|
+
* - `"vertical"` (default): value large on top, label + period below
|
|
38
|
+
* - `"horizontal"`: label small-caps left, value large right — mirrors Borrowing Capacity style
|
|
39
|
+
*/
|
|
40
|
+
layout?: "vertical" | "horizontal";
|
|
30
41
|
className?: string;
|
|
31
42
|
}
|
|
32
43
|
|
|
@@ -36,8 +47,30 @@ export function TransactionsSummaryBlock({
|
|
|
36
47
|
period,
|
|
37
48
|
footnote,
|
|
38
49
|
action,
|
|
50
|
+
layout = "vertical",
|
|
39
51
|
className,
|
|
40
52
|
}: TransactionsSummaryBlockProps) {
|
|
53
|
+
if (layout === "horizontal") {
|
|
54
|
+
return (
|
|
55
|
+
<div className={cn("flex flex-col gap-0.5 py-3", className)}>
|
|
56
|
+
<div className="flex items-baseline justify-between gap-4">
|
|
57
|
+
<p className="text-xs font-semibold uppercase tracking-widest text-muted-foreground">
|
|
58
|
+
{label}
|
|
59
|
+
</p>
|
|
60
|
+
<div className="flex shrink-0 items-baseline gap-3">
|
|
61
|
+
<p className="text-lg font-bold tabular-nums text-foreground">
|
|
62
|
+
{value}
|
|
63
|
+
</p>
|
|
64
|
+
{action && <div className="shrink-0">{action}</div>}
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
{footnote && (
|
|
68
|
+
<p className="text-sm text-muted-foreground">{footnote}</p>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
41
74
|
return (
|
|
42
75
|
<div
|
|
43
76
|
className={cn("flex items-start justify-between gap-2 py-3", className)}
|