@retrivora-ai/rag-engine 1.5.5 → 1.5.7
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/dist/{chunk-Q4MDH6C4.mjs → chunk-ID2Q4CF7.mjs} +2 -0
- package/dist/handlers/index.js +2 -0
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +118 -40
- package/dist/index.mjs +118 -40
- package/dist/server.js +2 -0
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +26 -0
- package/src/components/DynamicChart.tsx +32 -16
- package/src/components/MessageBubble.tsx +112 -27
- package/src/components/ProductCarousel.tsx +2 -2
- package/src/core/Pipeline.ts +2 -0
- package/src/types/props.ts +3 -0
package/dist/index.mjs
CHANGED
|
@@ -123,7 +123,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
123
123
|
};
|
|
124
124
|
if (!products || products.length === 0) return null;
|
|
125
125
|
if (products.length === 1) {
|
|
126
|
-
return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[
|
|
126
|
+
return /* @__PURE__ */ React3.createElement("div", { className: "my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up" }, /* @__PURE__ */ React3.createElement(ProductCard, { product: products[0], primaryColor, onAddToCart }));
|
|
127
127
|
}
|
|
128
128
|
return /* @__PURE__ */ React3.createElement("div", { className: "relative w-full my-4 group/carousel animate-fade-in-up" }, canScroll && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { className: "absolute -left-4 top-1/2 -translate-y-1/2 z-20 opacity-100 md:opacity-0 md:group-hover/carousel:opacity-100 transition-opacity" }, /* @__PURE__ */ React3.createElement(
|
|
129
129
|
"button",
|
|
@@ -158,7 +158,7 @@ function ProductCarousel({ products, primaryColor = "#6366f1", onAddToCart }) {
|
|
|
158
158
|
"div",
|
|
159
159
|
{
|
|
160
160
|
key: product.id,
|
|
161
|
-
className: "snap-start flex-shrink-0 w-[
|
|
161
|
+
className: "snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
|
|
162
162
|
},
|
|
163
163
|
/* @__PURE__ */ React3.createElement(ProductCard, { product, primaryColor, onAddToCart })
|
|
164
164
|
))
|
|
@@ -183,9 +183,20 @@ import {
|
|
|
183
183
|
ResponsiveContainer
|
|
184
184
|
} from "recharts";
|
|
185
185
|
var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"];
|
|
186
|
-
function DynamicChart({
|
|
186
|
+
function DynamicChart({
|
|
187
|
+
config,
|
|
188
|
+
primaryColor = "#6366f1",
|
|
189
|
+
accentColor = "#8b5cf6",
|
|
190
|
+
viewportSize = "large"
|
|
191
|
+
}) {
|
|
187
192
|
const { type, data } = config;
|
|
188
193
|
const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
|
|
194
|
+
const isCompact = viewportSize === "compact";
|
|
195
|
+
const isMedium = viewportSize === "medium";
|
|
196
|
+
const chartHeightClass = isCompact ? "h-56 min-h-[220px]" : isMedium ? "h-64 min-h-[250px]" : "h-72 min-h-[280px]";
|
|
197
|
+
const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
|
|
198
|
+
const pieLabel = ({ name, percent }) => isCompact ? `${name}` : `${name} ${((percent != null ? percent : 0) * 100).toFixed(0)}%`;
|
|
199
|
+
const axisTick = { fontSize: isCompact ? 10 : 12, fill: "#64748b" };
|
|
189
200
|
const sanitizedData = React4.useMemo(() => {
|
|
190
201
|
if (!data) return [];
|
|
191
202
|
return data.map((item) => {
|
|
@@ -285,7 +296,7 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
285
296
|
return row;
|
|
286
297
|
};
|
|
287
298
|
if (type === "pie") {
|
|
288
|
-
return /* @__PURE__ */ React4.createElement("div", { className:
|
|
299
|
+
return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
|
|
289
300
|
Pie,
|
|
290
301
|
{
|
|
291
302
|
data: sanitizedData,
|
|
@@ -293,31 +304,31 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
293
304
|
nameKey: finalXKey,
|
|
294
305
|
cx: "50%",
|
|
295
306
|
cy: "50%",
|
|
296
|
-
outerRadius:
|
|
297
|
-
label:
|
|
307
|
+
outerRadius: pieOuterRadius,
|
|
308
|
+
label: pieLabel
|
|
298
309
|
},
|
|
299
310
|
sanitizedData.map((entry, index) => /* @__PURE__ */ React4.createElement(Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
|
|
300
|
-
), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend,
|
|
311
|
+
), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }))));
|
|
301
312
|
}
|
|
302
|
-
return /* @__PURE__ */ React4.createElement("div", { className:
|
|
313
|
+
return /* @__PURE__ */ React4.createElement("div", { className: `w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden` }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
303
314
|
Bar,
|
|
304
315
|
{
|
|
305
316
|
key,
|
|
306
317
|
dataKey: key,
|
|
307
318
|
fill: colors[index % colors.length],
|
|
308
319
|
radius: [4, 4, 0, 0],
|
|
309
|
-
barSize: Math.max(20, 60 / data.length)
|
|
320
|
+
barSize: isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)
|
|
310
321
|
}
|
|
311
|
-
))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick:
|
|
322
|
+
))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: axisTick, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
312
323
|
Line,
|
|
313
324
|
{
|
|
314
325
|
key,
|
|
315
326
|
type: "monotone",
|
|
316
327
|
dataKey: key,
|
|
317
328
|
stroke: colors[index % colors.length],
|
|
318
|
-
strokeWidth: 3,
|
|
319
|
-
dot: { r: 4, strokeWidth: 2 },
|
|
320
|
-
activeDot: { r: 6 }
|
|
329
|
+
strokeWidth: isCompact ? 2 : 3,
|
|
330
|
+
dot: { r: isCompact ? 3 : 4, strokeWidth: 2 },
|
|
331
|
+
activeDot: { r: isCompact ? 5 : 6 }
|
|
321
332
|
}
|
|
322
333
|
)))));
|
|
323
334
|
}
|
|
@@ -376,6 +387,14 @@ function sanitizeJson(raw) {
|
|
|
376
387
|
}
|
|
377
388
|
return s;
|
|
378
389
|
}
|
|
390
|
+
function extractLikelyJsonBlock(raw) {
|
|
391
|
+
const trimmed = raw.trim();
|
|
392
|
+
const objectStart = trimmed.indexOf("{");
|
|
393
|
+
const arrayStart = trimmed.indexOf("[");
|
|
394
|
+
const starts = [objectStart, arrayStart].filter((index) => index >= 0);
|
|
395
|
+
if (starts.length === 0) return trimmed;
|
|
396
|
+
return trimmed.slice(Math.min(...starts));
|
|
397
|
+
}
|
|
379
398
|
function resolveImage(data) {
|
|
380
399
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
381
400
|
const v = data[key];
|
|
@@ -392,7 +411,9 @@ function normaliseChild(children) {
|
|
|
392
411
|
}
|
|
393
412
|
return children;
|
|
394
413
|
}
|
|
395
|
-
function DataTable({ config }) {
|
|
414
|
+
function DataTable({ config, viewportSize = "large" }) {
|
|
415
|
+
const isCompact = viewportSize === "compact";
|
|
416
|
+
const isMedium = viewportSize === "medium";
|
|
396
417
|
const keys = React5.useMemo(() => {
|
|
397
418
|
if (Array.isArray(config.columns) && config.columns.length) {
|
|
398
419
|
return config.columns;
|
|
@@ -414,11 +435,11 @@ function DataTable({ config }) {
|
|
|
414
435
|
if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
|
|
415
436
|
return String(val);
|
|
416
437
|
};
|
|
417
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.createElement("table", { className:
|
|
438
|
+
return /* @__PURE__ */ React5.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React5.createElement("table", { className: `w-full text-left border-collapse ${isCompact ? "min-w-[240px] text-xs" : isMedium ? "min-w-[280px] text-[13px]" : "min-w-[320px] text-sm"}` }, /* @__PURE__ */ React5.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ React5.createElement("tr", null, keys.map((k) => /* @__PURE__ */ React5.createElement(
|
|
418
439
|
"th",
|
|
419
440
|
{
|
|
420
441
|
key: k,
|
|
421
|
-
className: "px-4 py-3 font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap
|
|
442
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
|
|
422
443
|
},
|
|
423
444
|
k
|
|
424
445
|
)))), /* @__PURE__ */ React5.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ React5.createElement(
|
|
@@ -431,34 +452,63 @@ function DataTable({ config }) {
|
|
|
431
452
|
"td",
|
|
432
453
|
{
|
|
433
454
|
key: k,
|
|
434
|
-
className: "px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap
|
|
455
|
+
className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} text-slate-600 dark:text-white/70 whitespace-nowrap`
|
|
435
456
|
},
|
|
436
457
|
formatCell(row[k])
|
|
437
458
|
))
|
|
438
459
|
))))), /* @__PURE__ */ React5.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ React5.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
|
|
439
460
|
}
|
|
440
|
-
function
|
|
461
|
+
function normalizeTabularRows(rows, columns) {
|
|
462
|
+
if (!Array.isArray(rows)) return [];
|
|
463
|
+
return rows.map((row) => {
|
|
464
|
+
if (Array.isArray(row)) {
|
|
465
|
+
const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
|
|
466
|
+
return keys.reduce((acc, key, index) => {
|
|
467
|
+
acc[key] = row[index];
|
|
468
|
+
return acc;
|
|
469
|
+
}, {});
|
|
470
|
+
}
|
|
471
|
+
if (row && typeof row === "object") {
|
|
472
|
+
return row;
|
|
473
|
+
}
|
|
474
|
+
return { value: row };
|
|
475
|
+
}).filter((row) => Object.keys(row).length > 0);
|
|
476
|
+
}
|
|
477
|
+
function resolveStructuredRows(config) {
|
|
478
|
+
if (Array.isArray(config.data) && config.data.length > 0) return config.data;
|
|
479
|
+
if (Array.isArray(config.rows) && config.rows.length > 0) return config.rows;
|
|
480
|
+
if (Array.isArray(config.items) && config.items.length > 0) return config.items;
|
|
481
|
+
if (Array.isArray(config.products) && config.products.length > 0) return config.products;
|
|
482
|
+
if (Array.isArray(config.results) && config.results.length > 0) return config.results;
|
|
483
|
+
return [];
|
|
484
|
+
}
|
|
485
|
+
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
|
|
441
486
|
var _a;
|
|
442
487
|
const result = React5.useMemo(() => {
|
|
443
488
|
if (isStreaming) return { loading: true };
|
|
444
489
|
try {
|
|
445
490
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
446
|
-
const parsed = JSON.parse(sanitizeJson(clean));
|
|
491
|
+
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
447
492
|
const config2 = __spreadValues({}, parsed);
|
|
448
493
|
if (!config2.view) {
|
|
449
494
|
if (config2.type === "products" || Array.isArray(config2.items)) {
|
|
450
495
|
config2.view = "carousel";
|
|
451
496
|
config2.data = config2.data || config2.items || [];
|
|
452
|
-
} else if (["pie", "bar", "line"].includes(config2.type) || ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
497
|
+
} else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
498
|
+
const resolvedChartType = config2.chartType === "pie" || config2.chartType === "bar" || config2.chartType === "line" ? config2.chartType : config2.type === "pie" || config2.type === "bar" || config2.type === "line" ? config2.type : "bar";
|
|
453
499
|
config2.view = "chart";
|
|
454
|
-
config2.chartType =
|
|
500
|
+
config2.chartType = resolvedChartType;
|
|
455
501
|
config2.data = config2.data || [];
|
|
456
502
|
} else {
|
|
457
503
|
config2.view = "table";
|
|
458
504
|
config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
|
|
459
505
|
}
|
|
460
506
|
}
|
|
461
|
-
|
|
507
|
+
const resolvedRows = resolveStructuredRows(config2);
|
|
508
|
+
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
509
|
+
data: normalizeTabularRows(resolvedRows, config2.columns)
|
|
510
|
+
});
|
|
511
|
+
return { config: normalizedConfig };
|
|
462
512
|
} catch (err) {
|
|
463
513
|
return { error: String(err) };
|
|
464
514
|
}
|
|
@@ -470,11 +520,12 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
470
520
|
return /* @__PURE__ */ React5.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ React5.createElement("code", null, rawContent));
|
|
471
521
|
}
|
|
472
522
|
const { config } = result;
|
|
523
|
+
const isCompact = viewportSize === "compact";
|
|
473
524
|
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
474
525
|
const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
|
|
475
526
|
switch (config.view) {
|
|
476
527
|
case "chart":
|
|
477
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-6 p-4 bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden
|
|
528
|
+
return /* @__PURE__ */ React5.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(
|
|
478
529
|
DynamicChart,
|
|
479
530
|
{
|
|
480
531
|
config: {
|
|
@@ -485,25 +536,26 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
485
536
|
colors: config.colors
|
|
486
537
|
},
|
|
487
538
|
primaryColor,
|
|
488
|
-
accentColor
|
|
539
|
+
accentColor,
|
|
540
|
+
viewportSize
|
|
489
541
|
}
|
|
490
542
|
), hasInsights && /* @__PURE__ */ React5.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ React5.createElement(
|
|
491
543
|
"span",
|
|
492
544
|
{
|
|
493
545
|
key: insight,
|
|
494
|
-
className:
|
|
546
|
+
className: `rounded-full border border-emerald-200 bg-emerald-50 ${isCompact ? "px-2.5 py-1 text-[10px]" : "px-3 py-1 text-[11px]"} font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300`
|
|
495
547
|
},
|
|
496
548
|
insight
|
|
497
549
|
))));
|
|
498
550
|
case "carousel":
|
|
499
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: "mb-2 text-xs font-semibold text-slate-500
|
|
551
|
+
return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
|
|
500
552
|
var _a2;
|
|
501
553
|
return __spreadProps(__spreadValues({}, item), {
|
|
502
554
|
image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
|
|
503
555
|
});
|
|
504
556
|
}), primaryColor, onAddToCart }));
|
|
505
557
|
case "table":
|
|
506
|
-
return /* @__PURE__ */ React5.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto
|
|
558
|
+
return /* @__PURE__ */ React5.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(DataTable, { config: {
|
|
507
559
|
type: "table",
|
|
508
560
|
title: config.title,
|
|
509
561
|
description: config.description,
|
|
@@ -511,7 +563,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
511
563
|
dataKeys: config.dataKeys,
|
|
512
564
|
xAxisKey: config.xAxisKey,
|
|
513
565
|
data: config.data
|
|
514
|
-
} }));
|
|
566
|
+
}, viewportSize }));
|
|
515
567
|
default:
|
|
516
568
|
return null;
|
|
517
569
|
}
|
|
@@ -522,9 +574,12 @@ function MessageBubble({
|
|
|
522
574
|
isStreaming = false,
|
|
523
575
|
primaryColor = "#6366f1",
|
|
524
576
|
accentColor = "#8b5cf6",
|
|
525
|
-
onAddToCart
|
|
577
|
+
onAddToCart,
|
|
578
|
+
viewportSize = "large"
|
|
526
579
|
}) {
|
|
527
580
|
const isUser = message.role === "user";
|
|
581
|
+
const isCompact = viewportSize === "compact";
|
|
582
|
+
const isMedium = viewportSize === "medium";
|
|
528
583
|
const [showSources, setShowSources] = React5.useState(false);
|
|
529
584
|
const hasStructuredProductBlock = React5.useMemo(
|
|
530
585
|
() => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
|
|
@@ -701,7 +756,8 @@ ${match.trim()}
|
|
|
701
756
|
primaryColor,
|
|
702
757
|
accentColor,
|
|
703
758
|
isStreaming,
|
|
704
|
-
onAddToCart
|
|
759
|
+
onAddToCart,
|
|
760
|
+
viewportSize
|
|
705
761
|
}
|
|
706
762
|
);
|
|
707
763
|
}
|
|
@@ -715,7 +771,8 @@ ${match.trim()}
|
|
|
715
771
|
primaryColor,
|
|
716
772
|
accentColor,
|
|
717
773
|
isStreaming,
|
|
718
|
-
onAddToCart
|
|
774
|
+
onAddToCart,
|
|
775
|
+
viewportSize
|
|
719
776
|
}
|
|
720
777
|
);
|
|
721
778
|
}
|
|
@@ -726,22 +783,22 @@ ${match.trim()}
|
|
|
726
783
|
return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
727
784
|
}
|
|
728
785
|
}),
|
|
729
|
-
[primaryColor, accentColor, isStreaming, onAddToCart]
|
|
786
|
+
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
|
|
730
787
|
);
|
|
731
|
-
return /* @__PURE__ */ React5.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
|
|
788
|
+
return /* @__PURE__ */ React5.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
|
|
732
789
|
"div",
|
|
733
790
|
{
|
|
734
|
-
className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
|
|
791
|
+
className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
|
|
735
792
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
736
793
|
},
|
|
737
|
-
isUser ? /* @__PURE__ */ React5.createElement(User, { className: "w-4 h-4 text-white
|
|
738
|
-
), /* @__PURE__ */ React5.createElement("div", { className: `flex flex-col gap-1 max-w-[90%] ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ React5.createElement(
|
|
794
|
+
isUser ? /* @__PURE__ */ React5.createElement(User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ React5.createElement(Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
|
|
795
|
+
), /* @__PURE__ */ React5.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ React5.createElement(
|
|
739
796
|
"div",
|
|
740
797
|
{
|
|
741
|
-
className: `relative px-4 py-3 rounded-2xl
|
|
798
|
+
className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
|
|
742
799
|
style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
|
743
800
|
},
|
|
744
|
-
isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
801
|
+
isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
|
|
745
802
|
), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
|
|
746
803
|
ProductCarousel,
|
|
747
804
|
{
|
|
@@ -1024,6 +1081,8 @@ function ChatWindow({
|
|
|
1024
1081
|
const { ui, projectId } = useConfig();
|
|
1025
1082
|
const [input, setInput] = useState4("");
|
|
1026
1083
|
const [mounted, setMounted] = useState4(false);
|
|
1084
|
+
const [viewportSize, setViewportSize] = useState4("large");
|
|
1085
|
+
const windowRef = useRef3(null);
|
|
1027
1086
|
const bottomRef = useRef3(null);
|
|
1028
1087
|
const inputRef = useRef3(null);
|
|
1029
1088
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
@@ -1082,6 +1141,22 @@ function ChatWindow({
|
|
|
1082
1141
|
useEffect4(() => {
|
|
1083
1142
|
setMounted(true);
|
|
1084
1143
|
}, []);
|
|
1144
|
+
useEffect4(() => {
|
|
1145
|
+
const element = windowRef.current;
|
|
1146
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
1147
|
+
const resolveViewportSize = (width) => {
|
|
1148
|
+
if (width < 420) return "compact";
|
|
1149
|
+
if (width < 640) return "medium";
|
|
1150
|
+
return "large";
|
|
1151
|
+
};
|
|
1152
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
1153
|
+
if (!entry) return;
|
|
1154
|
+
setViewportSize(resolveViewportSize(entry.contentRect.width));
|
|
1155
|
+
});
|
|
1156
|
+
setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
|
|
1157
|
+
observer.observe(element);
|
|
1158
|
+
return () => observer.disconnect();
|
|
1159
|
+
}, []);
|
|
1085
1160
|
useEffect4(() => {
|
|
1086
1161
|
var _a2;
|
|
1087
1162
|
if (messages.length > 0 || isLoading) {
|
|
@@ -1145,6 +1220,7 @@ function ChatWindow({
|
|
|
1145
1220
|
return /* @__PURE__ */ React8.createElement(
|
|
1146
1221
|
"div",
|
|
1147
1222
|
{
|
|
1223
|
+
ref: windowRef,
|
|
1148
1224
|
className: `relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${isGlass ? "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl" : "bg-white dark:bg-[#0f0f1a]"} ${className}`,
|
|
1149
1225
|
style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
|
|
1150
1226
|
},
|
|
@@ -1241,7 +1317,8 @@ function ChatWindow({
|
|
|
1241
1317
|
isStreaming: isLoading && index === messages.length - 1 && msg.role === "assistant",
|
|
1242
1318
|
primaryColor: ui.primaryColor,
|
|
1243
1319
|
accentColor: ui.accentColor,
|
|
1244
|
-
onAddToCart
|
|
1320
|
+
onAddToCart,
|
|
1321
|
+
viewportSize
|
|
1245
1322
|
}
|
|
1246
1323
|
)), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ React8.createElement(
|
|
1247
1324
|
MessageBubble,
|
|
@@ -1250,7 +1327,8 @@ function ChatWindow({
|
|
|
1250
1327
|
isStreaming: true,
|
|
1251
1328
|
primaryColor: ui.primaryColor,
|
|
1252
1329
|
accentColor: ui.accentColor,
|
|
1253
|
-
onAddToCart
|
|
1330
|
+
onAddToCart,
|
|
1331
|
+
viewportSize
|
|
1254
1332
|
}
|
|
1255
1333
|
), error && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ React8.createElement(TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ React8.createElement("span", null, error)), /* @__PURE__ */ React8.createElement("div", { ref: bottomRef })),
|
|
1256
1334
|
/* @__PURE__ */ React8.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ React8.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ React8.createElement(
|
package/dist/server.js
CHANGED
|
@@ -3952,6 +3952,8 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
3952
3952
|
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
3953
3953
|
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
3954
3954
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
3955
|
+
- If the user explicitly asks for a pie chart, return "view": "chart" with "chartType": "pie", not a table fallback.
|
|
3956
|
+
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
3955
3957
|
|
|
3956
3958
|
5. EXAMPLE
|
|
3957
3959
|
User: "provide me the distribution of products across categories and highlight which ones are in stock in a pie chart"
|
package/dist/server.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.7",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -65,6 +65,8 @@ export function ChatWindow({
|
|
|
65
65
|
const { ui, projectId } = useConfig();
|
|
66
66
|
const [input, setInput] = useState('');
|
|
67
67
|
const [mounted, setMounted] = useState(false);
|
|
68
|
+
const [viewportSize, setViewportSize] = useState<'compact' | 'medium' | 'large'>('large');
|
|
69
|
+
const windowRef = useRef<HTMLDivElement>(null);
|
|
68
70
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
69
71
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
70
72
|
const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
|
|
@@ -136,6 +138,27 @@ export function ChatWindow({
|
|
|
136
138
|
setMounted(true);
|
|
137
139
|
}, []);
|
|
138
140
|
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
const element = windowRef.current;
|
|
143
|
+
if (!element || typeof ResizeObserver === 'undefined') return;
|
|
144
|
+
|
|
145
|
+
const resolveViewportSize = (width: number) => {
|
|
146
|
+
if (width < 420) return 'compact';
|
|
147
|
+
if (width < 640) return 'medium';
|
|
148
|
+
return 'large';
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
152
|
+
if (!entry) return;
|
|
153
|
+
setViewportSize(resolveViewportSize(entry.contentRect.width));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
setViewportSize(resolveViewportSize(element.getBoundingClientRect().width));
|
|
157
|
+
observer.observe(element);
|
|
158
|
+
|
|
159
|
+
return () => observer.disconnect();
|
|
160
|
+
}, []);
|
|
161
|
+
|
|
139
162
|
// Scroll to bottom on new message (but not on initial mount with empty messages)
|
|
140
163
|
useEffect(() => {
|
|
141
164
|
if (messages.length > 0 || isLoading) {
|
|
@@ -206,6 +229,7 @@ export function ChatWindow({
|
|
|
206
229
|
|
|
207
230
|
return (
|
|
208
231
|
<div
|
|
232
|
+
ref={windowRef}
|
|
209
233
|
className={`relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${
|
|
210
234
|
isGlass
|
|
211
235
|
? 'bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl'
|
|
@@ -344,6 +368,7 @@ export function ChatWindow({
|
|
|
344
368
|
primaryColor={ui.primaryColor}
|
|
345
369
|
accentColor={ui.accentColor}
|
|
346
370
|
onAddToCart={onAddToCart}
|
|
371
|
+
viewportSize={viewportSize}
|
|
347
372
|
/>
|
|
348
373
|
))
|
|
349
374
|
)}
|
|
@@ -356,6 +381,7 @@ export function ChatWindow({
|
|
|
356
381
|
primaryColor={ui.primaryColor}
|
|
357
382
|
accentColor={ui.accentColor}
|
|
358
383
|
onAddToCart={onAddToCart}
|
|
384
|
+
viewportSize={viewportSize}
|
|
359
385
|
/>
|
|
360
386
|
)}
|
|
361
387
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
|
|
6
6
|
XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
|
|
7
7
|
} from 'recharts';
|
|
8
|
+
import { ChatViewportSize } from '../types/props';
|
|
8
9
|
|
|
9
10
|
export interface ChartConfig {
|
|
10
11
|
type: 'bar' | 'line' | 'pie';
|
|
@@ -18,13 +19,28 @@ interface DynamicChartProps {
|
|
|
18
19
|
config: ChartConfig;
|
|
19
20
|
primaryColor?: string;
|
|
20
21
|
accentColor?: string;
|
|
22
|
+
viewportSize?: ChatViewportSize;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
const DEFAULT_COLORS = ['#6366f1', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899'];
|
|
24
26
|
|
|
25
|
-
export function DynamicChart({
|
|
27
|
+
export function DynamicChart({
|
|
28
|
+
config,
|
|
29
|
+
primaryColor = '#6366f1',
|
|
30
|
+
accentColor = '#8b5cf6',
|
|
31
|
+
viewportSize = 'large',
|
|
32
|
+
}: DynamicChartProps) {
|
|
26
33
|
const { type, data } = config;
|
|
27
34
|
const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
|
|
35
|
+
const isCompact = viewportSize === 'compact';
|
|
36
|
+
const isMedium = viewportSize === 'medium';
|
|
37
|
+
const chartHeightClass = isCompact ? 'h-56 min-h-[220px]' : isMedium ? 'h-64 min-h-[250px]' : 'h-72 min-h-[280px]';
|
|
38
|
+
const pieOuterRadius = isCompact ? 56 : isMedium ? 68 : 80;
|
|
39
|
+
const pieLabel = ({ name, percent }: { name?: string; percent?: number }) =>
|
|
40
|
+
isCompact
|
|
41
|
+
? `${name}`
|
|
42
|
+
: `${name} ${((percent ?? 0) * 100).toFixed(0)}%`;
|
|
43
|
+
const axisTick = { fontSize: isCompact ? 10 : 12, fill: '#64748b' };
|
|
28
44
|
|
|
29
45
|
// CRITICAL: Sanitize the data array to remove any non-primitive values (objects/arrays)
|
|
30
46
|
// This prevents the "Objects are not valid as a React child" error in Tooltips/Legends
|
|
@@ -176,7 +192,7 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
176
192
|
// Handle Pie Chart separately as it has a different structure
|
|
177
193
|
if (type === 'pie') {
|
|
178
194
|
return (
|
|
179
|
-
<div className=
|
|
195
|
+
<div className={`w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden`}>
|
|
180
196
|
<ResponsiveContainer width="99%" height="100%">
|
|
181
197
|
<PieChart>
|
|
182
198
|
<Pie
|
|
@@ -185,15 +201,15 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
185
201
|
nameKey={finalXKey}
|
|
186
202
|
cx="50%"
|
|
187
203
|
cy="50%"
|
|
188
|
-
outerRadius={
|
|
189
|
-
label={
|
|
204
|
+
outerRadius={pieOuterRadius}
|
|
205
|
+
label={pieLabel}
|
|
190
206
|
>
|
|
191
207
|
{sanitizedData.map((entry, index) => (
|
|
192
208
|
<Cell key={`cell-${index}`} fill={stockAwareColor(entry, index)} />
|
|
193
209
|
))}
|
|
194
210
|
</Pie>
|
|
195
211
|
<Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} />
|
|
196
|
-
<Legend />
|
|
212
|
+
<Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
|
|
197
213
|
</PieChart>
|
|
198
214
|
</ResponsiveContainer>
|
|
199
215
|
</div>
|
|
@@ -202,41 +218,41 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
202
218
|
|
|
203
219
|
// Bar and Line charts
|
|
204
220
|
return (
|
|
205
|
-
<div className=
|
|
221
|
+
<div className={`w-full ${chartHeightClass} mt-4 mb-2 select-none overflow-hidden`}>
|
|
206
222
|
<ResponsiveContainer width="99%" height="100%">
|
|
207
223
|
{type === 'bar' ? (
|
|
208
224
|
<BarChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
|
209
225
|
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
|
|
210
|
-
<XAxis dataKey={finalXKey} tick={
|
|
211
|
-
<YAxis tick={
|
|
226
|
+
<XAxis dataKey={finalXKey} tick={axisTick} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
|
|
227
|
+
<YAxis tick={axisTick} tickLine={false} axisLine={false} />
|
|
212
228
|
<Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} cursor={{ fill: '#f1f5f9' }} />
|
|
213
|
-
<Legend wrapperStyle={{ fontSize: 12 }} />
|
|
229
|
+
<Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
|
|
214
230
|
{finalDataKeys.map((key, index) => (
|
|
215
231
|
<Bar
|
|
216
232
|
key={key}
|
|
217
233
|
dataKey={key}
|
|
218
234
|
fill={colors[index % colors.length]}
|
|
219
235
|
radius={[4, 4, 0, 0]}
|
|
220
|
-
barSize={Math.max(20, 60 / data.length)}
|
|
236
|
+
barSize={isCompact ? Math.max(14, 42 / data.length) : Math.max(20, 60 / data.length)}
|
|
221
237
|
/>
|
|
222
238
|
))}
|
|
223
239
|
</BarChart>
|
|
224
240
|
) : (
|
|
225
241
|
<LineChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
|
226
242
|
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
|
|
227
|
-
<XAxis dataKey={finalXKey} tick={
|
|
228
|
-
<YAxis tick={
|
|
243
|
+
<XAxis dataKey={finalXKey} tick={axisTick} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
|
|
244
|
+
<YAxis tick={axisTick} tickLine={false} axisLine={false} />
|
|
229
245
|
<Tooltip content={(props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === 'string' ? props.label : undefined)} />
|
|
230
|
-
<Legend wrapperStyle={{ fontSize: 12 }} />
|
|
246
|
+
<Legend wrapperStyle={{ fontSize: isCompact ? 10 : 12 }} />
|
|
231
247
|
{finalDataKeys.map((key, index) => (
|
|
232
248
|
<Line
|
|
233
249
|
key={key}
|
|
234
250
|
type="monotone"
|
|
235
251
|
dataKey={key}
|
|
236
252
|
stroke={colors[index % colors.length]}
|
|
237
|
-
strokeWidth={3}
|
|
238
|
-
dot={{ r: 4, strokeWidth: 2 }}
|
|
239
|
-
activeDot={{ r: 6 }}
|
|
253
|
+
strokeWidth={isCompact ? 2 : 3}
|
|
254
|
+
dot={{ r: isCompact ? 3 : 4, strokeWidth: 2 }}
|
|
255
|
+
activeDot={{ r: isCompact ? 5 : 6 }}
|
|
240
256
|
/>
|
|
241
257
|
))}
|
|
242
258
|
</LineChart>
|