@wealthx/shadcn 1.5.42 → 1.5.44

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.
Files changed (209) hide show
  1. package/.turbo/turbo-build.log +207 -202
  2. package/CHANGELOG.md +12 -0
  3. package/dist/{chunk-5FHBC6DY.mjs → chunk-33WZ5NCW.mjs} +1 -1
  4. package/dist/{chunk-LBXIYS34.mjs → chunk-4PVCJ3JD.mjs} +1 -1
  5. package/dist/{chunk-EHQL64B7.mjs → chunk-4SUXTO2Z.mjs} +4 -4
  6. package/dist/{chunk-BAONSY54.mjs → chunk-5RYH7SOQ.mjs} +1 -1
  7. package/dist/{chunk-3C4DZTGA.mjs → chunk-5XD7A7YC.mjs} +1 -1
  8. package/dist/{chunk-5DAQU3B6.mjs → chunk-66JXT7NY.mjs} +1 -1
  9. package/dist/{chunk-NGKTJRFN.mjs → chunk-6DO4EGT2.mjs} +2 -2
  10. package/dist/{chunk-C7ZTZTEW.mjs → chunk-6XJWL2E5.mjs} +1 -1
  11. package/dist/{chunk-C35JMOII.mjs → chunk-7RMXM5O6.mjs} +5 -5
  12. package/dist/{chunk-FQUT5XD6.mjs → chunk-A4UP4QFB.mjs} +1 -1
  13. package/dist/{chunk-USIRKDYQ.mjs → chunk-BFCX7ADE.mjs} +1 -1
  14. package/dist/{chunk-XGRSPFFC.mjs → chunk-CQHKU24Z.mjs} +1 -1
  15. package/dist/{chunk-HONTZFLO.mjs → chunk-DP4ER6TJ.mjs} +1 -1
  16. package/dist/{chunk-VLVEZHFE.mjs → chunk-EFSLAMHI.mjs} +4 -4
  17. package/dist/{chunk-FYZBGWYR.mjs → chunk-FVSOFXJQ.mjs} +1 -1
  18. package/dist/{chunk-JUMEIPII.mjs → chunk-G2MOZZPE.mjs} +8 -8
  19. package/dist/{chunk-D3HKFRQO.mjs → chunk-GQWKBESP.mjs} +8 -5
  20. package/dist/{chunk-MD66TGX7.mjs → chunk-GXDKWCMV.mjs} +1 -1
  21. package/dist/{chunk-77L3UPBW.mjs → chunk-H7NOUDU3.mjs} +5 -5
  22. package/dist/{chunk-4LLTZ45R.mjs → chunk-HOXTEU5K.mjs} +8 -7
  23. package/dist/{chunk-ZA37ZWZW.mjs → chunk-IXW77PMI.mjs} +7 -7
  24. package/dist/{chunk-XHZONBL4.mjs → chunk-JLEQU5BO.mjs} +1 -1
  25. package/dist/{chunk-6UKOJLXO.mjs → chunk-JSFWRD7K.mjs} +4 -4
  26. package/dist/{chunk-7PTRHNUV.mjs → chunk-JY3FUGNL.mjs} +1 -1
  27. package/dist/{chunk-3ZU5BH6X.mjs → chunk-KEOAPKJO.mjs} +3 -3
  28. package/dist/{chunk-4QTHK7ML.mjs → chunk-KWYFJQV6.mjs} +1 -1
  29. package/dist/{chunk-FGMDBJCF.mjs → chunk-LDPCSE7J.mjs} +4 -4
  30. package/dist/chunk-LFWNKXZU.mjs +109 -0
  31. package/dist/{chunk-IRZWYTGV.mjs → chunk-M32YSAWL.mjs} +8 -7
  32. package/dist/{chunk-LLAGF6BA.mjs → chunk-MUB2G36A.mjs} +1 -1
  33. package/dist/{chunk-DQNNP6I4.mjs → chunk-NIETQFJQ.mjs} +1 -1
  34. package/dist/{chunk-RUX3OLVZ.mjs → chunk-OTFG57ZF.mjs} +1 -1
  35. package/dist/{chunk-OKIWXOJL.mjs → chunk-OWTW5WAJ.mjs} +1 -1
  36. package/dist/{chunk-WWIWRNBK.mjs → chunk-P7NSCTAW.mjs} +1 -1
  37. package/dist/{chunk-BZWQU52U.mjs → chunk-QZREZL2F.mjs} +1 -1
  38. package/dist/{chunk-E432NK23.mjs → chunk-RBQ4BZUV.mjs} +6 -6
  39. package/dist/{chunk-I2EKKSEF.mjs → chunk-RKBLVNDC.mjs} +4 -7
  40. package/dist/{chunk-LHQACMZY.mjs → chunk-SPPQFW32.mjs} +106 -50
  41. package/dist/{chunk-OSSS56CB.mjs → chunk-SUXJWKRI.mjs} +4 -4
  42. package/dist/{chunk-SCGCGVDN.mjs → chunk-SZXIPE5J.mjs} +1 -1
  43. package/dist/{chunk-VVURVETY.mjs → chunk-TOQRA2TD.mjs} +1 -1
  44. package/dist/{chunk-GYWOD2YI.mjs → chunk-TZSDYQFH.mjs} +4 -4
  45. package/dist/{chunk-S7SBLNX4.mjs → chunk-UB3WG6I4.mjs} +1 -1
  46. package/dist/{chunk-PGJRZHN7.mjs → chunk-UVZ3JWFG.mjs} +1 -1
  47. package/dist/{chunk-UD5UF5OC.mjs → chunk-W7OPFKTZ.mjs} +4 -4
  48. package/dist/{chunk-YEWNFK5S.mjs → chunk-WLXP4OOF.mjs} +5 -5
  49. package/dist/{chunk-ORMC3TV3.mjs → chunk-XYXYTTNW.mjs} +1 -1
  50. package/dist/{chunk-CZOGJC76.mjs → chunk-YACFZWRR.mjs} +7 -7
  51. package/dist/{chunk-UTCW5YUX.mjs → chunk-YPATB6YQ.mjs} +9 -9
  52. package/dist/{chunk-BZGFW6L7.mjs → chunk-YWJAIPUA.mjs} +1 -1
  53. package/dist/{chunk-MHBQJVHE.mjs → chunk-Z65BGSHI.mjs} +5 -5
  54. package/dist/{chunk-PCULNQWA.mjs → chunk-ZGSFRUVI.mjs} +3 -3
  55. package/dist/{chunk-7NQKFPXE.mjs → chunk-ZRYG6ICN.mjs} +1 -1
  56. package/dist/{chunk-ZFKAYRFQ.mjs → chunk-ZUHFYW65.mjs} +1 -1
  57. package/dist/components/ui/about-you-form.mjs +2 -2
  58. package/dist/components/ui/account-list-carousel.mjs +2 -2
  59. package/dist/components/ui/add-column-modal.mjs +4 -4
  60. package/dist/components/ui/add-lead-modal.mjs +4 -4
  61. package/dist/components/ui/advisor-card.mjs +2 -2
  62. package/dist/components/ui/ai-assistant-drawer.mjs +2 -2
  63. package/dist/components/ui/ai-builder/index.mjs +4 -4
  64. package/dist/components/ui/ai-conversations/index.mjs +4 -4
  65. package/dist/components/ui/alert-dialog.mjs +3 -3
  66. package/dist/components/ui/applicant-expenses-section.mjs +1 -1
  67. package/dist/components/ui/appointment-action-dialogs.mjs +5 -5
  68. package/dist/components/ui/appointment-availability-settings.mjs +4 -4
  69. package/dist/components/ui/appointment-book-dialog.mjs +4 -4
  70. package/dist/components/ui/appointment-detail-sheet.mjs +6 -6
  71. package/dist/components/ui/appointment-upcoming-card.mjs +4 -4
  72. package/dist/components/ui/asset-accordion.mjs +7 -7
  73. package/dist/components/ui/assets-liabilities-side-card.js +19 -66
  74. package/dist/components/ui/assets-liabilities-side-card.mjs +22 -69
  75. package/dist/components/ui/backoffice-alert-history-chart.js +1 -1
  76. package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -5
  77. package/dist/components/ui/backoffice-alert-matching-chart.js +1 -1
  78. package/dist/components/ui/backoffice-alert-matching-chart.mjs +5 -5
  79. package/dist/components/ui/backoffice-alerts-chart.js +1 -1
  80. package/dist/components/ui/backoffice-alerts-chart.mjs +5 -5
  81. package/dist/components/ui/backoffice-connections-chart.js +1 -1
  82. package/dist/components/ui/backoffice-connections-chart.mjs +5 -5
  83. package/dist/components/ui/backoffice-contact-history-chart.js +1 -1
  84. package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -5
  85. package/dist/components/ui/backoffice-contact-matching-chart.js +1 -1
  86. package/dist/components/ui/backoffice-contact-matching-chart.mjs +5 -5
  87. package/dist/components/ui/backoffice-signup-steps.mjs +4 -4
  88. package/dist/components/ui/bank-statement-generate-dialog.mjs +4 -4
  89. package/dist/components/ui/bank-statement-pdf-viewer.mjs +4 -4
  90. package/dist/components/ui/borrowing-capacity-atoms.js +3 -6
  91. package/dist/components/ui/borrowing-capacity-atoms.mjs +2 -2
  92. package/dist/components/ui/borrowing-capacity-card.js +5 -5
  93. package/dist/components/ui/borrowing-capacity-card.mjs +6 -6
  94. package/dist/components/ui/borrowing-capacity-line-chart.js +5 -5
  95. package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -5
  96. package/dist/components/ui/calculator-section.mjs +4 -4
  97. package/dist/components/ui/cash-balance-line-chart.js +102 -46
  98. package/dist/components/ui/cash-balance-line-chart.mjs +5 -5
  99. package/dist/components/ui/cashflow-bar-chart.js +7 -4
  100. package/dist/components/ui/cashflow-bar-chart.mjs +5 -5
  101. package/dist/components/ui/category-edit-dialog.js +1 -1
  102. package/dist/components/ui/category-edit-dialog.mjs +4 -4
  103. package/dist/components/ui/color-picker.mjs +2 -2
  104. package/dist/components/ui/contact-alert-dialog/index.mjs +4 -4
  105. package/dist/components/ui/create-contact-modal.mjs +4 -4
  106. package/dist/components/ui/csv-import-modal.mjs +4 -4
  107. package/dist/components/ui/dashboard-expense-categories.js +99 -66
  108. package/dist/components/ui/dashboard-expense-categories.mjs +104 -69
  109. package/dist/components/ui/dashboard-transactions-table.js +19 -9
  110. package/dist/components/ui/dashboard-transactions-table.mjs +26 -16
  111. package/dist/components/ui/data-table.mjs +2 -2
  112. package/dist/components/ui/date-picker.mjs +2 -2
  113. package/dist/components/ui/debt-accordion.mjs +7 -7
  114. package/dist/components/ui/delete-contact-component.mjs +4 -4
  115. package/dist/components/ui/dialog.mjs +3 -3
  116. package/dist/components/ui/document-checklist-template.mjs +2 -2
  117. package/dist/components/ui/expense-bar-chart.js +8 -7
  118. package/dist/components/ui/expense-bar-chart.mjs +5 -5
  119. package/dist/components/ui/expense-categories-bar.js +261 -0
  120. package/dist/components/ui/expense-categories-bar.mjs +12 -0
  121. package/dist/components/ui/expense-work-details.js +8 -7
  122. package/dist/components/ui/expense-work-details.mjs +7 -7
  123. package/dist/components/ui/file-preview-dialog.mjs +4 -4
  124. package/dist/components/ui/financial-cards.mjs +2 -2
  125. package/dist/components/ui/financial-drawers.mjs +2 -2
  126. package/dist/components/ui/financial-sections.mjs +3 -3
  127. package/dist/components/ui/frontend-signup-steps.mjs +2 -2
  128. package/dist/components/ui/income-bar-chart.js +8 -7
  129. package/dist/components/ui/income-bar-chart.mjs +5 -5
  130. package/dist/components/ui/income-sources-card.mjs +1 -1
  131. package/dist/components/ui/income-summary-component.mjs +1 -1
  132. package/dist/components/ui/income-work-details.js +8 -7
  133. package/dist/components/ui/income-work-details.mjs +6 -6
  134. package/dist/components/ui/incoming-outgoings-card.js +2 -2
  135. package/dist/components/ui/incoming-outgoings-card.mjs +3 -3
  136. package/dist/components/ui/interest-rate-section.mjs +1 -1
  137. package/dist/components/ui/kanban-column.mjs +5 -5
  138. package/dist/components/ui/loan-application-cards.mjs +3 -3
  139. package/dist/components/ui/loan-financials.mjs +3 -3
  140. package/dist/components/ui/money-input-with-slider.mjs +2 -2
  141. package/dist/components/ui/opportunity-card.mjs +4 -4
  142. package/dist/components/ui/opportunity-edit-modals.mjs +4 -4
  143. package/dist/components/ui/opportunity-summary-tab.mjs +8 -8
  144. package/dist/components/ui/pagination.mjs +2 -2
  145. package/dist/components/ui/pipeline-board.mjs +6 -6
  146. package/dist/components/ui/pipeline-chart.mjs +2 -2
  147. package/dist/components/ui/pipeline-dialogs.mjs +4 -4
  148. package/dist/components/ui/policy-ai/index.mjs +2 -2
  149. package/dist/components/ui/property-asset-card.mjs +4 -4
  150. package/dist/components/ui/property-cashflow-doughnut-chart.js +3 -3
  151. package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -5
  152. package/dist/components/ui/property-debt-equity-doughnut-chart.js +3 -3
  153. package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -5
  154. package/dist/components/ui/property-list-carousel.mjs +2 -2
  155. package/dist/components/ui/property-mobile-estimate-line-chart.js +4 -4
  156. package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -5
  157. package/dist/components/ui/property-report-dialog.mjs +5 -5
  158. package/dist/components/ui/resource-center/index.mjs +4 -4
  159. package/dist/components/ui/review-alerts-dialog.mjs +4 -4
  160. package/dist/components/ui/savings-goal-modal.mjs +7 -7
  161. package/dist/components/ui/scenario-drawer.mjs +4 -4
  162. package/dist/components/ui/scenario-list.js +4 -7
  163. package/dist/components/ui/scenario-list.mjs +5 -5
  164. package/dist/components/ui/share-details-dialog.mjs +4 -4
  165. package/dist/components/ui/sidebar-nav.mjs +4 -4
  166. package/dist/components/ui/signup-form-primitives.mjs +2 -2
  167. package/dist/components/ui/stage-timeline.mjs +1 -1
  168. package/dist/components/ui/support-agent/index.mjs +2 -2
  169. package/dist/components/ui/top-three-product.mjs +1 -1
  170. package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +3 -3
  171. package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -5
  172. package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -5
  173. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +4 -4
  174. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -5
  175. package/dist/components/ui/transactions-summary-block.js +13 -0
  176. package/dist/components/ui/transactions-summary-block.mjs +13 -0
  177. package/dist/index.js +2092 -1935
  178. package/dist/index.mjs +138 -134
  179. package/dist/lib/format-currency.js +54 -0
  180. package/dist/lib/format-currency.mjs +9 -0
  181. package/dist/styles.css +1 -1
  182. package/package.json +6 -1
  183. package/src/component-descriptions/assets-liabilities-side-card.md +19 -0
  184. package/src/component-descriptions/pipeline-chart.md +17 -0
  185. package/src/components/index.tsx +6 -0
  186. package/src/components/ui/assets-liabilities-side-card.tsx +43 -83
  187. package/src/components/ui/borrowing-capacity-atoms.tsx +4 -7
  188. package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -4
  189. package/src/components/ui/cash-balance-line-chart.tsx +123 -42
  190. package/src/components/ui/cashflow-bar-chart.tsx +7 -4
  191. package/src/components/ui/category-edit-dialog.tsx +1 -1
  192. package/src/components/ui/chart-shared.tsx +4 -4
  193. package/src/components/ui/dashboard-expense-categories.tsx +139 -63
  194. package/src/components/ui/dashboard-transactions-table.tsx +51 -15
  195. package/src/components/ui/expense-bar-chart.tsx +32 -19
  196. package/src/components/ui/expense-categories-bar.tsx +178 -0
  197. package/src/components/ui/income-bar-chart.tsx +32 -19
  198. package/src/components/ui/incoming-outgoings-card.tsx +2 -2
  199. package/src/components/ui/property-mobile-estimate-line-chart.tsx +4 -4
  200. package/src/components/ui/scenario-list.tsx +2 -2
  201. package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +7 -5
  202. package/src/components/ui/transactions-summary-block.tsx +39 -6
  203. package/src/styles/styles-css.ts +1 -1
  204. package/tsup.config.ts +2 -0
  205. package/dist/{chunk-CEYEK3TI.mjs → chunk-B4R62ID3.mjs} +3 -3
  206. package/dist/{chunk-7LN5OGC2.mjs → chunk-E3VAK4EB.mjs} +3 -3
  207. package/dist/{chunk-EY36WDCF.mjs → chunk-EEZFXE3P.mjs} +3 -3
  208. package/dist/{chunk-T5FRVEJQ.mjs → chunk-JTMN36BK.mjs} +3 -3
  209. /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: 10 }, color: FALLBACK_TICK },
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: 10 },
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
- <CardHeader className="px-3 sm:px-6">
245
- <CardTitle className="text-xs font-semibold uppercase tracking-wide">
246
- {title}
247
- </CardTitle>
248
- <CardAction>
249
- <div className="flex gap-0.5 sm:gap-1">
250
- {periods.map((p) => (
251
- <ChartPeriodButton
252
- key={p}
253
- period={p}
254
- active={period === p}
255
- onClick={() => setPeriod(p)}
256
- />
257
- ))}
258
- </div>
259
- </CardAction>
260
- </CardHeader>
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-medium text-foreground">
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: 10 },
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: 10 },
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-wide">
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: "Compare Loan Options") */
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 = "Compare Loan Options",
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
- <CardHeader className="px-3 sm:px-6">
132
- <CardTitle className="text-xs font-semibold uppercase tracking-wide">
133
- {title}
134
- </CardTitle>
135
- </CardHeader>
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
- * Matches the app design: large value at the top, category label below,
8
- * optional period text and footnote beneath.
7
+ * Two layout variants:
9
8
  *
10
- * Layout:
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 at top */
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)}