@wealthx/shadcn 1.5.37 → 1.5.39
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 +142 -133
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-LSSIWLYU.mjs → chunk-6XNEHTII.mjs} +1 -1
- package/dist/{chunk-ULQ53FRJ.mjs → chunk-7NQKFPXE.mjs} +1 -1
- package/dist/{chunk-734FOOJC.mjs → chunk-B5PSUONN.mjs} +25 -58
- package/dist/{chunk-DSVKEVX6.mjs → chunk-CZOGJC76.mjs} +1 -1
- package/dist/chunk-EFHPSKVF.mjs +192 -0
- package/dist/{chunk-JPGL36WQ.mjs → chunk-FL7DEYUA.mjs} +6 -7
- package/dist/{chunk-2CHH5QOA.mjs → chunk-FQUT5XD6.mjs} +1 -1
- package/dist/chunk-MGIDYXOP.mjs +814 -0
- package/dist/{chunk-OG2VM34K.mjs → chunk-MHBQJVHE.mjs} +1 -1
- package/dist/{chunk-NB3ZL36B.mjs → chunk-MZI77ZMX.mjs} +17 -2
- package/dist/chunk-R7M657QL.mjs +587 -0
- package/dist/{chunk-DIH2NZZ3.mjs → chunk-RRROLESJ.mjs} +33 -23
- package/dist/components/ui/ai-assistant-drawer.js +269 -121
- package/dist/components/ui/ai-assistant-drawer.mjs +2 -1
- package/dist/components/ui/ai-conversations/index.js +474 -286
- package/dist/components/ui/ai-conversations/index.mjs +2 -1
- package/dist/components/ui/chat-input-area.js +429 -0
- package/dist/components/ui/chat-input-area.mjs +11 -0
- package/dist/components/ui/file-preview-dialog.js +6 -7
- package/dist/components/ui/file-preview-dialog.mjs +2 -2
- package/dist/components/ui/kanban-column.js +6 -7
- package/dist/components/ui/kanban-column.mjs +3 -3
- package/dist/components/ui/opportunity-card.js +6 -7
- package/dist/components/ui/opportunity-card.mjs +2 -2
- package/dist/components/ui/page-top-bar.js +182 -5
- package/dist/components/ui/page-top-bar.mjs +3 -1
- package/dist/components/ui/pipeline-board.js +6 -7
- package/dist/components/ui/pipeline-board.mjs +4 -4
- package/dist/components/ui/policy-ai/index.js +1636 -0
- package/dist/components/ui/policy-ai/index.mjs +36 -0
- package/dist/components/ui/progress.js +6 -7
- package/dist/components/ui/progress.mjs +1 -1
- package/dist/components/ui/stage-timeline.js +6 -7
- package/dist/components/ui/stage-timeline.mjs +2 -2
- package/dist/components/ui/support-agent/index.js +1131 -0
- package/dist/components/ui/support-agent/index.mjs +27 -0
- package/dist/index.js +5609 -4100
- package/dist/index.mjs +77 -41
- package/dist/styles.css +1 -1
- package/package.json +16 -1
- package/src/components/index.tsx +54 -0
- package/src/components/ui/ai-assistant-drawer.tsx +24 -51
- package/src/components/ui/ai-conversations/index.tsx +16 -8
- package/src/components/ui/ai-conversations/thread.tsx +38 -27
- package/src/components/ui/chat-input-area.tsx +244 -0
- package/src/components/ui/page-top-bar.tsx +31 -5
- package/src/components/ui/policy-ai/index.tsx +41 -0
- package/src/components/ui/policy-ai/policy-ai-panel.tsx +526 -0
- package/src/components/ui/policy-ai/policy-ai-primitives.tsx +332 -0
- package/src/components/ui/policy-ai/policy-ai-responses.tsx +543 -0
- package/src/components/ui/progress.tsx +15 -12
- package/src/components/ui/support-agent/index.tsx +25 -0
- package/src/components/ui/support-agent/support-agent-fab.tsx +116 -0
- package/src/components/ui/support-agent/support-agent-panel.tsx +498 -0
- package/src/components/ui/support-agent/support-agent-primitives.tsx +354 -0
- package/src/styles/globals.css +1 -0
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +3 -0
|
@@ -0,0 +1,1636 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __objRest = (source, exclude) => {
|
|
26
|
+
var target = {};
|
|
27
|
+
for (var prop in source)
|
|
28
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
if (source != null && __getOwnPropSymbols)
|
|
31
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
32
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
33
|
+
target[prop] = source[prop];
|
|
34
|
+
}
|
|
35
|
+
return target;
|
|
36
|
+
};
|
|
37
|
+
var __export = (target, all) => {
|
|
38
|
+
for (var name in all)
|
|
39
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
40
|
+
};
|
|
41
|
+
var __copyProps = (to, from, except, desc) => {
|
|
42
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
43
|
+
for (let key of __getOwnPropNames(from))
|
|
44
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
45
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
46
|
+
}
|
|
47
|
+
return to;
|
|
48
|
+
};
|
|
49
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
50
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
51
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
52
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
53
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
54
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
55
|
+
mod
|
|
56
|
+
));
|
|
57
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
58
|
+
|
|
59
|
+
// src/components/ui/policy-ai/index.tsx
|
|
60
|
+
var policy_ai_exports = {};
|
|
61
|
+
__export(policy_ai_exports, {
|
|
62
|
+
PolicyAIFAB: () => PolicyAIFAB,
|
|
63
|
+
PolicyAIPanel: () => PolicyAIPanel,
|
|
64
|
+
PolicyCitationPanel: () => PolicyCitationPanel,
|
|
65
|
+
PolicyComparisonTable: () => PolicyComparisonTable,
|
|
66
|
+
PolicyQueryChip: () => PolicyQueryChip,
|
|
67
|
+
PolicyRankedList: () => PolicyRankedList,
|
|
68
|
+
PolicySingleBankAnswer: () => PolicySingleBankAnswer,
|
|
69
|
+
PolicyVerdictBadge: () => PolicyVerdictBadge
|
|
70
|
+
});
|
|
71
|
+
module.exports = __toCommonJS(policy_ai_exports);
|
|
72
|
+
|
|
73
|
+
// src/components/ui/policy-ai/policy-ai-primitives.tsx
|
|
74
|
+
var React2 = __toESM(require("react"));
|
|
75
|
+
var import_lucide_react2 = require("lucide-react");
|
|
76
|
+
|
|
77
|
+
// src/lib/utils.ts
|
|
78
|
+
var import_clsx = require("clsx");
|
|
79
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
80
|
+
var twMerge = (0, import_tailwind_merge.extendTailwindMerge)({
|
|
81
|
+
extend: {
|
|
82
|
+
classGroups: {
|
|
83
|
+
"font-size": [
|
|
84
|
+
{
|
|
85
|
+
text: [
|
|
86
|
+
"display-large",
|
|
87
|
+
"display-medium",
|
|
88
|
+
"display-small",
|
|
89
|
+
"h1",
|
|
90
|
+
"h2",
|
|
91
|
+
"h3",
|
|
92
|
+
"h4",
|
|
93
|
+
"h5",
|
|
94
|
+
"h6",
|
|
95
|
+
"body-large",
|
|
96
|
+
"body-medium",
|
|
97
|
+
"body-small",
|
|
98
|
+
"label-large",
|
|
99
|
+
"label-medium",
|
|
100
|
+
"label-small",
|
|
101
|
+
"button",
|
|
102
|
+
"button-xs",
|
|
103
|
+
"caption",
|
|
104
|
+
"overline",
|
|
105
|
+
"code"
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
function cn(...inputs) {
|
|
113
|
+
return twMerge((0, import_clsx.clsx)(inputs));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/components/ui/badge.tsx
|
|
117
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
118
|
+
|
|
119
|
+
// src/lib/slot.tsx
|
|
120
|
+
var React = __toESM(require("react"));
|
|
121
|
+
function mergeRefs(...refs) {
|
|
122
|
+
return (value) => {
|
|
123
|
+
for (const ref of refs) {
|
|
124
|
+
if (typeof ref === "function") ref(value);
|
|
125
|
+
else if (ref !== null)
|
|
126
|
+
ref.current = value;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
var Slot = React.forwardRef(
|
|
131
|
+
(_a, forwardedRef) => {
|
|
132
|
+
var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
|
|
133
|
+
const child = React.Children.only(children);
|
|
134
|
+
if (!React.isValidElement(child)) return null;
|
|
135
|
+
const childProps = child.props;
|
|
136
|
+
const merged = __spreadValues({}, props);
|
|
137
|
+
for (const key of Object.keys(childProps)) {
|
|
138
|
+
if (key === "className") {
|
|
139
|
+
merged.className = [props.className, childProps.className].filter(Boolean).join(" ");
|
|
140
|
+
} else if (key === "style") {
|
|
141
|
+
merged.style = __spreadValues(__spreadValues({}, props.style), childProps.style);
|
|
142
|
+
} else if (key.startsWith("on") && typeof childProps[key] === "function") {
|
|
143
|
+
const parentHandler = props[key];
|
|
144
|
+
if (typeof parentHandler === "function") {
|
|
145
|
+
merged[key] = (...args) => {
|
|
146
|
+
childProps[key](...args);
|
|
147
|
+
parentHandler(...args);
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
merged[key] = childProps[key];
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
merged[key] = childProps[key];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const childRef = child.ref;
|
|
157
|
+
merged.ref = forwardedRef ? mergeRefs(forwardedRef, childRef) : childRef;
|
|
158
|
+
return React.cloneElement(
|
|
159
|
+
child,
|
|
160
|
+
merged
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
Slot.displayName = "Slot";
|
|
165
|
+
|
|
166
|
+
// src/components/ui/badge.tsx
|
|
167
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
168
|
+
var badgeVariants = (0, import_class_variance_authority.cva)(
|
|
169
|
+
"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2.5 py-0.5 text-caption whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3",
|
|
170
|
+
{
|
|
171
|
+
variants: {
|
|
172
|
+
variant: {
|
|
173
|
+
default: "border-primary/40 bg-primary/10 text-foreground [a&]:hover:bg-primary/15",
|
|
174
|
+
secondary: "border-border bg-muted text-muted-foreground [a&]:hover:bg-muted/80",
|
|
175
|
+
destructive: "border-destructive/40 bg-destructive/10 text-destructive-text focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/15",
|
|
176
|
+
success: "border-success/40 bg-success/10 text-success-text [a&]:hover:bg-success/15",
|
|
177
|
+
warning: "border-warning/40 bg-warning/10 text-warning-text [a&]:hover:bg-warning/15",
|
|
178
|
+
info: "border-info/40 bg-info/10 text-info-text [a&]:hover:bg-info/15",
|
|
179
|
+
outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
180
|
+
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
181
|
+
link: "text-primary underline-offset-4 [a&]:hover:underline"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
defaultVariants: {
|
|
185
|
+
variant: "default"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
function Badge(_a) {
|
|
190
|
+
var _b = _a, {
|
|
191
|
+
className,
|
|
192
|
+
variant = "default",
|
|
193
|
+
asChild = false
|
|
194
|
+
} = _b, props = __objRest(_b, [
|
|
195
|
+
"className",
|
|
196
|
+
"variant",
|
|
197
|
+
"asChild"
|
|
198
|
+
]);
|
|
199
|
+
const Comp = asChild ? Slot : "span";
|
|
200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
201
|
+
Comp,
|
|
202
|
+
__spreadValues({
|
|
203
|
+
className: cn(badgeVariants({ variant }), className),
|
|
204
|
+
"data-slot": "badge",
|
|
205
|
+
"data-variant": variant
|
|
206
|
+
}, props)
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/components/ui/button.tsx
|
|
211
|
+
var import_react = require("react");
|
|
212
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
213
|
+
var import_lucide_react = require("lucide-react");
|
|
214
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
215
|
+
var buttonVariants = (0, import_class_variance_authority2.cva)(
|
|
216
|
+
"inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 font-sans text-button whitespace-nowrap transition-all active:scale-[0.98] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
217
|
+
{
|
|
218
|
+
variants: {
|
|
219
|
+
variant: {
|
|
220
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
221
|
+
secondary: "bg-brand-secondary text-brand-secondary-foreground shadow-xs hover:bg-brand-secondary/80 focus-visible:ring-brand-secondary/30",
|
|
222
|
+
destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
223
|
+
outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground focus-visible:border-border focus-visible:ring-border/50 dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
224
|
+
"outline-primary": "border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50",
|
|
225
|
+
"outline-secondary": "border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:border-brand-secondary focus-visible:ring-brand-secondary/30",
|
|
226
|
+
ghost: "hover:bg-accent hover:text-accent-foreground hover:shadow-xs focus-visible:ring-border/50 dark:hover:bg-accent/50",
|
|
227
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
228
|
+
},
|
|
229
|
+
size: {
|
|
230
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
231
|
+
xs: "h-6 gap-1 px-2 text-button-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
232
|
+
sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
233
|
+
lg: "h-10 px-6 has-[>svg]:px-4",
|
|
234
|
+
icon: "size-9",
|
|
235
|
+
"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
236
|
+
"icon-sm": "size-8",
|
|
237
|
+
"icon-lg": "size-10"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
defaultVariants: {
|
|
241
|
+
variant: "default",
|
|
242
|
+
size: "default"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
var Button = (0, import_react.forwardRef)(function Button2(_a, ref) {
|
|
247
|
+
var _b = _a, {
|
|
248
|
+
className,
|
|
249
|
+
variant,
|
|
250
|
+
size,
|
|
251
|
+
asChild = false,
|
|
252
|
+
loading = false,
|
|
253
|
+
disabled,
|
|
254
|
+
type = "button",
|
|
255
|
+
children
|
|
256
|
+
} = _b, props = __objRest(_b, [
|
|
257
|
+
"className",
|
|
258
|
+
"variant",
|
|
259
|
+
"size",
|
|
260
|
+
"asChild",
|
|
261
|
+
"loading",
|
|
262
|
+
"disabled",
|
|
263
|
+
"type",
|
|
264
|
+
"children"
|
|
265
|
+
]);
|
|
266
|
+
const Comp = asChild ? Slot : "button";
|
|
267
|
+
const isIconOnly = size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg";
|
|
268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
269
|
+
Comp,
|
|
270
|
+
__spreadProps(__spreadValues({
|
|
271
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
272
|
+
"data-size": size,
|
|
273
|
+
"data-slot": "button",
|
|
274
|
+
"data-variant": variant,
|
|
275
|
+
disabled: loading || disabled,
|
|
276
|
+
ref,
|
|
277
|
+
type
|
|
278
|
+
}, props), {
|
|
279
|
+
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { "aria-hidden": "true", className: "animate-spin" }),
|
|
281
|
+
!isIconOnly && children
|
|
282
|
+
] }) : children
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// src/components/ui/policy-ai/policy-ai-primitives.tsx
|
|
288
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
289
|
+
var POLICY_TYPE_COLORS = {
|
|
290
|
+
Income: "text-primary",
|
|
291
|
+
Security: "text-warning",
|
|
292
|
+
Serviceability: "text-info",
|
|
293
|
+
"Loan Type": "text-secondary",
|
|
294
|
+
Borrower: "text-success"
|
|
295
|
+
};
|
|
296
|
+
var QUERY_TYPE_LABELS = {
|
|
297
|
+
single_bank: "Single bank",
|
|
298
|
+
cross_bank_comparison: "Cross-bank",
|
|
299
|
+
threshold_filter: "Filter",
|
|
300
|
+
ranking: "Ranking",
|
|
301
|
+
scenario_match: "Scenario",
|
|
302
|
+
general: "General"
|
|
303
|
+
};
|
|
304
|
+
function PolicyQueryChip({ context, className }) {
|
|
305
|
+
const { policyType, categories, queryType, bankName } = context;
|
|
306
|
+
const typeColor = POLICY_TYPE_COLORS[policyType];
|
|
307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
308
|
+
"div",
|
|
309
|
+
{
|
|
310
|
+
"data-slot": "policy-query-chip",
|
|
311
|
+
className: cn(
|
|
312
|
+
"inline-flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground",
|
|
313
|
+
className
|
|
314
|
+
),
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.Tag, { className: "size-3 shrink-0", "aria-hidden": "true" }),
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn("font-medium", typeColor), children: policyType }),
|
|
318
|
+
bankName && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
319
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-border", children: "\xB7" }),
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-foreground", children: bankName })
|
|
321
|
+
] }),
|
|
322
|
+
categories.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-border", children: "\xB7" }),
|
|
324
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: categories.join(", ") })
|
|
325
|
+
] }),
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { variant: "outline", className: "text-xs px-1.5 py-0 shrink-0", children: QUERY_TYPE_LABELS[queryType] })
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
var VERDICT_CONFIG = {
|
|
332
|
+
yes: { variant: "success", label: "Yes" },
|
|
333
|
+
soft_no: { variant: "warning", label: "Soft No" },
|
|
334
|
+
no: { variant: "destructive", label: "No" },
|
|
335
|
+
unknown: { variant: "secondary", label: "\u2014" }
|
|
336
|
+
};
|
|
337
|
+
function PolicyVerdictBadge({
|
|
338
|
+
verdict,
|
|
339
|
+
className
|
|
340
|
+
}) {
|
|
341
|
+
const { variant, label } = VERDICT_CONFIG[verdict];
|
|
342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
343
|
+
Badge,
|
|
344
|
+
{
|
|
345
|
+
"data-slot": "policy-verdict-badge",
|
|
346
|
+
variant,
|
|
347
|
+
className: cn("shrink-0", className),
|
|
348
|
+
children: label
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
function PolicyCitationPanel({
|
|
353
|
+
citations,
|
|
354
|
+
className
|
|
355
|
+
}) {
|
|
356
|
+
const [open, setOpen] = React2.useState(false);
|
|
357
|
+
if (citations.length === 0) return null;
|
|
358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
359
|
+
"div",
|
|
360
|
+
{
|
|
361
|
+
"data-slot": "policy-citation-panel",
|
|
362
|
+
className: cn("border-t border-border", className),
|
|
363
|
+
children: [
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
365
|
+
Button,
|
|
366
|
+
{
|
|
367
|
+
variant: "ghost",
|
|
368
|
+
size: "sm",
|
|
369
|
+
className: "w-full justify-between px-0 text-xs text-muted-foreground hover:text-foreground hover:bg-transparent gap-1",
|
|
370
|
+
onClick: () => setOpen((v) => !v),
|
|
371
|
+
"aria-expanded": open,
|
|
372
|
+
children: [
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.FileText, { className: "size-3", "aria-hidden": "true" }),
|
|
375
|
+
"View sources (",
|
|
376
|
+
citations.length,
|
|
377
|
+
")"
|
|
378
|
+
] }),
|
|
379
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronUp, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react2.ChevronDown, { className: "size-3", "aria-hidden": "true" })
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
),
|
|
383
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "mt-1 flex flex-col gap-2 pb-1", children: citations.map((cite) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { className: "flex gap-2 text-xs", children: [
|
|
384
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "shrink-0 flex items-center justify-center size-4 bg-muted text-muted-foreground font-mono font-semibold text-xs", children: cite.index }),
|
|
385
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-foreground", children: cite.bankName }),
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: cite.category })
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-muted-foreground leading-relaxed line-clamp-3", children: cite.excerpt })
|
|
391
|
+
] })
|
|
392
|
+
] }, cite.index)) })
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// src/components/ui/policy-ai/policy-ai-responses.tsx
|
|
399
|
+
var React5 = __toESM(require("react"));
|
|
400
|
+
var import_lucide_react3 = require("lucide-react");
|
|
401
|
+
|
|
402
|
+
// src/components/ui/input.tsx
|
|
403
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
404
|
+
function Input(_a) {
|
|
405
|
+
var _b = _a, { className, type } = _b, props = __objRest(_b, ["className", "type"]);
|
|
406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
407
|
+
"input",
|
|
408
|
+
__spreadValues({
|
|
409
|
+
className: cn(
|
|
410
|
+
"h-9 w-full min-w-0 border border-input bg-transparent px-3 py-1 text-body-medium font-sans shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-label-medium file:text-foreground placeholder:font-normal placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30",
|
|
411
|
+
"focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-primary/20",
|
|
412
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
413
|
+
className
|
|
414
|
+
),
|
|
415
|
+
"data-slot": "input",
|
|
416
|
+
type
|
|
417
|
+
}, props)
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/components/ui/tooltip.tsx
|
|
422
|
+
var import_tooltip = require("@base-ui/react/tooltip");
|
|
423
|
+
|
|
424
|
+
// src/lib/theme-provider.tsx
|
|
425
|
+
var import_react2 = require("react");
|
|
426
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
427
|
+
var ThemeVarsContext = (0, import_react2.createContext)({});
|
|
428
|
+
function useThemeVars() {
|
|
429
|
+
return (0, import_react2.useContext)(ThemeVarsContext);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/components/ui/tooltip.tsx
|
|
433
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
434
|
+
function TooltipProvider(_a) {
|
|
435
|
+
var _b = _a, {
|
|
436
|
+
delay = 0
|
|
437
|
+
} = _b, props = __objRest(_b, [
|
|
438
|
+
"delay"
|
|
439
|
+
]);
|
|
440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
441
|
+
import_tooltip.Tooltip.Provider,
|
|
442
|
+
__spreadValues({
|
|
443
|
+
"data-slot": "tooltip-provider",
|
|
444
|
+
delay
|
|
445
|
+
}, props)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
function Tooltip(_a) {
|
|
449
|
+
var props = __objRest(_a, []);
|
|
450
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Root, __spreadValues({ "data-slot": "tooltip" }, props));
|
|
451
|
+
}
|
|
452
|
+
function TooltipTrigger(_a) {
|
|
453
|
+
var props = __objRest(_a, []);
|
|
454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Trigger, __spreadValues({ "data-slot": "tooltip-trigger" }, props));
|
|
455
|
+
}
|
|
456
|
+
function TooltipContent(_a) {
|
|
457
|
+
var _b = _a, {
|
|
458
|
+
className,
|
|
459
|
+
sideOffset = 8,
|
|
460
|
+
side,
|
|
461
|
+
children,
|
|
462
|
+
style
|
|
463
|
+
} = _b, props = __objRest(_b, [
|
|
464
|
+
"className",
|
|
465
|
+
"sideOffset",
|
|
466
|
+
"side",
|
|
467
|
+
"children",
|
|
468
|
+
"style"
|
|
469
|
+
]);
|
|
470
|
+
const themeVars = useThemeVars();
|
|
471
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Positioner, { sideOffset, side, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
472
|
+
import_tooltip.Tooltip.Popup,
|
|
473
|
+
__spreadProps(__spreadValues({
|
|
474
|
+
className: cn(
|
|
475
|
+
"relative z-50 w-fit animate-in overflow-visible bg-brand-secondary px-3 py-1.5 text-caption text-balance text-brand-secondary-foreground fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards",
|
|
476
|
+
className
|
|
477
|
+
),
|
|
478
|
+
"data-slot": "tooltip-content",
|
|
479
|
+
style: __spreadValues(__spreadValues({}, themeVars), style)
|
|
480
|
+
}, props), {
|
|
481
|
+
children: [
|
|
482
|
+
children,
|
|
483
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_tooltip.Tooltip.Arrow, { className: "z-50 size-2.5 rotate-45 bg-brand-secondary data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1 data-[side=top]:-bottom-1" })
|
|
484
|
+
]
|
|
485
|
+
})
|
|
486
|
+
) }) });
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/components/ui/popover.tsx
|
|
490
|
+
var React4 = __toESM(require("react"));
|
|
491
|
+
var import_popover = require("@base-ui/react/popover");
|
|
492
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
493
|
+
var PopoverPortalContext = React4.createContext(void 0);
|
|
494
|
+
function Popover(_a) {
|
|
495
|
+
var props = __objRest(_a, []);
|
|
496
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Root, __spreadValues({ "data-slot": "popover" }, props));
|
|
497
|
+
}
|
|
498
|
+
function PopoverTrigger(_a) {
|
|
499
|
+
var props = __objRest(_a, []);
|
|
500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Trigger, __spreadValues({ "data-slot": "popover-trigger" }, props));
|
|
501
|
+
}
|
|
502
|
+
function PopoverContent(_a) {
|
|
503
|
+
var _b = _a, {
|
|
504
|
+
className,
|
|
505
|
+
align = "center",
|
|
506
|
+
sideOffset = 4,
|
|
507
|
+
style
|
|
508
|
+
} = _b, props = __objRest(_b, [
|
|
509
|
+
"className",
|
|
510
|
+
"align",
|
|
511
|
+
"sideOffset",
|
|
512
|
+
"style"
|
|
513
|
+
]);
|
|
514
|
+
const themeVars = useThemeVars();
|
|
515
|
+
const portalContainer = React4.useContext(PopoverPortalContext);
|
|
516
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_popover.Popover.Portal, { container: portalContainer != null ? portalContainer : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
517
|
+
import_popover.Popover.Positioner,
|
|
518
|
+
{
|
|
519
|
+
className: "z-[200]",
|
|
520
|
+
align,
|
|
521
|
+
sideOffset,
|
|
522
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
523
|
+
import_popover.Popover.Popup,
|
|
524
|
+
__spreadValues({
|
|
525
|
+
className: cn(
|
|
526
|
+
"z-50 w-72 border border-border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
|
|
527
|
+
className
|
|
528
|
+
),
|
|
529
|
+
"data-slot": "popover-content",
|
|
530
|
+
style: __spreadValues(__spreadValues({}, themeVars), style)
|
|
531
|
+
}, props)
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
) });
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// src/components/ui/progress.tsx
|
|
538
|
+
var import_progress = require("@base-ui/react/progress");
|
|
539
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
540
|
+
function Progress(_a) {
|
|
541
|
+
var _b = _a, {
|
|
542
|
+
className,
|
|
543
|
+
value,
|
|
544
|
+
indicatorClassName
|
|
545
|
+
} = _b, props = __objRest(_b, [
|
|
546
|
+
"className",
|
|
547
|
+
"value",
|
|
548
|
+
"indicatorClassName"
|
|
549
|
+
]);
|
|
550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
551
|
+
import_progress.Progress.Root,
|
|
552
|
+
__spreadProps(__spreadValues({
|
|
553
|
+
className: cn("relative h-2 w-full overflow-hidden bg-muted", className),
|
|
554
|
+
"data-slot": "progress",
|
|
555
|
+
value
|
|
556
|
+
}, props), {
|
|
557
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_progress.Progress.Track, { className: "h-full", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
558
|
+
import_progress.Progress.Indicator,
|
|
559
|
+
{
|
|
560
|
+
className: cn("h-full bg-primary transition-all", indicatorClassName),
|
|
561
|
+
"data-slot": "progress-indicator"
|
|
562
|
+
}
|
|
563
|
+
) })
|
|
564
|
+
})
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/components/ui/tabs.tsx
|
|
569
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
570
|
+
var import_tabs = require("@base-ui/react/tabs");
|
|
571
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
572
|
+
function Tabs(_a) {
|
|
573
|
+
var _b = _a, {
|
|
574
|
+
className,
|
|
575
|
+
orientation = "horizontal"
|
|
576
|
+
} = _b, props = __objRest(_b, [
|
|
577
|
+
"className",
|
|
578
|
+
"orientation"
|
|
579
|
+
]);
|
|
580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
581
|
+
import_tabs.Tabs.Root,
|
|
582
|
+
__spreadValues({
|
|
583
|
+
className: cn(
|
|
584
|
+
"group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
|
|
585
|
+
className
|
|
586
|
+
),
|
|
587
|
+
"data-orientation": orientation,
|
|
588
|
+
"data-slot": "tabs"
|
|
589
|
+
}, props)
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
var tabsListVariants = (0, import_class_variance_authority3.cva)(
|
|
593
|
+
"group/tabs-list inline-flex w-fit items-center justify-center gap-1 rounded-none p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
|
|
594
|
+
{
|
|
595
|
+
variants: {
|
|
596
|
+
variant: {
|
|
597
|
+
default: "bg-muted",
|
|
598
|
+
line: "bg-transparent p-0"
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
defaultVariants: {
|
|
602
|
+
variant: "default"
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
function TabsList(_a) {
|
|
607
|
+
var _b = _a, {
|
|
608
|
+
className,
|
|
609
|
+
variant = "default"
|
|
610
|
+
} = _b, props = __objRest(_b, [
|
|
611
|
+
"className",
|
|
612
|
+
"variant"
|
|
613
|
+
]);
|
|
614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
615
|
+
import_tabs.Tabs.List,
|
|
616
|
+
__spreadValues({
|
|
617
|
+
className: cn(tabsListVariants({ variant }), className),
|
|
618
|
+
"data-slot": "tabs-list",
|
|
619
|
+
"data-variant": variant
|
|
620
|
+
}, props)
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function TabsTrigger(_a) {
|
|
624
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
626
|
+
import_tabs.Tabs.Tab,
|
|
627
|
+
__spreadValues({
|
|
628
|
+
className: cn(
|
|
629
|
+
// Base layout & typography
|
|
630
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap",
|
|
631
|
+
"rounded-none border border-transparent px-1.5 py-1 text-label-medium",
|
|
632
|
+
"text-muted-foreground transition-all",
|
|
633
|
+
// Vertical orientation
|
|
634
|
+
"group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start",
|
|
635
|
+
// Hover & focus
|
|
636
|
+
"hover:text-foreground",
|
|
637
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring",
|
|
638
|
+
// Disabled
|
|
639
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
640
|
+
// Active state — Default variant: primary/10 bg + subtle shadow
|
|
641
|
+
// Base UI uses data-active attribute for the active/selected tab
|
|
642
|
+
"data-active:bg-primary/10 data-active:text-foreground",
|
|
643
|
+
"group-data-[variant=default]/tabs-list:data-active:shadow-sm",
|
|
644
|
+
// Active state — Line variant: suppress bg & shadow
|
|
645
|
+
"group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
|
646
|
+
"group-data-[variant=line]/tabs-list:data-active:shadow-none",
|
|
647
|
+
// Indicator pseudo-element (visible only for Line variant, active state)
|
|
648
|
+
"after:absolute after:bg-primary after:opacity-0 after:transition-opacity",
|
|
649
|
+
"group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5",
|
|
650
|
+
"group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5",
|
|
651
|
+
"group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
|
652
|
+
// SVG icons
|
|
653
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
654
|
+
className
|
|
655
|
+
),
|
|
656
|
+
"data-slot": "tabs-trigger"
|
|
657
|
+
}, props)
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// src/components/ui/policy-ai/policy-ai-responses.tsx
|
|
662
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
663
|
+
function BankAvatar({ name }) {
|
|
664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
665
|
+
"span",
|
|
666
|
+
{
|
|
667
|
+
"aria-hidden": "true",
|
|
668
|
+
className: "shrink-0 inline-flex items-center justify-center size-7 bg-muted text-muted-foreground text-xs font-semibold border border-border",
|
|
669
|
+
children: name.charAt(0).toUpperCase()
|
|
670
|
+
}
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
function QueryContextInfo({ label }) {
|
|
674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Tooltip, { children: [
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
676
|
+
"span",
|
|
677
|
+
{
|
|
678
|
+
className: "shrink-0 text-muted-foreground/60 hover:text-muted-foreground cursor-default transition-colors",
|
|
679
|
+
"aria-label": label,
|
|
680
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react3.Info, { className: "size-3.5", "aria-hidden": "true" })
|
|
681
|
+
}
|
|
682
|
+
) }),
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipContent, { side: "top", children: label })
|
|
684
|
+
] }) });
|
|
685
|
+
}
|
|
686
|
+
function queryContextLabel(context) {
|
|
687
|
+
return [
|
|
688
|
+
context.policyType,
|
|
689
|
+
...context.categories,
|
|
690
|
+
context.queryType.replace(/_/g, " ")
|
|
691
|
+
].join(" \xB7 ");
|
|
692
|
+
}
|
|
693
|
+
function CitationBadge({ citation }) {
|
|
694
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { children: [
|
|
695
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", "aria-label": `View source ${citation.index}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
696
|
+
Badge,
|
|
697
|
+
{
|
|
698
|
+
variant: "secondary",
|
|
699
|
+
className: "cursor-pointer px-1.5 py-0 text-xs mx-0.5 align-baseline hover:bg-secondary/80 transition-colors",
|
|
700
|
+
children: citation.index
|
|
701
|
+
}
|
|
702
|
+
) }) }),
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverContent, { className: "w-72 p-3", sideOffset: 6, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
|
|
705
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs font-semibold text-foreground", children: citation.bankName }),
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: citation.category })
|
|
707
|
+
] }),
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-xs text-muted-foreground leading-relaxed", children: citation.excerpt })
|
|
709
|
+
] }) })
|
|
710
|
+
] });
|
|
711
|
+
}
|
|
712
|
+
function AnswerWithCitations({
|
|
713
|
+
answer,
|
|
714
|
+
citations
|
|
715
|
+
}) {
|
|
716
|
+
const citationMap = new Map(citations.map((c) => [c.index, c]));
|
|
717
|
+
const parts = answer.split(/(\[\d+\])/g);
|
|
718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-foreground leading-relaxed whitespace-pre-line", children: parts.map((part, i) => {
|
|
719
|
+
const match = part.match(/^\[(\d+)\]$/);
|
|
720
|
+
if (match) {
|
|
721
|
+
const citation = citationMap.get(parseInt(match[1], 10));
|
|
722
|
+
if (citation) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CitationBadge, { citation }, i);
|
|
723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground", children: part }, i);
|
|
724
|
+
}
|
|
725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React5.Fragment, { children: part }, i);
|
|
726
|
+
}) });
|
|
727
|
+
}
|
|
728
|
+
function PolicySingleBankAnswer({
|
|
729
|
+
bankName,
|
|
730
|
+
verdict,
|
|
731
|
+
answer,
|
|
732
|
+
citations,
|
|
733
|
+
queryContext,
|
|
734
|
+
className
|
|
735
|
+
}) {
|
|
736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
737
|
+
"div",
|
|
738
|
+
{
|
|
739
|
+
"data-slot": "policy-single-bank-answer",
|
|
740
|
+
className: cn("border border-border bg-card flex flex-col", className),
|
|
741
|
+
children: [
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border", children: [
|
|
743
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BankAvatar, { name: bankName }),
|
|
744
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 flex items-center gap-1.5 min-w-0", children: [
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-sm text-foreground truncate", children: bankName }),
|
|
746
|
+
queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
|
|
747
|
+
] }),
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict })
|
|
749
|
+
] }),
|
|
750
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AnswerWithCitations, { answer, citations }) })
|
|
751
|
+
]
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
function PolicyComparisonTable({
|
|
756
|
+
categories,
|
|
757
|
+
banks,
|
|
758
|
+
summaryCounts,
|
|
759
|
+
citations,
|
|
760
|
+
queryContext,
|
|
761
|
+
className
|
|
762
|
+
}) {
|
|
763
|
+
const [search, setSearch] = React5.useState("");
|
|
764
|
+
const [filter, setFilter] = React5.useState("all");
|
|
765
|
+
const filtered = React5.useMemo(() => {
|
|
766
|
+
let result = banks;
|
|
767
|
+
if (search.trim()) {
|
|
768
|
+
const q = search.toLowerCase();
|
|
769
|
+
result = result.filter((b) => b.bankName.toLowerCase().includes(q));
|
|
770
|
+
}
|
|
771
|
+
if (filter !== "all") {
|
|
772
|
+
result = result.filter((b) => b.verdict === filter);
|
|
773
|
+
}
|
|
774
|
+
return result;
|
|
775
|
+
}, [banks, search, filter]);
|
|
776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
777
|
+
"div",
|
|
778
|
+
{
|
|
779
|
+
"data-slot": "policy-comparison-table",
|
|
780
|
+
className: cn("border border-border bg-card flex flex-col", className),
|
|
781
|
+
children: [
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-2.5 border-b border-border bg-muted/30", children: [
|
|
783
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
784
|
+
import_lucide_react3.Building2,
|
|
785
|
+
{
|
|
786
|
+
className: "size-3.5 text-muted-foreground shrink-0",
|
|
787
|
+
"aria-hidden": "true"
|
|
788
|
+
}
|
|
789
|
+
),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-sm flex-wrap flex-1 min-w-0", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-foreground", children: [
|
|
792
|
+
summaryCounts.total,
|
|
793
|
+
" banks"
|
|
794
|
+
] }),
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-muted-foreground", children: "\xB7" }),
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "success", className: "text-xs px-1.5 py-0", children: [
|
|
797
|
+
summaryCounts.yes,
|
|
798
|
+
" Yes"
|
|
799
|
+
] }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "warning", className: "text-xs px-1.5 py-0", children: [
|
|
801
|
+
summaryCounts.softNo,
|
|
802
|
+
" Soft No"
|
|
803
|
+
] }),
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Badge, { variant: "destructive", className: "text-xs px-1.5 py-0", children: [
|
|
805
|
+
summaryCounts.no,
|
|
806
|
+
" No"
|
|
807
|
+
] })
|
|
808
|
+
] }),
|
|
809
|
+
queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
|
|
810
|
+
] }),
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 py-2.5 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
812
|
+
Input,
|
|
813
|
+
{
|
|
814
|
+
"aria-label": "Search banks",
|
|
815
|
+
placeholder: "Search banks\u2026",
|
|
816
|
+
value: search,
|
|
817
|
+
onChange: (e) => setSearch(e.target.value),
|
|
818
|
+
className: "h-8 text-sm"
|
|
819
|
+
}
|
|
820
|
+
) }),
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-b border-border px-4 pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
822
|
+
Tabs,
|
|
823
|
+
{
|
|
824
|
+
value: filter,
|
|
825
|
+
onValueChange: (v) => setFilter(v),
|
|
826
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(TabsList, { variant: "line", className: "justify-start h-8 gap-0 -mb-px", children: [
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "all", className: "text-sm px-3 h-7", children: "All" }),
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "yes", className: "text-sm px-3 h-7", children: "Yes" }),
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "soft_no", className: "text-sm px-3 h-7", children: "Soft No" }),
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TabsTrigger, { value: "no", className: "text-sm px-3 h-7", children: "No" })
|
|
831
|
+
] })
|
|
832
|
+
}
|
|
833
|
+
) }),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { className: "w-full text-sm border-collapse", children: [
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b border-border bg-muted/20", children: [
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { className: "text-left text-sm font-medium text-muted-foreground px-4 py-2", children: "Bank" }),
|
|
837
|
+
categories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
838
|
+
"th",
|
|
839
|
+
{
|
|
840
|
+
className: "text-left text-sm font-medium text-muted-foreground px-3 py-2 w-px whitespace-nowrap",
|
|
841
|
+
children: cat
|
|
842
|
+
},
|
|
843
|
+
cat
|
|
844
|
+
))
|
|
845
|
+
] }) }),
|
|
846
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
847
|
+
"td",
|
|
848
|
+
{
|
|
849
|
+
colSpan: categories.length + 1,
|
|
850
|
+
className: "px-4 py-6 text-center text-sm text-muted-foreground",
|
|
851
|
+
children: "No banks match your search."
|
|
852
|
+
}
|
|
853
|
+
) }) : filtered.map((bank) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { className: "border-b border-border", children: [
|
|
854
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
855
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BankAvatar, { name: bank.bankName }),
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
|
|
857
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium text-foreground leading-snug", children: bank.bankName }),
|
|
858
|
+
bank.details && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-muted-foreground leading-snug", children: bank.details })
|
|
859
|
+
] })
|
|
860
|
+
] }) }),
|
|
861
|
+
categories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
862
|
+
"td",
|
|
863
|
+
{
|
|
864
|
+
className: "px-3 py-2.5 align-top w-px whitespace-nowrap",
|
|
865
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict: bank.verdict })
|
|
866
|
+
},
|
|
867
|
+
cat
|
|
868
|
+
))
|
|
869
|
+
] }, bank.bankName)) })
|
|
870
|
+
] }) })
|
|
871
|
+
]
|
|
872
|
+
}
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
var VERDICT_SCORE_COLORS = {
|
|
876
|
+
yes: { track: "bg-success/20", indicator: "bg-success" },
|
|
877
|
+
soft_no: { track: "bg-warning/20", indicator: "bg-warning" },
|
|
878
|
+
no: { track: "bg-destructive/20", indicator: "bg-destructive" },
|
|
879
|
+
unknown: { track: "bg-muted", indicator: "bg-muted-foreground" }
|
|
880
|
+
};
|
|
881
|
+
function PolicyRankedList({
|
|
882
|
+
categories,
|
|
883
|
+
banks,
|
|
884
|
+
citations,
|
|
885
|
+
queryContext,
|
|
886
|
+
className
|
|
887
|
+
}) {
|
|
888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
889
|
+
"div",
|
|
890
|
+
{
|
|
891
|
+
"data-slot": "policy-ranked-list",
|
|
892
|
+
className: cn("border border-border bg-card flex flex-col", className),
|
|
893
|
+
children: [
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 px-4 py-2.5 border-b border-border bg-muted/30", children: [
|
|
895
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-muted-foreground shrink-0", children: "Ranked:" }),
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center gap-1 flex-wrap flex-1 min-w-0", children: categories.map((cat, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(React5.Fragment, { children: [
|
|
897
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-muted-foreground", children: "+" }),
|
|
898
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Badge, { variant: "secondary", className: "text-xs px-1.5 py-0", children: cat })
|
|
899
|
+
] }, cat)) }),
|
|
900
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-muted-foreground shrink-0", children: [
|
|
901
|
+
banks.length,
|
|
902
|
+
" banks"
|
|
903
|
+
] }),
|
|
904
|
+
queryContext && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(QueryContextInfo, { label: queryContextLabel(queryContext) })
|
|
905
|
+
] }),
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "divide-y divide-border", children: banks.map((bank) => {
|
|
907
|
+
var _a, _b;
|
|
908
|
+
const scorePercent = Math.round(bank.score * 100);
|
|
909
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col", children: [
|
|
910
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3", children: [
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "shrink-0 w-6 text-center text-sm font-bold text-muted-foreground", children: [
|
|
912
|
+
"#",
|
|
913
|
+
bank.rank
|
|
914
|
+
] }),
|
|
915
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col gap-1.5", children: [
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
917
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm font-medium text-foreground truncate", children: bank.bankName }),
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
919
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-muted-foreground font-mono", children: [
|
|
920
|
+
scorePercent,
|
|
921
|
+
"%"
|
|
922
|
+
] }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PolicyVerdictBadge, { verdict: bank.verdict })
|
|
924
|
+
] })
|
|
925
|
+
] }),
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
927
|
+
Progress,
|
|
928
|
+
{
|
|
929
|
+
value: scorePercent,
|
|
930
|
+
className: cn(
|
|
931
|
+
"h-1.5",
|
|
932
|
+
((_a = VERDICT_SCORE_COLORS[bank.verdict]) != null ? _a : VERDICT_SCORE_COLORS.unknown).track
|
|
933
|
+
),
|
|
934
|
+
indicatorClassName: ((_b = VERDICT_SCORE_COLORS[bank.verdict]) != null ? _b : VERDICT_SCORE_COLORS.unknown).indicator,
|
|
935
|
+
"aria-label": `${bank.bankName} policy score: ${scorePercent}%`
|
|
936
|
+
}
|
|
937
|
+
)
|
|
938
|
+
] })
|
|
939
|
+
] }),
|
|
940
|
+
bank.highlights.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "px-4 pb-3 pl-[52px]", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "flex flex-col gap-0.5", children: bank.highlights.map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
941
|
+
"li",
|
|
942
|
+
{
|
|
943
|
+
className: "text-sm text-muted-foreground leading-relaxed list-disc list-inside",
|
|
944
|
+
children: h
|
|
945
|
+
},
|
|
946
|
+
i
|
|
947
|
+
)) }) })
|
|
948
|
+
] }, bank.bankName);
|
|
949
|
+
}) })
|
|
950
|
+
]
|
|
951
|
+
}
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// src/components/ui/policy-ai/policy-ai-panel.tsx
|
|
956
|
+
var React7 = __toESM(require("react"));
|
|
957
|
+
var import_lucide_react6 = require("lucide-react");
|
|
958
|
+
|
|
959
|
+
// src/components/ui/chat-input-area.tsx
|
|
960
|
+
var React6 = __toESM(require("react"));
|
|
961
|
+
var import_lucide_react4 = require("lucide-react");
|
|
962
|
+
|
|
963
|
+
// src/components/ui/textarea.tsx
|
|
964
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
965
|
+
function Textarea(_a) {
|
|
966
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
968
|
+
"textarea",
|
|
969
|
+
__spreadValues({
|
|
970
|
+
className: cn(
|
|
971
|
+
// WealthX: removed shadow-xs (flat panels), added font-sans
|
|
972
|
+
"flex field-sizing-content min-h-16 w-full border border-input bg-transparent px-3 py-2 text-body-medium font-sans transition-[color,box-shadow] outline-none placeholder:font-normal placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-primary/20 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40",
|
|
973
|
+
className
|
|
974
|
+
),
|
|
975
|
+
"data-slot": "textarea"
|
|
976
|
+
}, props)
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// src/components/ui/chat-input-area.tsx
|
|
981
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
982
|
+
var DEFAULT_HINT = "Enter to send \xB7 Shift+Enter for new line";
|
|
983
|
+
function ChatInputArea({
|
|
984
|
+
value,
|
|
985
|
+
onChange,
|
|
986
|
+
onSend,
|
|
987
|
+
onAttachFile,
|
|
988
|
+
onAttachImage,
|
|
989
|
+
disabled = false,
|
|
990
|
+
placeholder = "Type your message\u2026",
|
|
991
|
+
hint = DEFAULT_HINT,
|
|
992
|
+
maxHeight = 160,
|
|
993
|
+
autoFocus = false,
|
|
994
|
+
className
|
|
995
|
+
}) {
|
|
996
|
+
const textareaRef = React6.useRef(null);
|
|
997
|
+
const fileInputRef = React6.useRef(null);
|
|
998
|
+
const imageInputRef = React6.useRef(null);
|
|
999
|
+
React6.useEffect(() => {
|
|
1000
|
+
if (autoFocus) {
|
|
1001
|
+
setTimeout(() => {
|
|
1002
|
+
var _a;
|
|
1003
|
+
return (_a = textareaRef.current) == null ? void 0 : _a.focus();
|
|
1004
|
+
}, 50);
|
|
1005
|
+
}
|
|
1006
|
+
}, [autoFocus]);
|
|
1007
|
+
const handleSend = React6.useCallback(() => {
|
|
1008
|
+
const text = value.trim();
|
|
1009
|
+
if (!text || disabled) return;
|
|
1010
|
+
onSend(text);
|
|
1011
|
+
if (textareaRef.current) {
|
|
1012
|
+
textareaRef.current.style.height = "auto";
|
|
1013
|
+
}
|
|
1014
|
+
}, [value, disabled, onSend]);
|
|
1015
|
+
const handleKeyDown = React6.useCallback(
|
|
1016
|
+
(e) => {
|
|
1017
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1018
|
+
e.preventDefault();
|
|
1019
|
+
handleSend();
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
[handleSend]
|
|
1023
|
+
);
|
|
1024
|
+
const handleTextareaChange = React6.useCallback(
|
|
1025
|
+
(e) => {
|
|
1026
|
+
onChange(e.target.value);
|
|
1027
|
+
const el = e.target;
|
|
1028
|
+
el.style.height = "auto";
|
|
1029
|
+
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
1030
|
+
},
|
|
1031
|
+
[onChange, maxHeight]
|
|
1032
|
+
);
|
|
1033
|
+
const handleFileChange = React6.useCallback(
|
|
1034
|
+
(e) => {
|
|
1035
|
+
var _a;
|
|
1036
|
+
if ((_a = e.target.files) == null ? void 0 : _a.length) {
|
|
1037
|
+
onAttachFile == null ? void 0 : onAttachFile(e.target.files);
|
|
1038
|
+
e.target.value = "";
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
[onAttachFile]
|
|
1042
|
+
);
|
|
1043
|
+
const handleImageChange = React6.useCallback(
|
|
1044
|
+
(e) => {
|
|
1045
|
+
var _a;
|
|
1046
|
+
if ((_a = e.target.files) == null ? void 0 : _a.length) {
|
|
1047
|
+
onAttachImage == null ? void 0 : onAttachImage(e.target.files);
|
|
1048
|
+
e.target.value = "";
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
[onAttachImage]
|
|
1052
|
+
);
|
|
1053
|
+
const showFileButton = typeof onAttachFile === "function";
|
|
1054
|
+
const showImageButton = typeof onAttachImage === "function";
|
|
1055
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1056
|
+
"div",
|
|
1057
|
+
{
|
|
1058
|
+
"data-slot": "chat-input-area",
|
|
1059
|
+
className: cn("flex flex-col gap-1.5", className),
|
|
1060
|
+
children: [
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "border border-border bg-background flex flex-col focus-within:ring-1 focus-within:ring-ring", children: [
|
|
1062
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1063
|
+
Textarea,
|
|
1064
|
+
{
|
|
1065
|
+
ref: textareaRef,
|
|
1066
|
+
value,
|
|
1067
|
+
onChange: handleTextareaChange,
|
|
1068
|
+
onKeyDown: handleKeyDown,
|
|
1069
|
+
placeholder,
|
|
1070
|
+
disabled,
|
|
1071
|
+
rows: 3,
|
|
1072
|
+
className: "resize-none text-sm border-0 shadow-none focus-visible:ring-0 px-3 pt-3 pb-1 min-h-[72px]",
|
|
1073
|
+
"aria-label": placeholder
|
|
1074
|
+
}
|
|
1075
|
+
),
|
|
1076
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between px-2 pb-2", children: [
|
|
1077
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
1078
|
+
showFileButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1080
|
+
Button,
|
|
1081
|
+
{
|
|
1082
|
+
variant: "ghost",
|
|
1083
|
+
size: "icon-sm",
|
|
1084
|
+
type: "button",
|
|
1085
|
+
title: "Attach file",
|
|
1086
|
+
"aria-label": "Attach file",
|
|
1087
|
+
disabled,
|
|
1088
|
+
onClick: () => {
|
|
1089
|
+
var _a;
|
|
1090
|
+
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
1091
|
+
},
|
|
1092
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Paperclip, { className: "size-3.5", "aria-hidden": "true" })
|
|
1093
|
+
}
|
|
1094
|
+
),
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1096
|
+
"input",
|
|
1097
|
+
{
|
|
1098
|
+
ref: fileInputRef,
|
|
1099
|
+
type: "file",
|
|
1100
|
+
multiple: true,
|
|
1101
|
+
className: "sr-only",
|
|
1102
|
+
tabIndex: -1,
|
|
1103
|
+
onChange: handleFileChange
|
|
1104
|
+
}
|
|
1105
|
+
)
|
|
1106
|
+
] }),
|
|
1107
|
+
showImageButton && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1109
|
+
Button,
|
|
1110
|
+
{
|
|
1111
|
+
variant: "ghost",
|
|
1112
|
+
size: "icon-sm",
|
|
1113
|
+
type: "button",
|
|
1114
|
+
title: "Upload image",
|
|
1115
|
+
"aria-label": "Upload image",
|
|
1116
|
+
disabled,
|
|
1117
|
+
onClick: () => {
|
|
1118
|
+
var _a;
|
|
1119
|
+
return (_a = imageInputRef.current) == null ? void 0 : _a.click();
|
|
1120
|
+
},
|
|
1121
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.ImagePlus, { className: "size-3.5", "aria-hidden": "true" })
|
|
1122
|
+
}
|
|
1123
|
+
),
|
|
1124
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1125
|
+
"input",
|
|
1126
|
+
{
|
|
1127
|
+
ref: imageInputRef,
|
|
1128
|
+
type: "file",
|
|
1129
|
+
multiple: true,
|
|
1130
|
+
accept: "image/*",
|
|
1131
|
+
className: "sr-only",
|
|
1132
|
+
tabIndex: -1,
|
|
1133
|
+
onChange: handleImageChange
|
|
1134
|
+
}
|
|
1135
|
+
)
|
|
1136
|
+
] })
|
|
1137
|
+
] }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1139
|
+
Button,
|
|
1140
|
+
{
|
|
1141
|
+
size: "icon-sm",
|
|
1142
|
+
type: "button",
|
|
1143
|
+
"aria-label": "Send message",
|
|
1144
|
+
disabled: !value.trim() || disabled,
|
|
1145
|
+
onClick: handleSend,
|
|
1146
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Send, { className: "size-3.5", "aria-hidden": "true" })
|
|
1147
|
+
}
|
|
1148
|
+
)
|
|
1149
|
+
] })
|
|
1150
|
+
] }),
|
|
1151
|
+
hint !== false && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: hint })
|
|
1152
|
+
]
|
|
1153
|
+
}
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// src/components/ui/chat-widget-primitives.tsx
|
|
1158
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1159
|
+
|
|
1160
|
+
// src/components/ui/avatar.tsx
|
|
1161
|
+
var import_avatar = require("@base-ui/react/avatar");
|
|
1162
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1163
|
+
function Avatar(_a) {
|
|
1164
|
+
var _b = _a, {
|
|
1165
|
+
className,
|
|
1166
|
+
size = "default"
|
|
1167
|
+
} = _b, props = __objRest(_b, [
|
|
1168
|
+
"className",
|
|
1169
|
+
"size"
|
|
1170
|
+
]);
|
|
1171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1172
|
+
import_avatar.Avatar.Root,
|
|
1173
|
+
__spreadValues({
|
|
1174
|
+
className: cn(
|
|
1175
|
+
"group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
|
|
1176
|
+
className
|
|
1177
|
+
),
|
|
1178
|
+
"data-size": size,
|
|
1179
|
+
"data-slot": "avatar"
|
|
1180
|
+
}, props)
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
function AvatarFallback(_a) {
|
|
1184
|
+
var _b = _a, {
|
|
1185
|
+
className
|
|
1186
|
+
} = _b, props = __objRest(_b, [
|
|
1187
|
+
"className"
|
|
1188
|
+
]);
|
|
1189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1190
|
+
import_avatar.Avatar.Fallback,
|
|
1191
|
+
__spreadValues({
|
|
1192
|
+
className: cn(
|
|
1193
|
+
"flex size-full items-center justify-center rounded-full overflow-hidden bg-muted text-body-small font-sans text-muted-foreground group-data-[size=sm]/avatar:text-caption",
|
|
1194
|
+
className
|
|
1195
|
+
),
|
|
1196
|
+
"data-slot": "avatar-fallback"
|
|
1197
|
+
}, props)
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// src/components/ui/chat-widget-primitives.tsx
|
|
1202
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1203
|
+
function ChatWidgetMessage({
|
|
1204
|
+
role,
|
|
1205
|
+
content,
|
|
1206
|
+
timestamp,
|
|
1207
|
+
isStreaming,
|
|
1208
|
+
className
|
|
1209
|
+
}) {
|
|
1210
|
+
if (role === "system") {
|
|
1211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("flex items-center justify-center py-2", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-body-small text-muted-foreground", children: content }) });
|
|
1212
|
+
}
|
|
1213
|
+
const isLeft = role === "bot" || role === "advisor";
|
|
1214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1215
|
+
"div",
|
|
1216
|
+
{
|
|
1217
|
+
className: cn(
|
|
1218
|
+
"flex gap-2",
|
|
1219
|
+
isLeft ? "items-start" : "flex-row-reverse items-start",
|
|
1220
|
+
className
|
|
1221
|
+
),
|
|
1222
|
+
children: [
|
|
1223
|
+
isLeft && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Avatar, { className: "size-7", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1224
|
+
AvatarFallback,
|
|
1225
|
+
{
|
|
1226
|
+
className: role === "advisor" ? "bg-primary/15 text-foreground" : void 0,
|
|
1227
|
+
children: role === "advisor" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.UserRound, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.Bot, { className: "size-3.5" })
|
|
1228
|
+
}
|
|
1229
|
+
) }),
|
|
1230
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1231
|
+
"div",
|
|
1232
|
+
{
|
|
1233
|
+
className: cn(
|
|
1234
|
+
"flex max-w-[80%] flex-col gap-1",
|
|
1235
|
+
!isLeft && "items-end"
|
|
1236
|
+
),
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1239
|
+
"div",
|
|
1240
|
+
{
|
|
1241
|
+
className: cn(
|
|
1242
|
+
"px-3 py-2 text-body-medium",
|
|
1243
|
+
isLeft ? "border border-border bg-card text-card-foreground shadow-sm" : "text-primary-foreground"
|
|
1244
|
+
),
|
|
1245
|
+
style: !isLeft ? { backgroundColor: "var(--primary)" } : void 0,
|
|
1246
|
+
children: isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatWidgetTypingIndicator, {}) : content
|
|
1247
|
+
}
|
|
1248
|
+
),
|
|
1249
|
+
timestamp && !isStreaming && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-[10px] text-muted-foreground", children: timestamp })
|
|
1250
|
+
]
|
|
1251
|
+
}
|
|
1252
|
+
)
|
|
1253
|
+
]
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
function ChatWidgetTypingIndicator({
|
|
1258
|
+
className
|
|
1259
|
+
}) {
|
|
1260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1261
|
+
"div",
|
|
1262
|
+
{
|
|
1263
|
+
role: "status",
|
|
1264
|
+
"aria-label": "Typing",
|
|
1265
|
+
className: cn("flex items-center gap-1 py-0.5", className),
|
|
1266
|
+
children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1267
|
+
"span",
|
|
1268
|
+
{
|
|
1269
|
+
className: "size-1.5 animate-bounce rounded-full bg-muted-foreground/60",
|
|
1270
|
+
style: { animationDelay: `${i * 0.15}s` },
|
|
1271
|
+
"aria-hidden": "true"
|
|
1272
|
+
},
|
|
1273
|
+
i
|
|
1274
|
+
))
|
|
1275
|
+
}
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// src/components/ui/policy-ai/policy-ai-panel.tsx
|
|
1280
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1281
|
+
var DEFAULT_SUGGESTED = {
|
|
1282
|
+
Income: [
|
|
1283
|
+
"Which banks accept casual income?",
|
|
1284
|
+
"Which lenders accept bonus income, ranked best to worst?",
|
|
1285
|
+
"How is self-employed income assessed across lenders?"
|
|
1286
|
+
],
|
|
1287
|
+
Security: [
|
|
1288
|
+
"Which banks accept apartments under 40sqm?",
|
|
1289
|
+
"What is the maximum LVR for a serviced apartment?",
|
|
1290
|
+
"Do any lenders accept hobby farm properties?"
|
|
1291
|
+
],
|
|
1292
|
+
Serviceability: [
|
|
1293
|
+
"Which banks have the most flexible DTI ratio?",
|
|
1294
|
+
"How is HECS debt treated by different lenders?",
|
|
1295
|
+
"Which lenders apply the lowest assessment buffer rate?"
|
|
1296
|
+
],
|
|
1297
|
+
"Loan Type": [
|
|
1298
|
+
"Which lenders offer cashback on refinances?",
|
|
1299
|
+
"Which banks accept low-doc construction loans?",
|
|
1300
|
+
"What are the pre-approval policies across lenders?"
|
|
1301
|
+
],
|
|
1302
|
+
Borrower: [
|
|
1303
|
+
"Which banks accept non-resident borrowers?",
|
|
1304
|
+
"Which lenders offer LMI waiver for medical professionals?",
|
|
1305
|
+
"How do lenders treat prior credit impairment?"
|
|
1306
|
+
]
|
|
1307
|
+
};
|
|
1308
|
+
var DEFAULT_THINKING_STEPS = [
|
|
1309
|
+
"Classifying query type\u2026",
|
|
1310
|
+
"Searching across 40+ banks\u2026",
|
|
1311
|
+
"Retrieving policy documents\u2026",
|
|
1312
|
+
"Generating response\u2026"
|
|
1313
|
+
];
|
|
1314
|
+
function PolicyAIThinkingSteps({ steps }) {
|
|
1315
|
+
const [currentStep, setCurrentStep] = React7.useState(0);
|
|
1316
|
+
React7.useEffect(() => {
|
|
1317
|
+
setCurrentStep(0);
|
|
1318
|
+
}, [steps]);
|
|
1319
|
+
React7.useEffect(() => {
|
|
1320
|
+
if (currentStep >= steps.length - 1) return;
|
|
1321
|
+
const timer = setTimeout(() => setCurrentStep((s) => s + 1), 1400);
|
|
1322
|
+
return () => clearTimeout(timer);
|
|
1323
|
+
}, [currentStep, steps.length]);
|
|
1324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col gap-2.5 px-4 py-3", children: steps.map((step, i) => {
|
|
1325
|
+
const isDone = i < currentStep;
|
|
1326
|
+
const isCurrent = i === currentStep;
|
|
1327
|
+
const isPending = i > currentStep;
|
|
1328
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1329
|
+
"div",
|
|
1330
|
+
{
|
|
1331
|
+
className: cn(
|
|
1332
|
+
"flex items-center gap-2.5 transition-opacity duration-300",
|
|
1333
|
+
isPending && "opacity-30"
|
|
1334
|
+
),
|
|
1335
|
+
children: [
|
|
1336
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "shrink-0 size-4 flex items-center justify-center", children: isDone ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Check, { className: "size-3.5 text-primary", "aria-hidden": "true" }) : isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1337
|
+
"span",
|
|
1338
|
+
{
|
|
1339
|
+
className: "flex items-center gap-0.5",
|
|
1340
|
+
"aria-label": "In progress",
|
|
1341
|
+
children: [0, 1, 2].map((j) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1342
|
+
"span",
|
|
1343
|
+
{
|
|
1344
|
+
className: "size-1 bg-muted-foreground/70 animate-bounce",
|
|
1345
|
+
style: { animationDelay: `${j * 150}ms` }
|
|
1346
|
+
},
|
|
1347
|
+
j
|
|
1348
|
+
))
|
|
1349
|
+
}
|
|
1350
|
+
) : null }),
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1352
|
+
"span",
|
|
1353
|
+
{
|
|
1354
|
+
className: cn(
|
|
1355
|
+
"text-sm leading-snug transition-colors duration-200",
|
|
1356
|
+
isDone && "text-muted-foreground",
|
|
1357
|
+
isCurrent && "text-foreground font-medium",
|
|
1358
|
+
isPending && "text-muted-foreground"
|
|
1359
|
+
),
|
|
1360
|
+
children: step
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
]
|
|
1364
|
+
},
|
|
1365
|
+
step
|
|
1366
|
+
);
|
|
1367
|
+
}) });
|
|
1368
|
+
}
|
|
1369
|
+
function ResponseCard({
|
|
1370
|
+
content,
|
|
1371
|
+
queryContext
|
|
1372
|
+
}) {
|
|
1373
|
+
if (content.type === "single_bank") {
|
|
1374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1375
|
+
PolicySingleBankAnswer,
|
|
1376
|
+
{
|
|
1377
|
+
bankName: content.bankName,
|
|
1378
|
+
verdict: content.verdict,
|
|
1379
|
+
answer: content.answer,
|
|
1380
|
+
citations: content.citations,
|
|
1381
|
+
queryContext
|
|
1382
|
+
}
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
if (content.type === "cross_bank_comparison") {
|
|
1386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1387
|
+
PolicyComparisonTable,
|
|
1388
|
+
{
|
|
1389
|
+
categories: content.categories,
|
|
1390
|
+
banks: content.banks,
|
|
1391
|
+
summaryCounts: content.summaryCounts,
|
|
1392
|
+
citations: content.citations,
|
|
1393
|
+
queryContext
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
if (content.type === "ranked_list") {
|
|
1398
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1399
|
+
PolicyRankedList,
|
|
1400
|
+
{
|
|
1401
|
+
categories: content.categories,
|
|
1402
|
+
banks: content.banks,
|
|
1403
|
+
citations: content.citations,
|
|
1404
|
+
queryContext
|
|
1405
|
+
}
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
return null;
|
|
1409
|
+
}
|
|
1410
|
+
function PolicyAIFAB({
|
|
1411
|
+
onClick,
|
|
1412
|
+
hasNudge,
|
|
1413
|
+
className
|
|
1414
|
+
}) {
|
|
1415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("relative inline-flex shrink-0", className), children: [
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1417
|
+
Button,
|
|
1418
|
+
{
|
|
1419
|
+
"data-slot": "policy-ai-fab",
|
|
1420
|
+
size: "icon",
|
|
1421
|
+
onClick,
|
|
1422
|
+
className: "size-12 shadow-lg rounded-full",
|
|
1423
|
+
"aria-label": "Open Policy AI",
|
|
1424
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.BrainCircuit, { className: "size-5", "aria-hidden": "true" })
|
|
1425
|
+
}
|
|
1426
|
+
),
|
|
1427
|
+
hasNudge && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "absolute -top-1 -right-1 size-3 bg-destructive rounded-full border-2 border-background" })
|
|
1428
|
+
] });
|
|
1429
|
+
}
|
|
1430
|
+
function PolicyAIPanel({
|
|
1431
|
+
open,
|
|
1432
|
+
onClose,
|
|
1433
|
+
messages = [],
|
|
1434
|
+
suggestedQuestions,
|
|
1435
|
+
isStreaming = false,
|
|
1436
|
+
isLoading = false,
|
|
1437
|
+
thinkingSteps,
|
|
1438
|
+
onSendMessage,
|
|
1439
|
+
onAttachFile,
|
|
1440
|
+
onAttachImage,
|
|
1441
|
+
onReset,
|
|
1442
|
+
position = "bottom-right",
|
|
1443
|
+
inline = false,
|
|
1444
|
+
className
|
|
1445
|
+
}) {
|
|
1446
|
+
var _a;
|
|
1447
|
+
const resolvedThinkingSteps = thinkingSteps != null ? thinkingSteps : DEFAULT_THINKING_STEPS;
|
|
1448
|
+
const [inputValue, setInputValue] = React7.useState("");
|
|
1449
|
+
const [minimised, setMinimised] = React7.useState(false);
|
|
1450
|
+
const [activeTab, setActiveTab] = React7.useState("Income");
|
|
1451
|
+
const messagesEndRef = React7.useRef(null);
|
|
1452
|
+
const isChatMode = messages.length > 0;
|
|
1453
|
+
React7.useEffect(() => {
|
|
1454
|
+
var _a2;
|
|
1455
|
+
if (open && !minimised) {
|
|
1456
|
+
(_a2 = messagesEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
|
|
1457
|
+
}
|
|
1458
|
+
}, [messages, open, minimised]);
|
|
1459
|
+
const handleSend = React7.useCallback(
|
|
1460
|
+
(text) => {
|
|
1461
|
+
if (!text || isStreaming) return;
|
|
1462
|
+
onSendMessage == null ? void 0 : onSendMessage(text);
|
|
1463
|
+
setInputValue("");
|
|
1464
|
+
},
|
|
1465
|
+
[isStreaming, onSendMessage]
|
|
1466
|
+
);
|
|
1467
|
+
if (!open) return null;
|
|
1468
|
+
const positionClass = position === "bottom-left" ? "left-6" : "right-6";
|
|
1469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1470
|
+
"div",
|
|
1471
|
+
{
|
|
1472
|
+
"data-slot": "policy-ai-panel",
|
|
1473
|
+
className: cn(
|
|
1474
|
+
"flex flex-col bg-card",
|
|
1475
|
+
inline ? "h-full border-0" : [
|
|
1476
|
+
"fixed z-50 border border-border shadow-2xl",
|
|
1477
|
+
"bottom-20 w-[400px]",
|
|
1478
|
+
"animate-in slide-in-from-bottom-4 fade-in duration-200",
|
|
1479
|
+
positionClass,
|
|
1480
|
+
minimised && "shadow-lg"
|
|
1481
|
+
],
|
|
1482
|
+
className
|
|
1483
|
+
),
|
|
1484
|
+
style: inline ? void 0 : {
|
|
1485
|
+
maxHeight: minimised ? "auto" : "min(600px, calc(100vh - 120px))"
|
|
1486
|
+
},
|
|
1487
|
+
children: [
|
|
1488
|
+
!inline && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "shrink-0 flex items-center gap-2.5 px-3 py-2.5 border-b border-border bg-card", children: [
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1490
|
+
import_lucide_react6.BrainCircuit,
|
|
1491
|
+
{
|
|
1492
|
+
className: "size-4 text-primary shrink-0",
|
|
1493
|
+
"aria-hidden": "true"
|
|
1494
|
+
}
|
|
1495
|
+
),
|
|
1496
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-sm font-semibold text-foreground flex-1 truncate", children: "Policy AI" }),
|
|
1497
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
1498
|
+
isChatMode && onReset && !minimised && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1499
|
+
Button,
|
|
1500
|
+
{
|
|
1501
|
+
variant: "ghost",
|
|
1502
|
+
size: "icon-sm",
|
|
1503
|
+
onClick: onReset,
|
|
1504
|
+
title: "New conversation",
|
|
1505
|
+
"aria-label": "New conversation",
|
|
1506
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.RotateCcw, { className: "size-3.5", "aria-hidden": "true" })
|
|
1507
|
+
}
|
|
1508
|
+
),
|
|
1509
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1510
|
+
Button,
|
|
1511
|
+
{
|
|
1512
|
+
variant: "ghost",
|
|
1513
|
+
size: "icon-sm",
|
|
1514
|
+
onClick: () => setMinimised((v) => !v),
|
|
1515
|
+
title: minimised ? "Restore" : "Minimise",
|
|
1516
|
+
"aria-label": minimised ? "Restore panel" : "Minimise panel",
|
|
1517
|
+
children: minimised ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.ChevronDown, { className: "size-3.5", "aria-hidden": "true" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.Minus, { className: "size-3.5", "aria-hidden": "true" })
|
|
1518
|
+
}
|
|
1519
|
+
),
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1521
|
+
Button,
|
|
1522
|
+
{
|
|
1523
|
+
variant: "ghost",
|
|
1524
|
+
size: "icon-sm",
|
|
1525
|
+
onClick: onClose,
|
|
1526
|
+
title: "Close",
|
|
1527
|
+
"aria-label": "Close Policy AI",
|
|
1528
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.X, { className: "size-3.5", "aria-hidden": "true" })
|
|
1529
|
+
}
|
|
1530
|
+
)
|
|
1531
|
+
] })
|
|
1532
|
+
] }),
|
|
1533
|
+
(!minimised || inline) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn(!inline && "flex-1 overflow-y-auto min-h-0"), children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col justify-center h-full py-8", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PolicyAIThinkingSteps, { steps: resolvedThinkingSteps }) }) : !isChatMode ? (
|
|
1535
|
+
/* Home state — suggested questions by policy type */
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col", children: [
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "px-3 pt-3 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs text-muted-foreground leading-relaxed", children: "Ask me about lending policies across 40+ Australian banks \u2014 income, LVR, security types, serviceability, and more." }) }),
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border-b border-border px-3 pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1539
|
+
Tabs,
|
|
1540
|
+
{
|
|
1541
|
+
value: activeTab,
|
|
1542
|
+
onValueChange: (v) => setActiveTab(v),
|
|
1543
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1544
|
+
TabsList,
|
|
1545
|
+
{
|
|
1546
|
+
variant: "line",
|
|
1547
|
+
className: "justify-start h-8 gap-0 -mb-px overflow-x-auto",
|
|
1548
|
+
children: Object.keys(DEFAULT_SUGGESTED).map(
|
|
1549
|
+
(type) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1550
|
+
TabsTrigger,
|
|
1551
|
+
{
|
|
1552
|
+
value: type,
|
|
1553
|
+
className: "text-xs px-2 h-7 shrink-0",
|
|
1554
|
+
children: type
|
|
1555
|
+
},
|
|
1556
|
+
type
|
|
1557
|
+
)
|
|
1558
|
+
)
|
|
1559
|
+
}
|
|
1560
|
+
)
|
|
1561
|
+
}
|
|
1562
|
+
) }),
|
|
1563
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex flex-col px-3 py-2 gap-1", children: ((_a = (suggestedQuestions != null ? suggestedQuestions : DEFAULT_SUGGESTED)[activeTab]) != null ? _a : []).map((q) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1564
|
+
"button",
|
|
1565
|
+
{
|
|
1566
|
+
onClick: () => setInputValue(q),
|
|
1567
|
+
className: "w-full text-left text-xs text-foreground px-3 py-2 border border-border hover:bg-muted/60 transition-colors leading-relaxed",
|
|
1568
|
+
children: q
|
|
1569
|
+
},
|
|
1570
|
+
q
|
|
1571
|
+
)) })
|
|
1572
|
+
] })
|
|
1573
|
+
) : (
|
|
1574
|
+
/* Chat state — messages + structured response cards */
|
|
1575
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-4 px-3 py-3", children: [
|
|
1576
|
+
messages.map(
|
|
1577
|
+
(msg) => msg.role === "user" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1578
|
+
ChatWidgetMessage,
|
|
1579
|
+
{
|
|
1580
|
+
role: "user",
|
|
1581
|
+
content: msg.content
|
|
1582
|
+
},
|
|
1583
|
+
msg.id
|
|
1584
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1585
|
+
msg.content && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-foreground leading-relaxed", children: msg.content }),
|
|
1586
|
+
msg.responseContent && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1587
|
+
ResponseCard,
|
|
1588
|
+
{
|
|
1589
|
+
content: msg.responseContent,
|
|
1590
|
+
queryContext: msg.queryContext
|
|
1591
|
+
}
|
|
1592
|
+
)
|
|
1593
|
+
] }, msg.id)
|
|
1594
|
+
),
|
|
1595
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PolicyAIThinkingSteps, { steps: resolvedThinkingSteps }),
|
|
1596
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: messagesEndRef })
|
|
1597
|
+
] })
|
|
1598
|
+
) }),
|
|
1599
|
+
!isLoading && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1600
|
+
"div",
|
|
1601
|
+
{
|
|
1602
|
+
className: cn(
|
|
1603
|
+
"border-t border-border px-3 py-3 bg-card",
|
|
1604
|
+
inline ? "sticky bottom-0 z-10" : "shrink-0"
|
|
1605
|
+
),
|
|
1606
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1607
|
+
ChatInputArea,
|
|
1608
|
+
{
|
|
1609
|
+
value: inputValue,
|
|
1610
|
+
onChange: setInputValue,
|
|
1611
|
+
onSend: handleSend,
|
|
1612
|
+
onAttachFile,
|
|
1613
|
+
onAttachImage,
|
|
1614
|
+
disabled: isStreaming,
|
|
1615
|
+
placeholder: "Ask about lending policies\u2026",
|
|
1616
|
+
autoFocus: !minimised
|
|
1617
|
+
}
|
|
1618
|
+
)
|
|
1619
|
+
}
|
|
1620
|
+
)
|
|
1621
|
+
] })
|
|
1622
|
+
]
|
|
1623
|
+
}
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1627
|
+
0 && (module.exports = {
|
|
1628
|
+
PolicyAIFAB,
|
|
1629
|
+
PolicyAIPanel,
|
|
1630
|
+
PolicyCitationPanel,
|
|
1631
|
+
PolicyComparisonTable,
|
|
1632
|
+
PolicyQueryChip,
|
|
1633
|
+
PolicyRankedList,
|
|
1634
|
+
PolicySingleBankAnswer,
|
|
1635
|
+
PolicyVerdictBadge
|
|
1636
|
+
});
|