@underverse-ui/underverse 0.2.39 → 0.2.40
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/index.cjs +1581 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -1
- package/dist/index.d.ts +145 -1
- package/dist/index.js +1575 -204
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,9 +32,11 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AccessDenied: () => AccessDenied,
|
|
34
34
|
Alert: () => Alert_default,
|
|
35
|
+
AreaChart: () => AreaChart,
|
|
35
36
|
Avatar: () => Avatar_default,
|
|
36
37
|
Badge: () => Badge_default,
|
|
37
38
|
BadgeBase: () => Badge,
|
|
39
|
+
BarChart: () => BarChart,
|
|
38
40
|
BatteryProgress: () => BatteryProgress,
|
|
39
41
|
BottomSheet: () => BottomSheet,
|
|
40
42
|
Breadcrumb: () => Breadcrumb_default,
|
|
@@ -72,6 +74,7 @@ __export(index_exports, {
|
|
|
72
74
|
FormLabel: () => FormLabel,
|
|
73
75
|
FormMessage: () => FormMessage,
|
|
74
76
|
FormSubmitButton: () => FormSubmitButton,
|
|
77
|
+
GaugeChart: () => GaugeChart,
|
|
75
78
|
GlobalLoading: () => GlobalLoading,
|
|
76
79
|
GradientBadge: () => GradientBadge,
|
|
77
80
|
Grid: () => Grid_default,
|
|
@@ -83,6 +86,7 @@ __export(index_exports, {
|
|
|
83
86
|
Label: () => Label,
|
|
84
87
|
LanguageSwitcher: () => LanguageSwitcherHeadless,
|
|
85
88
|
LanguageSwitcherHeadless: () => LanguageSwitcherHeadless,
|
|
89
|
+
LineChart: () => LineChart,
|
|
86
90
|
List: () => List_default,
|
|
87
91
|
ListItem: () => ListItem,
|
|
88
92
|
LoadingBar: () => LoadingBar,
|
|
@@ -99,10 +103,12 @@ __export(index_exports, {
|
|
|
99
103
|
PageLoading: () => PageLoading,
|
|
100
104
|
Pagination: () => Pagination,
|
|
101
105
|
PasswordInput: () => PasswordInput,
|
|
106
|
+
PieChart: () => PieChart,
|
|
102
107
|
PillTabs: () => PillTabs,
|
|
103
108
|
Popover: () => Popover,
|
|
104
109
|
Progress: () => Progress,
|
|
105
110
|
PulseBadge: () => PulseBadge,
|
|
111
|
+
RadarChart: () => RadarChart,
|
|
106
112
|
RadioGroup: () => RadioGroup,
|
|
107
113
|
RadioGroupItem: () => RadioGroupItem,
|
|
108
114
|
SIZE_STYLES_BTN: () => SIZE_STYLES_BTN,
|
|
@@ -127,6 +133,7 @@ __export(index_exports, {
|
|
|
127
133
|
SlideOver: () => SlideOver,
|
|
128
134
|
Slider: () => Slider,
|
|
129
135
|
SmartImage: () => SmartImage,
|
|
136
|
+
Sparkline: () => Sparkline,
|
|
130
137
|
StatusBadge: () => StatusBadge,
|
|
131
138
|
StepProgress: () => StepProgress,
|
|
132
139
|
Switch: () => Switch_default,
|
|
@@ -10439,23 +10446,1387 @@ GridItem.displayName = "Grid.Item";
|
|
|
10439
10446
|
var Grid = Object.assign(GridRoot, { Item: GridItem });
|
|
10440
10447
|
var Grid_default = Grid;
|
|
10441
10448
|
|
|
10442
|
-
// ../../components/ui/
|
|
10449
|
+
// ../../components/ui/LineChart.tsx
|
|
10450
|
+
var import_react23 = require("react");
|
|
10451
|
+
|
|
10452
|
+
// ../../components/ui/ChartTooltip.tsx
|
|
10443
10453
|
var import_react22 = require("react");
|
|
10454
|
+
var import_react_dom10 = require("react-dom");
|
|
10444
10455
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
10445
|
-
function
|
|
10446
|
-
const [
|
|
10456
|
+
function ChartTooltip({ x, y, visible, label, value, color, secondaryLabel, secondaryValue, items, containerRef }) {
|
|
10457
|
+
const [isMounted, setIsMounted] = (0, import_react22.useState)(false);
|
|
10458
|
+
const [position, setPosition] = (0, import_react22.useState)(null);
|
|
10459
|
+
(0, import_react22.useEffect)(() => {
|
|
10460
|
+
setIsMounted(true);
|
|
10461
|
+
}, []);
|
|
10447
10462
|
(0, import_react22.useEffect)(() => {
|
|
10463
|
+
if (visible && containerRef?.current) {
|
|
10464
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
10465
|
+
setPosition({
|
|
10466
|
+
top: rect.top + y,
|
|
10467
|
+
left: rect.left + x
|
|
10468
|
+
});
|
|
10469
|
+
}
|
|
10470
|
+
}, [visible, x, y, containerRef]);
|
|
10471
|
+
if (!visible || !isMounted || !position) return null;
|
|
10472
|
+
const tooltipContent = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
10473
|
+
"div",
|
|
10474
|
+
{
|
|
10475
|
+
style: {
|
|
10476
|
+
position: "fixed",
|
|
10477
|
+
top: position.top,
|
|
10478
|
+
left: position.left + 12,
|
|
10479
|
+
zIndex: 99999,
|
|
10480
|
+
pointerEvents: "none",
|
|
10481
|
+
animation: "chartTooltipFadeIn 0.15s ease-out"
|
|
10482
|
+
},
|
|
10483
|
+
children: [
|
|
10484
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
10485
|
+
"div",
|
|
10486
|
+
{
|
|
10487
|
+
className: cn("bg-popover text-popover-foreground border border-border", "rounded-lg shadow-xl px-3 py-2 text-sm", "backdrop-blur-sm"),
|
|
10488
|
+
style: {
|
|
10489
|
+
minWidth: "80px",
|
|
10490
|
+
width: "max-content",
|
|
10491
|
+
boxShadow: "0 10px 25px -3px rgba(0, 0, 0, 0.5), 0 4px 10px -2px rgba(0, 0, 0, 0.3)"
|
|
10492
|
+
},
|
|
10493
|
+
children: [
|
|
10494
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "text-muted-foreground text-xs mb-1", children: label }),
|
|
10495
|
+
items && items.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex flex-col gap-1", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10496
|
+
item.color && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "w-2 h-2 rounded-full shrink-0", style: { backgroundColor: item.color } }),
|
|
10497
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
10498
|
+
item.label,
|
|
10499
|
+
":"
|
|
10500
|
+
] }),
|
|
10501
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold ml-auto", children: item.value })
|
|
10502
|
+
] }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
10503
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10504
|
+
color && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "w-2 h-2 rounded-full shrink-0", style: { backgroundColor: color } }),
|
|
10505
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "font-semibold", children: value })
|
|
10506
|
+
] }),
|
|
10507
|
+
secondaryLabel && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "text-muted-foreground text-xs mt-1", children: [
|
|
10508
|
+
secondaryLabel,
|
|
10509
|
+
": ",
|
|
10510
|
+
secondaryValue
|
|
10511
|
+
] })
|
|
10512
|
+
] })
|
|
10513
|
+
]
|
|
10514
|
+
}
|
|
10515
|
+
),
|
|
10516
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("style", { children: `
|
|
10517
|
+
@keyframes chartTooltipFadeIn {
|
|
10518
|
+
from { opacity: 0; transform: translateX(-5px); }
|
|
10519
|
+
to { opacity: 1; transform: translateX(0); }
|
|
10520
|
+
}
|
|
10521
|
+
` })
|
|
10522
|
+
]
|
|
10523
|
+
}
|
|
10524
|
+
);
|
|
10525
|
+
return (0, import_react_dom10.createPortal)(tooltipContent, document.body);
|
|
10526
|
+
}
|
|
10527
|
+
|
|
10528
|
+
// ../../components/ui/LineChart.tsx
|
|
10529
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
10530
|
+
function LineChart({
|
|
10531
|
+
data,
|
|
10532
|
+
width = 400,
|
|
10533
|
+
height = 200,
|
|
10534
|
+
color = "currentColor",
|
|
10535
|
+
fillColor,
|
|
10536
|
+
showDots = true,
|
|
10537
|
+
showGrid = true,
|
|
10538
|
+
showLabels = true,
|
|
10539
|
+
showValues = false,
|
|
10540
|
+
animated = true,
|
|
10541
|
+
curved = true,
|
|
10542
|
+
className = ""
|
|
10543
|
+
}) {
|
|
10544
|
+
const svgRef = (0, import_react23.useRef)(null);
|
|
10545
|
+
const padding = { top: 20, right: 20, bottom: 40, left: 40 };
|
|
10546
|
+
const chartWidth = width - padding.left - padding.right;
|
|
10547
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
10548
|
+
const [hoveredPoint, setHoveredPoint] = (0, import_react23.useState)(null);
|
|
10549
|
+
const { minValue, maxValue, points, linePath, areaPath } = (0, import_react23.useMemo)(() => {
|
|
10550
|
+
if (!data.length) return { minValue: 0, maxValue: 0, points: [], linePath: "", areaPath: "" };
|
|
10551
|
+
const values = data.map((d) => d.value);
|
|
10552
|
+
const min = Math.min(...values);
|
|
10553
|
+
const max = Math.max(...values);
|
|
10554
|
+
const range = max - min || 1;
|
|
10555
|
+
const pts = data.map((d, i) => ({
|
|
10556
|
+
x: padding.left + i / (data.length - 1 || 1) * chartWidth,
|
|
10557
|
+
y: padding.top + chartHeight - (d.value - min) / range * chartHeight,
|
|
10558
|
+
...d
|
|
10559
|
+
}));
|
|
10560
|
+
let path = "";
|
|
10561
|
+
let area = "";
|
|
10562
|
+
if (curved && pts.length > 2) {
|
|
10563
|
+
path = `M ${pts[0].x} ${pts[0].y}`;
|
|
10564
|
+
area = `M ${pts[0].x} ${padding.top + chartHeight} L ${pts[0].x} ${pts[0].y}`;
|
|
10565
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
10566
|
+
const p0 = pts[Math.max(0, i - 1)];
|
|
10567
|
+
const p1 = pts[i];
|
|
10568
|
+
const p2 = pts[i + 1];
|
|
10569
|
+
const p3 = pts[Math.min(pts.length - 1, i + 2)];
|
|
10570
|
+
const cp1x = p1.x + (p2.x - p0.x) / 6;
|
|
10571
|
+
const cp1y = p1.y + (p2.y - p0.y) / 6;
|
|
10572
|
+
const cp2x = p2.x - (p3.x - p1.x) / 6;
|
|
10573
|
+
const cp2y = p2.y - (p3.y - p1.y) / 6;
|
|
10574
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
10575
|
+
area += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
10576
|
+
}
|
|
10577
|
+
area += ` L ${pts[pts.length - 1].x} ${padding.top + chartHeight} Z`;
|
|
10578
|
+
} else {
|
|
10579
|
+
path = pts.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
|
|
10580
|
+
area = `M ${pts[0].x} ${padding.top + chartHeight} ` + pts.map((p) => `L ${p.x} ${p.y}`).join(" ") + ` L ${pts[pts.length - 1].x} ${padding.top + chartHeight} Z`;
|
|
10581
|
+
}
|
|
10582
|
+
return { minValue: min, maxValue: max, points: pts, linePath: path, areaPath: area };
|
|
10583
|
+
}, [data, chartWidth, chartHeight, curved, padding.left, padding.top]);
|
|
10584
|
+
const gridLines = (0, import_react23.useMemo)(() => {
|
|
10585
|
+
const lines = [];
|
|
10586
|
+
const steps = 5;
|
|
10587
|
+
for (let i = 0; i <= steps; i++) {
|
|
10588
|
+
const y = padding.top + i / steps * chartHeight;
|
|
10589
|
+
const value = maxValue - i / steps * (maxValue - minValue);
|
|
10590
|
+
lines.push({ y, value });
|
|
10591
|
+
}
|
|
10592
|
+
return lines;
|
|
10593
|
+
}, [minValue, maxValue, chartHeight, padding.top]);
|
|
10594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
10595
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("svg", { ref: svgRef, width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
10596
|
+
showGrid && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("g", { children: [
|
|
10597
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("line", { x1: padding.left, y1: line.y, x2: width - padding.right, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10598
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", fill: "currentColor", className: "text-muted-foreground", children: line.value.toFixed(0) })
|
|
10599
|
+
] }, i)) }),
|
|
10600
|
+
fillColor && areaPath && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("path", { d: areaPath, fill: fillColor, opacity: 0.2, className: animated ? "animate-[fadeIn_0.6s_ease-out]" : "" }),
|
|
10601
|
+
linePath && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10602
|
+
"path",
|
|
10603
|
+
{
|
|
10604
|
+
d: linePath,
|
|
10605
|
+
fill: "none",
|
|
10606
|
+
stroke: color,
|
|
10607
|
+
strokeWidth: 2,
|
|
10608
|
+
strokeLinecap: "round",
|
|
10609
|
+
strokeLinejoin: "round",
|
|
10610
|
+
className: animated ? "animate-[drawLine_1s_ease-out]" : "",
|
|
10611
|
+
style: animated ? {
|
|
10612
|
+
strokeDasharray: 1e3,
|
|
10613
|
+
strokeDashoffset: 0,
|
|
10614
|
+
animation: "drawLine 1s ease-out forwards"
|
|
10615
|
+
} : void 0
|
|
10616
|
+
}
|
|
10617
|
+
),
|
|
10618
|
+
showDots && points.map((point, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
10619
|
+
"g",
|
|
10620
|
+
{
|
|
10621
|
+
onMouseEnter: () => setHoveredPoint({ x: point.x, y: point.y, label: point.label, value: point.value }),
|
|
10622
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
10623
|
+
className: "cursor-pointer",
|
|
10624
|
+
children: [
|
|
10625
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10626
|
+
"circle",
|
|
10627
|
+
{
|
|
10628
|
+
cx: point.x,
|
|
10629
|
+
cy: point.y,
|
|
10630
|
+
r: hoveredPoint?.x === point.x ? 6 : 4,
|
|
10631
|
+
fill: color,
|
|
10632
|
+
className: `transition-all duration-150 ${animated ? "animate-[scaleIn_0.3s_ease-out]" : ""}`,
|
|
10633
|
+
style: animated ? { animationDelay: `${i * 0.05}s`, animationFillMode: "both" } : void 0
|
|
10634
|
+
}
|
|
10635
|
+
),
|
|
10636
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("circle", { cx: point.x, cy: point.y, r: 16, fill: "transparent" }),
|
|
10637
|
+
showValues && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("text", { x: point.x, y: point.y - 12, textAnchor: "middle", fontSize: "10", fontWeight: "500", className: "text-foreground", fill: "currentColor", children: point.value })
|
|
10638
|
+
]
|
|
10639
|
+
},
|
|
10640
|
+
i
|
|
10641
|
+
)),
|
|
10642
|
+
hoveredPoint && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("g", { className: "pointer-events-none", children: [
|
|
10643
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10644
|
+
"line",
|
|
10645
|
+
{
|
|
10646
|
+
x1: hoveredPoint.x,
|
|
10647
|
+
y1: padding.top,
|
|
10648
|
+
x2: hoveredPoint.x,
|
|
10649
|
+
y2: padding.top + chartHeight,
|
|
10650
|
+
stroke: color,
|
|
10651
|
+
strokeWidth: 1,
|
|
10652
|
+
strokeDasharray: "4 4",
|
|
10653
|
+
opacity: 0.5
|
|
10654
|
+
}
|
|
10655
|
+
),
|
|
10656
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10657
|
+
"line",
|
|
10658
|
+
{
|
|
10659
|
+
x1: padding.left,
|
|
10660
|
+
y1: hoveredPoint.y,
|
|
10661
|
+
x2: padding.left + chartWidth,
|
|
10662
|
+
y2: hoveredPoint.y,
|
|
10663
|
+
stroke: color,
|
|
10664
|
+
strokeWidth: 1,
|
|
10665
|
+
strokeDasharray: "4 4",
|
|
10666
|
+
opacity: 0.5
|
|
10667
|
+
}
|
|
10668
|
+
)
|
|
10669
|
+
] }),
|
|
10670
|
+
showLabels && points.map((point, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("text", { x: point.x, y: height - 10, textAnchor: "middle", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: point.label }, i)),
|
|
10671
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("style", { children: `
|
|
10672
|
+
@keyframes drawLine {
|
|
10673
|
+
from { stroke-dashoffset: 1000; }
|
|
10674
|
+
to { stroke-dashoffset: 0; }
|
|
10675
|
+
}
|
|
10676
|
+
@keyframes scaleIn {
|
|
10677
|
+
from { transform: scale(0); opacity: 0; }
|
|
10678
|
+
to { transform: scale(1); opacity: 1; }
|
|
10679
|
+
}
|
|
10680
|
+
@keyframes fadeIn {
|
|
10681
|
+
from { opacity: 0; }
|
|
10682
|
+
to { opacity: 0.2; }
|
|
10683
|
+
}
|
|
10684
|
+
` })
|
|
10685
|
+
] }),
|
|
10686
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10687
|
+
ChartTooltip,
|
|
10688
|
+
{
|
|
10689
|
+
x: hoveredPoint?.x ?? 0,
|
|
10690
|
+
y: hoveredPoint?.y ?? 0,
|
|
10691
|
+
visible: !!hoveredPoint,
|
|
10692
|
+
label: hoveredPoint?.label,
|
|
10693
|
+
value: hoveredPoint?.value,
|
|
10694
|
+
color,
|
|
10695
|
+
containerRef: svgRef
|
|
10696
|
+
}
|
|
10697
|
+
)
|
|
10698
|
+
] });
|
|
10699
|
+
}
|
|
10700
|
+
|
|
10701
|
+
// ../../components/ui/BarChart.tsx
|
|
10702
|
+
var import_react24 = require("react");
|
|
10703
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
10704
|
+
function BarChart({
|
|
10705
|
+
data,
|
|
10706
|
+
width = 400,
|
|
10707
|
+
height = 200,
|
|
10708
|
+
color = "currentColor",
|
|
10709
|
+
showLabels = true,
|
|
10710
|
+
showValues = true,
|
|
10711
|
+
showGrid = true,
|
|
10712
|
+
horizontal = false,
|
|
10713
|
+
animated = true,
|
|
10714
|
+
barRadius = 4,
|
|
10715
|
+
barGap = 0.3,
|
|
10716
|
+
className = ""
|
|
10717
|
+
}) {
|
|
10718
|
+
const svgRef = (0, import_react24.useRef)(null);
|
|
10719
|
+
const padding = horizontal ? { top: 20, right: 40, bottom: 20, left: 80 } : { top: 20, right: 20, bottom: 40, left: 40 };
|
|
10720
|
+
const chartWidth = width - padding.left - padding.right;
|
|
10721
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
10722
|
+
const [hoveredBar, setHoveredBar] = (0, import_react24.useState)(null);
|
|
10723
|
+
const { maxValue, bars, gridLines } = (0, import_react24.useMemo)(() => {
|
|
10724
|
+
if (!data.length) return { maxValue: 0, bars: [], gridLines: [] };
|
|
10725
|
+
const max = Math.max(...data.map((d) => d.value));
|
|
10726
|
+
const barCount = data.length;
|
|
10727
|
+
const barsData = data.map((d, i) => {
|
|
10728
|
+
if (horizontal) {
|
|
10729
|
+
const barHeight = chartHeight / barCount * (1 - barGap);
|
|
10730
|
+
const gap = chartHeight / barCount * barGap;
|
|
10731
|
+
return {
|
|
10732
|
+
x: padding.left,
|
|
10733
|
+
y: padding.top + i * (barHeight + gap) + gap / 2,
|
|
10734
|
+
width: d.value / max * chartWidth,
|
|
10735
|
+
height: barHeight,
|
|
10736
|
+
...d
|
|
10737
|
+
};
|
|
10738
|
+
} else {
|
|
10739
|
+
const barWidth = chartWidth / barCount * (1 - barGap);
|
|
10740
|
+
const gap = chartWidth / barCount * barGap;
|
|
10741
|
+
return {
|
|
10742
|
+
x: padding.left + i * (barWidth + gap) + gap / 2,
|
|
10743
|
+
y: padding.top + chartHeight - d.value / max * chartHeight,
|
|
10744
|
+
width: barWidth,
|
|
10745
|
+
height: d.value / max * chartHeight,
|
|
10746
|
+
...d
|
|
10747
|
+
};
|
|
10748
|
+
}
|
|
10749
|
+
});
|
|
10750
|
+
const lines = [];
|
|
10751
|
+
const steps = 5;
|
|
10752
|
+
for (let i = 0; i <= steps; i++) {
|
|
10753
|
+
const value = i / steps * max;
|
|
10754
|
+
if (horizontal) {
|
|
10755
|
+
lines.push({
|
|
10756
|
+
x: padding.left + i / steps * chartWidth,
|
|
10757
|
+
y1: padding.top,
|
|
10758
|
+
y2: height - padding.bottom,
|
|
10759
|
+
value
|
|
10760
|
+
});
|
|
10761
|
+
} else {
|
|
10762
|
+
lines.push({
|
|
10763
|
+
y: padding.top + chartHeight - i / steps * chartHeight,
|
|
10764
|
+
x1: padding.left,
|
|
10765
|
+
x2: width - padding.right,
|
|
10766
|
+
value
|
|
10767
|
+
});
|
|
10768
|
+
}
|
|
10769
|
+
}
|
|
10770
|
+
return { maxValue: max, bars: barsData, gridLines: lines };
|
|
10771
|
+
}, [data, chartWidth, chartHeight, horizontal, barGap, padding, width, height]);
|
|
10772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
10773
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("svg", { ref: svgRef, width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
10774
|
+
showGrid && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("g", { children: horizontal ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
10775
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("line", { x1: line.x, y1: line.y1, x2: line.x, y2: line.y2, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10776
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("text", { x: line.x, y: height - 8, textAnchor: "middle", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
10777
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
10778
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("line", { x1: line.x1, y1: line.y, x2: line.x2, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10779
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
10780
|
+
] }) }, i)) }),
|
|
10781
|
+
bars.map((bar, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
10782
|
+
"g",
|
|
10783
|
+
{
|
|
10784
|
+
onMouseEnter: () => setHoveredBar({
|
|
10785
|
+
x: horizontal ? bar.x + bar.width : bar.x + bar.width / 2,
|
|
10786
|
+
y: horizontal ? bar.y + bar.height / 2 : bar.y,
|
|
10787
|
+
label: bar.label,
|
|
10788
|
+
value: bar.value,
|
|
10789
|
+
color: bar.color || color
|
|
10790
|
+
}),
|
|
10791
|
+
onMouseLeave: () => setHoveredBar(null),
|
|
10792
|
+
className: "cursor-pointer",
|
|
10793
|
+
children: [
|
|
10794
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
10795
|
+
"rect",
|
|
10796
|
+
{
|
|
10797
|
+
x: bar.x,
|
|
10798
|
+
y: horizontal ? bar.y : bar.y,
|
|
10799
|
+
width: animated && !horizontal ? 0 : bar.width,
|
|
10800
|
+
height: animated && horizontal ? bar.height : horizontal ? bar.height : 0,
|
|
10801
|
+
rx: barRadius,
|
|
10802
|
+
ry: barRadius,
|
|
10803
|
+
fill: bar.color || color,
|
|
10804
|
+
className: `transition-all duration-150 ${hoveredBar?.label === bar.label ? "opacity-80" : ""}`,
|
|
10805
|
+
style: animated ? {
|
|
10806
|
+
animation: horizontal ? `growWidth 0.5s ease-out ${i * 0.1}s forwards` : `growHeight 0.5s ease-out ${i * 0.1}s forwards`,
|
|
10807
|
+
...horizontal ? { width: 0 } : { height: 0, y: padding.top + chartHeight }
|
|
10808
|
+
} : void 0,
|
|
10809
|
+
children: [
|
|
10810
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10811
|
+
"animate",
|
|
10812
|
+
{
|
|
10813
|
+
attributeName: horizontal ? "width" : "height",
|
|
10814
|
+
from: "0",
|
|
10815
|
+
to: horizontal ? bar.width : bar.height,
|
|
10816
|
+
dur: "0.5s",
|
|
10817
|
+
begin: `${i * 0.1}s`,
|
|
10818
|
+
fill: "freeze"
|
|
10819
|
+
}
|
|
10820
|
+
),
|
|
10821
|
+
!horizontal && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("animate", { attributeName: "y", from: padding.top + chartHeight, to: bar.y, dur: "0.5s", begin: `${i * 0.1}s`, fill: "freeze" })
|
|
10822
|
+
]
|
|
10823
|
+
}
|
|
10824
|
+
),
|
|
10825
|
+
showValues && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10826
|
+
"text",
|
|
10827
|
+
{
|
|
10828
|
+
x: horizontal ? bar.x + bar.width + 8 : bar.x + bar.width / 2,
|
|
10829
|
+
y: horizontal ? bar.y + bar.height / 2 + 4 : bar.y - 8,
|
|
10830
|
+
textAnchor: horizontal ? "start" : "middle",
|
|
10831
|
+
fontSize: "11",
|
|
10832
|
+
fontWeight: "500",
|
|
10833
|
+
className: "text-foreground",
|
|
10834
|
+
fill: "currentColor",
|
|
10835
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
10836
|
+
children: bar.value
|
|
10837
|
+
}
|
|
10838
|
+
),
|
|
10839
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10840
|
+
"text",
|
|
10841
|
+
{
|
|
10842
|
+
x: horizontal ? padding.left - 8 : bar.x + bar.width / 2,
|
|
10843
|
+
y: horizontal ? bar.y + bar.height / 2 + 4 : height - 10,
|
|
10844
|
+
textAnchor: horizontal ? "end" : "middle",
|
|
10845
|
+
fontSize: "10",
|
|
10846
|
+
className: "text-muted-foreground",
|
|
10847
|
+
fill: "currentColor",
|
|
10848
|
+
children: bar.label
|
|
10849
|
+
}
|
|
10850
|
+
)
|
|
10851
|
+
]
|
|
10852
|
+
},
|
|
10853
|
+
i
|
|
10854
|
+
)),
|
|
10855
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("style", { children: `
|
|
10856
|
+
@keyframes growHeight {
|
|
10857
|
+
from { height: 0; }
|
|
10858
|
+
}
|
|
10859
|
+
@keyframes growWidth {
|
|
10860
|
+
from { width: 0; }
|
|
10861
|
+
}
|
|
10862
|
+
@keyframes fadeIn {
|
|
10863
|
+
from { opacity: 0; }
|
|
10864
|
+
to { opacity: 1; }
|
|
10865
|
+
}
|
|
10866
|
+
` })
|
|
10867
|
+
] }),
|
|
10868
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10869
|
+
ChartTooltip,
|
|
10870
|
+
{
|
|
10871
|
+
x: hoveredBar?.x ?? 0,
|
|
10872
|
+
y: hoveredBar?.y ?? 0,
|
|
10873
|
+
visible: !!hoveredBar,
|
|
10874
|
+
label: hoveredBar?.label,
|
|
10875
|
+
value: hoveredBar?.value,
|
|
10876
|
+
color: hoveredBar?.color,
|
|
10877
|
+
containerRef: svgRef
|
|
10878
|
+
}
|
|
10879
|
+
)
|
|
10880
|
+
] });
|
|
10881
|
+
}
|
|
10882
|
+
|
|
10883
|
+
// ../../components/ui/PieChart.tsx
|
|
10884
|
+
var import_react25 = require("react");
|
|
10885
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
10886
|
+
function PieChart({
|
|
10887
|
+
data,
|
|
10888
|
+
size = 200,
|
|
10889
|
+
donut = false,
|
|
10890
|
+
donutWidth = 40,
|
|
10891
|
+
showLabels = true,
|
|
10892
|
+
showLegend = true,
|
|
10893
|
+
showPercentage = true,
|
|
10894
|
+
animated = true,
|
|
10895
|
+
startAngle = -90,
|
|
10896
|
+
className = ""
|
|
10897
|
+
}) {
|
|
10898
|
+
const containerRef = (0, import_react25.useRef)(null);
|
|
10899
|
+
const center = size / 2;
|
|
10900
|
+
const radius = size / 2 - 10;
|
|
10901
|
+
const innerRadius = donut ? radius - donutWidth : 0;
|
|
10902
|
+
const { segments, total } = (0, import_react25.useMemo)(() => {
|
|
10903
|
+
if (!data.length) return { segments: [], total: 0 };
|
|
10904
|
+
const sum = data.reduce((acc, d) => acc + d.value, 0);
|
|
10905
|
+
let currentAngle = startAngle;
|
|
10906
|
+
const segs = data.map((d, i) => {
|
|
10907
|
+
const percentage = d.value / sum;
|
|
10908
|
+
const angle = percentage * 360;
|
|
10909
|
+
const startRad = currentAngle * Math.PI / 180;
|
|
10910
|
+
const endRad = (currentAngle + angle) * Math.PI / 180;
|
|
10911
|
+
const midRad = (currentAngle + angle / 2) * Math.PI / 180;
|
|
10912
|
+
const largeArc = angle > 180 ? 1 : 0;
|
|
10913
|
+
const x1 = center + radius * Math.cos(startRad);
|
|
10914
|
+
const y1 = center + radius * Math.sin(startRad);
|
|
10915
|
+
const x2 = center + radius * Math.cos(endRad);
|
|
10916
|
+
const y2 = center + radius * Math.sin(endRad);
|
|
10917
|
+
const x3 = center + innerRadius * Math.cos(endRad);
|
|
10918
|
+
const y3 = center + innerRadius * Math.sin(endRad);
|
|
10919
|
+
const x4 = center + innerRadius * Math.cos(startRad);
|
|
10920
|
+
const y4 = center + innerRadius * Math.sin(startRad);
|
|
10921
|
+
const labelRadius = radius + 20;
|
|
10922
|
+
const labelX = center + labelRadius * Math.cos(midRad);
|
|
10923
|
+
const labelY = center + labelRadius * Math.sin(midRad);
|
|
10924
|
+
let path;
|
|
10925
|
+
if (donut) {
|
|
10926
|
+
path = [
|
|
10927
|
+
`M ${x1} ${y1}`,
|
|
10928
|
+
`A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`,
|
|
10929
|
+
`L ${x3} ${y3}`,
|
|
10930
|
+
`A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${x4} ${y4}`,
|
|
10931
|
+
"Z"
|
|
10932
|
+
].join(" ");
|
|
10933
|
+
} else {
|
|
10934
|
+
path = [`M ${center} ${center}`, `L ${x1} ${y1}`, `A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`, "Z"].join(" ");
|
|
10935
|
+
}
|
|
10936
|
+
currentAngle += angle;
|
|
10937
|
+
return {
|
|
10938
|
+
path,
|
|
10939
|
+
...d,
|
|
10940
|
+
percentage,
|
|
10941
|
+
labelX,
|
|
10942
|
+
labelY,
|
|
10943
|
+
midAngle: currentAngle - angle / 2
|
|
10944
|
+
};
|
|
10945
|
+
});
|
|
10946
|
+
return { segments: segs, total: sum };
|
|
10947
|
+
}, [data, center, radius, innerRadius, donut, startAngle]);
|
|
10948
|
+
const [hoveredSegment, setHoveredSegment] = (0, import_react25.useState)(null);
|
|
10949
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { ref: containerRef, className: `relative flex items-center gap-6 ${className}`, children: [
|
|
10950
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("svg", { width: size + 40, height: size + 40, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
10951
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("g", { transform: `translate(20, 20)`, children: [
|
|
10952
|
+
segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
10953
|
+
"g",
|
|
10954
|
+
{
|
|
10955
|
+
onMouseEnter: () => setHoveredSegment({
|
|
10956
|
+
x: seg.labelX + 20,
|
|
10957
|
+
y: seg.labelY + 20,
|
|
10958
|
+
label: seg.label,
|
|
10959
|
+
value: seg.value,
|
|
10960
|
+
percentage: seg.percentage,
|
|
10961
|
+
color: seg.color
|
|
10962
|
+
}),
|
|
10963
|
+
onMouseLeave: () => setHoveredSegment(null),
|
|
10964
|
+
children: [
|
|
10965
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10966
|
+
"path",
|
|
10967
|
+
{
|
|
10968
|
+
d: seg.path,
|
|
10969
|
+
fill: seg.color,
|
|
10970
|
+
className: `transition-all duration-150 cursor-pointer ${hoveredSegment?.label === seg.label ? "opacity-80" : ""}`,
|
|
10971
|
+
style: {
|
|
10972
|
+
transformOrigin: `${center}px ${center}px`,
|
|
10973
|
+
transform: hoveredSegment?.label === seg.label ? "scale(1.05)" : "scale(1)",
|
|
10974
|
+
...animated ? {
|
|
10975
|
+
opacity: hoveredSegment?.label === seg.label ? 0.8 : 0,
|
|
10976
|
+
animation: `pieSlice 0.5s ease-out ${i * 0.1}s forwards`
|
|
10977
|
+
} : void 0
|
|
10978
|
+
}
|
|
10979
|
+
}
|
|
10980
|
+
),
|
|
10981
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10982
|
+
"text",
|
|
10983
|
+
{
|
|
10984
|
+
x: seg.labelX,
|
|
10985
|
+
y: seg.labelY,
|
|
10986
|
+
textAnchor: seg.labelX > center ? "start" : "end",
|
|
10987
|
+
fontSize: "10",
|
|
10988
|
+
className: "text-foreground",
|
|
10989
|
+
fill: "currentColor",
|
|
10990
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
10991
|
+
children: showPercentage ? `${(seg.percentage * 100).toFixed(0)}%` : seg.value
|
|
10992
|
+
}
|
|
10993
|
+
)
|
|
10994
|
+
]
|
|
10995
|
+
},
|
|
10996
|
+
i
|
|
10997
|
+
)),
|
|
10998
|
+
donut && /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("g", { children: [
|
|
10999
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("text", { x: center, y: center - 5, textAnchor: "middle", fontSize: "12", className: "text-muted-foreground", fill: "currentColor", children: "Total" }),
|
|
11000
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("text", { x: center, y: center + 15, textAnchor: "middle", fontSize: "18", fontWeight: "600", className: "text-foreground", fill: "currentColor", children: total })
|
|
11001
|
+
] })
|
|
11002
|
+
] }),
|
|
11003
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("style", { children: `
|
|
11004
|
+
@keyframes pieSlice {
|
|
11005
|
+
from {
|
|
11006
|
+
opacity: 0;
|
|
11007
|
+
transform: scale(0);
|
|
11008
|
+
}
|
|
11009
|
+
to {
|
|
11010
|
+
opacity: 1;
|
|
11011
|
+
transform: scale(1);
|
|
11012
|
+
}
|
|
11013
|
+
}
|
|
11014
|
+
@keyframes fadeIn {
|
|
11015
|
+
from { opacity: 0; }
|
|
11016
|
+
to { opacity: 1; }
|
|
11017
|
+
}
|
|
11018
|
+
` })
|
|
11019
|
+
] }),
|
|
11020
|
+
showLegend && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex flex-col gap-2", children: segments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
11021
|
+
"div",
|
|
11022
|
+
{
|
|
11023
|
+
className: "flex items-center gap-2 text-sm",
|
|
11024
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
11025
|
+
children: [
|
|
11026
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "w-3 h-3 rounded-sm shrink-0", style: { backgroundColor: seg.color } }),
|
|
11027
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-muted-foreground", children: seg.label }),
|
|
11028
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-foreground font-medium ml-auto", children: showPercentage ? `${(seg.percentage * 100).toFixed(0)}%` : seg.value })
|
|
11029
|
+
]
|
|
11030
|
+
},
|
|
11031
|
+
i
|
|
11032
|
+
)) }),
|
|
11033
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
11034
|
+
ChartTooltip,
|
|
11035
|
+
{
|
|
11036
|
+
x: hoveredSegment?.x ?? center,
|
|
11037
|
+
y: hoveredSegment?.y ?? center,
|
|
11038
|
+
visible: !!hoveredSegment,
|
|
11039
|
+
label: hoveredSegment?.label,
|
|
11040
|
+
value: `${hoveredSegment?.value} (${((hoveredSegment?.percentage ?? 0) * 100).toFixed(1)}%)`,
|
|
11041
|
+
color: hoveredSegment?.color,
|
|
11042
|
+
containerRef
|
|
11043
|
+
}
|
|
11044
|
+
)
|
|
11045
|
+
] });
|
|
11046
|
+
}
|
|
11047
|
+
|
|
11048
|
+
// ../../components/ui/AreaChart.tsx
|
|
11049
|
+
var import_react26 = require("react");
|
|
11050
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
11051
|
+
function getCatmullRomSpline(points) {
|
|
11052
|
+
if (points.length < 2) return "";
|
|
11053
|
+
if (points.length === 2) {
|
|
11054
|
+
return `M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y}`;
|
|
11055
|
+
}
|
|
11056
|
+
let path = `M ${points[0].x} ${points[0].y}`;
|
|
11057
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
11058
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
11059
|
+
const p1 = points[i];
|
|
11060
|
+
const p2 = points[i + 1];
|
|
11061
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
11062
|
+
const tension = 0.5;
|
|
11063
|
+
const cp1x = p1.x + (p2.x - p0.x) * tension / 6;
|
|
11064
|
+
const cp1y = p1.y + (p2.y - p0.y) * tension / 6;
|
|
11065
|
+
const cp2x = p2.x - (p3.x - p1.x) * tension / 6;
|
|
11066
|
+
const cp2y = p2.y - (p3.y - p1.y) * tension / 6;
|
|
11067
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
11068
|
+
}
|
|
11069
|
+
return path;
|
|
11070
|
+
}
|
|
11071
|
+
function AreaChart({
|
|
11072
|
+
series,
|
|
11073
|
+
width = 400,
|
|
11074
|
+
height = 200,
|
|
11075
|
+
showDots = true,
|
|
11076
|
+
showGrid = true,
|
|
11077
|
+
showLabels = true,
|
|
11078
|
+
showLegend = true,
|
|
11079
|
+
animated = true,
|
|
11080
|
+
stacked = false,
|
|
11081
|
+
curved = true,
|
|
11082
|
+
className = ""
|
|
11083
|
+
}) {
|
|
11084
|
+
const containerRef = (0, import_react26.useRef)(null);
|
|
11085
|
+
const padding = { top: 20, right: 20, bottom: 40, left: 50 };
|
|
11086
|
+
const chartWidth = width - padding.left - padding.right;
|
|
11087
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
11088
|
+
const [hoveredPoint, setHoveredPoint] = (0, import_react26.useState)(null);
|
|
11089
|
+
const { processedSeries, gridLines, maxValue, labels } = (0, import_react26.useMemo)(() => {
|
|
11090
|
+
if (!series.length || !series[0]?.data?.length) {
|
|
11091
|
+
return { processedSeries: [], gridLines: [], maxValue: 0, labels: [] };
|
|
11092
|
+
}
|
|
11093
|
+
const allLabels = series[0].data.map((d) => d.label);
|
|
11094
|
+
const dataLength = series[0].data.length;
|
|
11095
|
+
let max = 0;
|
|
11096
|
+
if (stacked) {
|
|
11097
|
+
for (let i = 0; i < dataLength; i++) {
|
|
11098
|
+
const stackedValue = series.reduce((sum, s) => sum + (s.data[i]?.value || 0), 0);
|
|
11099
|
+
max = Math.max(max, stackedValue);
|
|
11100
|
+
}
|
|
11101
|
+
} else {
|
|
11102
|
+
max = Math.max(...series.flatMap((s) => s.data.map((d) => d.value)));
|
|
11103
|
+
}
|
|
11104
|
+
const processed = series.map((s, seriesIndex) => {
|
|
11105
|
+
const points = s.data.map((d, i) => {
|
|
11106
|
+
const x = padding.left + i / (dataLength - 1) * chartWidth;
|
|
11107
|
+
let y;
|
|
11108
|
+
if (stacked && seriesIndex > 0) {
|
|
11109
|
+
const stackedBase = series.slice(0, seriesIndex).reduce((sum, prevS) => sum + (prevS.data[i]?.value || 0), 0);
|
|
11110
|
+
const stackedValue = stackedBase + d.value;
|
|
11111
|
+
y = padding.top + chartHeight - stackedValue / max * chartHeight;
|
|
11112
|
+
} else {
|
|
11113
|
+
y = padding.top + chartHeight - d.value / max * chartHeight;
|
|
11114
|
+
}
|
|
11115
|
+
return { x, y, value: d.value, label: d.label };
|
|
11116
|
+
});
|
|
11117
|
+
const linePath = curved ? getCatmullRomSpline(points) : `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")}`;
|
|
11118
|
+
let areaPath;
|
|
11119
|
+
if (stacked && seriesIndex > 0) {
|
|
11120
|
+
const prevSeriesPoints = series.slice(0, seriesIndex).reduce((acc, prevS) => {
|
|
11121
|
+
return prevS.data.map((d, i) => {
|
|
11122
|
+
const prevVal = acc[i] || 0;
|
|
11123
|
+
return prevVal + d.value;
|
|
11124
|
+
});
|
|
11125
|
+
}, []).map((val, i) => ({
|
|
11126
|
+
x: padding.left + i / (dataLength - 1) * chartWidth,
|
|
11127
|
+
y: padding.top + chartHeight - val / max * chartHeight
|
|
11128
|
+
}));
|
|
11129
|
+
const reversedPrevPoints = [...prevSeriesPoints].reverse();
|
|
11130
|
+
areaPath = `${linePath} L ${reversedPrevPoints.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`;
|
|
11131
|
+
} else {
|
|
11132
|
+
areaPath = `${linePath} L ${padding.left + chartWidth} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
11133
|
+
}
|
|
11134
|
+
return {
|
|
11135
|
+
...s,
|
|
11136
|
+
points,
|
|
11137
|
+
linePath,
|
|
11138
|
+
areaPath,
|
|
11139
|
+
lineLength: points.reduce((acc, p, i) => {
|
|
11140
|
+
if (i === 0) return 0;
|
|
11141
|
+
const prev = points[i - 1];
|
|
11142
|
+
return acc + Math.sqrt(Math.pow(p.x - prev.x, 2) + Math.pow(p.y - prev.y, 2));
|
|
11143
|
+
}, 0)
|
|
11144
|
+
};
|
|
11145
|
+
});
|
|
11146
|
+
const lines = [];
|
|
11147
|
+
const steps = 5;
|
|
11148
|
+
for (let i = 0; i <= steps; i++) {
|
|
11149
|
+
const value = i / steps * max;
|
|
11150
|
+
lines.push({
|
|
11151
|
+
y: padding.top + chartHeight - i / steps * chartHeight,
|
|
11152
|
+
value
|
|
11153
|
+
});
|
|
11154
|
+
}
|
|
11155
|
+
return { processedSeries: processed, gridLines: lines, maxValue: max, labels: allLabels };
|
|
11156
|
+
}, [series, chartWidth, chartHeight, padding, stacked, curved]);
|
|
11157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { ref: containerRef, className: `relative flex flex-col gap-4 ${className}`, children: [
|
|
11158
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("svg", { width, height, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
11159
|
+
showGrid && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("g", { children: [
|
|
11160
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("line", { x1: padding.left, y1: line.y, x2: width - padding.right, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
11161
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
11162
|
+
] }, i)) }),
|
|
11163
|
+
[...processedSeries].reverse().map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
11164
|
+
"path",
|
|
11165
|
+
{
|
|
11166
|
+
d: s.areaPath,
|
|
11167
|
+
fill: s.color,
|
|
11168
|
+
fillOpacity: s.fillOpacity ?? 0.3,
|
|
11169
|
+
className: "transition-all duration-300",
|
|
11170
|
+
style: animated ? {
|
|
11171
|
+
opacity: 0,
|
|
11172
|
+
animation: `fadeIn 0.5s ease-out ${i * 0.1}s forwards`
|
|
11173
|
+
} : void 0
|
|
11174
|
+
},
|
|
11175
|
+
`area-${i}`
|
|
11176
|
+
)),
|
|
11177
|
+
processedSeries.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
11178
|
+
"path",
|
|
11179
|
+
{
|
|
11180
|
+
d: s.linePath,
|
|
11181
|
+
fill: "none",
|
|
11182
|
+
stroke: s.color,
|
|
11183
|
+
strokeWidth: 2,
|
|
11184
|
+
strokeLinecap: "round",
|
|
11185
|
+
strokeLinejoin: "round",
|
|
11186
|
+
style: animated ? {
|
|
11187
|
+
strokeDasharray: s.lineLength,
|
|
11188
|
+
strokeDashoffset: s.lineLength,
|
|
11189
|
+
animation: `drawLine 1s ease-out ${i * 0.1}s forwards`
|
|
11190
|
+
} : void 0
|
|
11191
|
+
},
|
|
11192
|
+
`line-${i}`
|
|
11193
|
+
)),
|
|
11194
|
+
showDots && processedSeries.map(
|
|
11195
|
+
(s, seriesIdx) => s.points.map((point, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
11196
|
+
"g",
|
|
11197
|
+
{
|
|
11198
|
+
onMouseEnter: () => {
|
|
11199
|
+
const items = processedSeries.map((ps) => ({
|
|
11200
|
+
label: ps.name,
|
|
11201
|
+
value: ps.points[i]?.value ?? 0,
|
|
11202
|
+
color: ps.color
|
|
11203
|
+
}));
|
|
11204
|
+
setHoveredPoint({
|
|
11205
|
+
x: point.x,
|
|
11206
|
+
y: point.y,
|
|
11207
|
+
label: point.label,
|
|
11208
|
+
items
|
|
11209
|
+
});
|
|
11210
|
+
},
|
|
11211
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
11212
|
+
className: "cursor-pointer",
|
|
11213
|
+
children: [
|
|
11214
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
11215
|
+
"circle",
|
|
11216
|
+
{
|
|
11217
|
+
cx: point.x,
|
|
11218
|
+
cy: point.y,
|
|
11219
|
+
r: hoveredPoint?.x === point.x ? 6 : 4,
|
|
11220
|
+
fill: s.color,
|
|
11221
|
+
className: "transition-all duration-150",
|
|
11222
|
+
style: animated ? {
|
|
11223
|
+
transform: "scale(0)",
|
|
11224
|
+
opacity: 0,
|
|
11225
|
+
transformOrigin: `${point.x}px ${point.y}px`,
|
|
11226
|
+
animation: `dotPop 0.3s ease-out ${seriesIdx * 0.1 + i * 0.05 + 0.5}s forwards`
|
|
11227
|
+
} : void 0
|
|
11228
|
+
}
|
|
11229
|
+
),
|
|
11230
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("circle", { cx: point.x, cy: point.y, r: 12, fill: "transparent" })
|
|
11231
|
+
]
|
|
11232
|
+
},
|
|
11233
|
+
`dot-${seriesIdx}-${i}`
|
|
11234
|
+
))
|
|
11235
|
+
),
|
|
11236
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "text-muted-foreground", children: labels.map((label, i) => {
|
|
11237
|
+
const x = padding.left + i / (labels.length - 1) * chartWidth;
|
|
11238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("text", { x, y: height - 10, textAnchor: "middle", fontSize: "10", fill: "currentColor", children: label }, i);
|
|
11239
|
+
}) }),
|
|
11240
|
+
hoveredPoint && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
11241
|
+
"line",
|
|
11242
|
+
{
|
|
11243
|
+
x1: hoveredPoint.x,
|
|
11244
|
+
y1: padding.top,
|
|
11245
|
+
x2: hoveredPoint.x,
|
|
11246
|
+
y2: padding.top + chartHeight,
|
|
11247
|
+
stroke: "currentColor",
|
|
11248
|
+
strokeWidth: 1,
|
|
11249
|
+
strokeDasharray: "4 4",
|
|
11250
|
+
opacity: 0.3,
|
|
11251
|
+
className: "text-foreground"
|
|
11252
|
+
}
|
|
11253
|
+
) }),
|
|
11254
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("style", { children: `
|
|
11255
|
+
@keyframes drawLine {
|
|
11256
|
+
to {
|
|
11257
|
+
stroke-dashoffset: 0;
|
|
11258
|
+
}
|
|
11259
|
+
}
|
|
11260
|
+
@keyframes fadeIn {
|
|
11261
|
+
from { opacity: 0; }
|
|
11262
|
+
to { opacity: 1; }
|
|
11263
|
+
}
|
|
11264
|
+
@keyframes dotPop {
|
|
11265
|
+
from {
|
|
11266
|
+
transform: scale(0);
|
|
11267
|
+
opacity: 0;
|
|
11268
|
+
}
|
|
11269
|
+
to {
|
|
11270
|
+
transform: scale(1);
|
|
11271
|
+
opacity: 1;
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
` })
|
|
11275
|
+
] }),
|
|
11276
|
+
showLegend && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex items-center justify-center gap-6", children: series.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
11277
|
+
"div",
|
|
11278
|
+
{
|
|
11279
|
+
className: "flex items-center gap-2 text-sm",
|
|
11280
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.5}s forwards` } : void 0,
|
|
11281
|
+
children: [
|
|
11282
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-3 h-3 rounded-sm", style: { backgroundColor: s.color } }),
|
|
11283
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-muted-foreground", children: s.name })
|
|
11284
|
+
]
|
|
11285
|
+
},
|
|
11286
|
+
i
|
|
11287
|
+
)) }),
|
|
11288
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
11289
|
+
ChartTooltip,
|
|
11290
|
+
{
|
|
11291
|
+
x: hoveredPoint?.x ?? 0,
|
|
11292
|
+
y: hoveredPoint?.y ?? 0,
|
|
11293
|
+
visible: !!hoveredPoint,
|
|
11294
|
+
label: hoveredPoint?.label,
|
|
11295
|
+
items: hoveredPoint?.items,
|
|
11296
|
+
containerRef
|
|
11297
|
+
}
|
|
11298
|
+
)
|
|
11299
|
+
] });
|
|
11300
|
+
}
|
|
11301
|
+
|
|
11302
|
+
// ../../components/ui/Sparkline.tsx
|
|
11303
|
+
var import_react27 = require("react");
|
|
11304
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
11305
|
+
function getCatmullRomSpline2(points) {
|
|
11306
|
+
if (points.length < 2) return "";
|
|
11307
|
+
if (points.length === 2) {
|
|
11308
|
+
return `M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y}`;
|
|
11309
|
+
}
|
|
11310
|
+
let path = `M ${points[0].x} ${points[0].y}`;
|
|
11311
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
11312
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
11313
|
+
const p1 = points[i];
|
|
11314
|
+
const p2 = points[i + 1];
|
|
11315
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
11316
|
+
const tension = 0.5;
|
|
11317
|
+
const cp1x = p1.x + (p2.x - p0.x) * tension / 6;
|
|
11318
|
+
const cp1y = p1.y + (p2.y - p0.y) * tension / 6;
|
|
11319
|
+
const cp2x = p2.x - (p3.x - p1.x) * tension / 6;
|
|
11320
|
+
const cp2y = p2.y - (p3.y - p1.y) * tension / 6;
|
|
11321
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
11322
|
+
}
|
|
11323
|
+
return path;
|
|
11324
|
+
}
|
|
11325
|
+
function Sparkline({
|
|
11326
|
+
data,
|
|
11327
|
+
width = 100,
|
|
11328
|
+
height = 30,
|
|
11329
|
+
color = "currentColor",
|
|
11330
|
+
fillColor,
|
|
11331
|
+
showFill = true,
|
|
11332
|
+
showDots = false,
|
|
11333
|
+
showEndDot = true,
|
|
11334
|
+
animated = true,
|
|
11335
|
+
curved = true,
|
|
11336
|
+
strokeWidth = 2,
|
|
11337
|
+
className = ""
|
|
11338
|
+
}) {
|
|
11339
|
+
const padding = 4;
|
|
11340
|
+
const chartWidth = width - padding * 2;
|
|
11341
|
+
const chartHeight = height - padding * 2;
|
|
11342
|
+
const { points, linePath, areaPath, lineLength, trend } = (0, import_react27.useMemo)(() => {
|
|
11343
|
+
const normalizedData = data.map((d) => typeof d === "number" ? d : d.value);
|
|
11344
|
+
if (!normalizedData.length) {
|
|
11345
|
+
return { points: [], linePath: "", areaPath: "", lineLength: 0, trend: 0 };
|
|
11346
|
+
}
|
|
11347
|
+
const min = Math.min(...normalizedData);
|
|
11348
|
+
const max = Math.max(...normalizedData);
|
|
11349
|
+
const range = max - min || 1;
|
|
11350
|
+
const pts = normalizedData.map((value, i) => ({
|
|
11351
|
+
x: padding + i / (normalizedData.length - 1) * chartWidth,
|
|
11352
|
+
y: padding + chartHeight - (value - min) / range * chartHeight,
|
|
11353
|
+
value
|
|
11354
|
+
}));
|
|
11355
|
+
const line = curved ? getCatmullRomSpline2(pts) : `M ${pts.map((p) => `${p.x} ${p.y}`).join(" L ")}`;
|
|
11356
|
+
const area = `${line} L ${padding + chartWidth} ${padding + chartHeight} L ${padding} ${padding + chartHeight} Z`;
|
|
11357
|
+
const length = pts.reduce((acc, p, i) => {
|
|
11358
|
+
if (i === 0) return 0;
|
|
11359
|
+
const prev = pts[i - 1];
|
|
11360
|
+
return acc + Math.sqrt(Math.pow(p.x - prev.x, 2) + Math.pow(p.y - prev.y, 2));
|
|
11361
|
+
}, 0);
|
|
11362
|
+
const trendValue = normalizedData[normalizedData.length - 1] - normalizedData[0];
|
|
11363
|
+
return { points: pts, linePath: line, areaPath: area, lineLength: length, trend: trendValue };
|
|
11364
|
+
}, [data, chartWidth, chartHeight, padding, curved]);
|
|
11365
|
+
const effectiveFillColor = fillColor || color;
|
|
11366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("svg", { width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
11367
|
+
showFill && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11368
|
+
"path",
|
|
11369
|
+
{
|
|
11370
|
+
d: areaPath,
|
|
11371
|
+
fill: effectiveFillColor,
|
|
11372
|
+
fillOpacity: 0.1,
|
|
11373
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.3s forwards" } : void 0
|
|
11374
|
+
}
|
|
11375
|
+
),
|
|
11376
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11377
|
+
"path",
|
|
11378
|
+
{
|
|
11379
|
+
d: linePath,
|
|
11380
|
+
fill: "none",
|
|
11381
|
+
stroke: color,
|
|
11382
|
+
strokeWidth,
|
|
11383
|
+
strokeLinecap: "round",
|
|
11384
|
+
strokeLinejoin: "round",
|
|
11385
|
+
style: animated ? {
|
|
11386
|
+
strokeDasharray: lineLength,
|
|
11387
|
+
strokeDashoffset: lineLength,
|
|
11388
|
+
animation: "drawLine 0.8s ease-out forwards"
|
|
11389
|
+
} : void 0
|
|
11390
|
+
}
|
|
11391
|
+
),
|
|
11392
|
+
showDots && points.map((point, i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11393
|
+
"circle",
|
|
11394
|
+
{
|
|
11395
|
+
cx: point.x,
|
|
11396
|
+
cy: point.y,
|
|
11397
|
+
r: 2,
|
|
11398
|
+
fill: color,
|
|
11399
|
+
style: animated ? {
|
|
11400
|
+
opacity: 0,
|
|
11401
|
+
animation: `fadeIn 0.3s ease-out ${i * 0.05 + 0.5}s forwards`
|
|
11402
|
+
} : void 0
|
|
11403
|
+
},
|
|
11404
|
+
i
|
|
11405
|
+
)),
|
|
11406
|
+
showEndDot && !showDots && points.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11407
|
+
"circle",
|
|
11408
|
+
{
|
|
11409
|
+
cx: points[points.length - 1].x,
|
|
11410
|
+
cy: points[points.length - 1].y,
|
|
11411
|
+
r: 3,
|
|
11412
|
+
fill: color,
|
|
11413
|
+
style: animated ? {
|
|
11414
|
+
opacity: 0,
|
|
11415
|
+
transform: "scale(0)",
|
|
11416
|
+
transformOrigin: `${points[points.length - 1].x}px ${points[points.length - 1].y}px`,
|
|
11417
|
+
animation: "dotPop 0.3s ease-out 0.6s forwards"
|
|
11418
|
+
} : void 0
|
|
11419
|
+
}
|
|
11420
|
+
),
|
|
11421
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("style", { children: `
|
|
11422
|
+
@keyframes drawLine {
|
|
11423
|
+
to {
|
|
11424
|
+
stroke-dashoffset: 0;
|
|
11425
|
+
}
|
|
11426
|
+
}
|
|
11427
|
+
@keyframes fadeIn {
|
|
11428
|
+
from { opacity: 0; }
|
|
11429
|
+
to { opacity: 1; }
|
|
11430
|
+
}
|
|
11431
|
+
@keyframes dotPop {
|
|
11432
|
+
from {
|
|
11433
|
+
transform: scale(0);
|
|
11434
|
+
opacity: 0;
|
|
11435
|
+
}
|
|
11436
|
+
to {
|
|
11437
|
+
transform: scale(1);
|
|
11438
|
+
opacity: 1;
|
|
11439
|
+
}
|
|
11440
|
+
}
|
|
11441
|
+
` })
|
|
11442
|
+
] });
|
|
11443
|
+
}
|
|
11444
|
+
|
|
11445
|
+
// ../../components/ui/RadarChart.tsx
|
|
11446
|
+
var import_react28 = require("react");
|
|
11447
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
11448
|
+
function RadarChart({
|
|
11449
|
+
series,
|
|
11450
|
+
size = 300,
|
|
11451
|
+
levels = 5,
|
|
11452
|
+
showLabels = true,
|
|
11453
|
+
showLegend = true,
|
|
11454
|
+
showValues = false,
|
|
11455
|
+
animated = true,
|
|
11456
|
+
className = ""
|
|
11457
|
+
}) {
|
|
11458
|
+
const containerRef = (0, import_react28.useRef)(null);
|
|
11459
|
+
const center = size / 2;
|
|
11460
|
+
const radius = size / 2 - 40;
|
|
11461
|
+
const [hoveredPoint, setHoveredPoint] = (0, import_react28.useState)(null);
|
|
11462
|
+
const { axes, processedSeries, levelPaths } = (0, import_react28.useMemo)(() => {
|
|
11463
|
+
if (!series.length || !series[0]?.data?.length) {
|
|
11464
|
+
return { axes: [], processedSeries: [], levelPaths: [] };
|
|
11465
|
+
}
|
|
11466
|
+
const axisLabels = series[0].data.map((d) => d.axis);
|
|
11467
|
+
const axisCount = axisLabels.length;
|
|
11468
|
+
const angleStep = 2 * Math.PI / axisCount;
|
|
11469
|
+
const maxValue = Math.max(...series.flatMap((s) => s.data.map((d) => d.value)));
|
|
11470
|
+
const axesData = axisLabels.map((label, i) => {
|
|
11471
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11472
|
+
const x = center + radius * Math.cos(angle);
|
|
11473
|
+
const y = center + radius * Math.sin(angle);
|
|
11474
|
+
const labelX = center + (radius + 20) * Math.cos(angle);
|
|
11475
|
+
const labelY = center + (radius + 20) * Math.sin(angle);
|
|
11476
|
+
return { label, x, y, labelX, labelY, angle };
|
|
11477
|
+
});
|
|
11478
|
+
const levelsData = [];
|
|
11479
|
+
for (let l = 1; l <= levels; l++) {
|
|
11480
|
+
const levelRadius = l / levels * radius;
|
|
11481
|
+
const points = axisLabels.map((_, i) => {
|
|
11482
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11483
|
+
return {
|
|
11484
|
+
x: center + levelRadius * Math.cos(angle),
|
|
11485
|
+
y: center + levelRadius * Math.sin(angle)
|
|
11486
|
+
};
|
|
11487
|
+
});
|
|
11488
|
+
levelsData.push({
|
|
11489
|
+
path: `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`,
|
|
11490
|
+
level: l,
|
|
11491
|
+
value: l / levels * maxValue
|
|
11492
|
+
});
|
|
11493
|
+
}
|
|
11494
|
+
const processed = series.map((s) => {
|
|
11495
|
+
const points = s.data.map((d, i) => {
|
|
11496
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11497
|
+
const r = d.value / maxValue * radius;
|
|
11498
|
+
return {
|
|
11499
|
+
x: center + r * Math.cos(angle),
|
|
11500
|
+
y: center + r * Math.sin(angle),
|
|
11501
|
+
value: d.value
|
|
11502
|
+
};
|
|
11503
|
+
});
|
|
11504
|
+
return {
|
|
11505
|
+
...s,
|
|
11506
|
+
points,
|
|
11507
|
+
path: `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`
|
|
11508
|
+
};
|
|
11509
|
+
});
|
|
11510
|
+
return { axes: axesData, processedSeries: processed, levelPaths: levelsData };
|
|
11511
|
+
}, [series, center, radius, levels]);
|
|
11512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { ref: containerRef, className: `relative flex flex-col gap-4 ${className}`, children: [
|
|
11513
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("svg", { width: size, height: size, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
11514
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("g", { className: "text-muted-foreground/20", children: levelPaths.map((level, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: level.path, fill: "none", stroke: "currentColor", strokeWidth: 1 }, i)) }),
|
|
11515
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("g", { className: "text-muted-foreground/30", children: axes.map((axis, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("line", { x1: center, y1: center, x2: axis.x, y2: axis.y, stroke: "currentColor", strokeWidth: 1 }, i)) }),
|
|
11516
|
+
processedSeries.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("g", { children: [
|
|
11517
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
11518
|
+
"path",
|
|
11519
|
+
{
|
|
11520
|
+
d: s.path,
|
|
11521
|
+
fill: s.color,
|
|
11522
|
+
fillOpacity: s.fillOpacity ?? 0.2,
|
|
11523
|
+
stroke: s.color,
|
|
11524
|
+
strokeWidth: 2,
|
|
11525
|
+
strokeLinejoin: "round",
|
|
11526
|
+
className: "transition-all duration-300",
|
|
11527
|
+
style: animated ? {
|
|
11528
|
+
opacity: 0,
|
|
11529
|
+
transform: "scale(0)",
|
|
11530
|
+
transformOrigin: `${center}px ${center}px`,
|
|
11531
|
+
animation: `radarPop 0.5s ease-out ${i * 0.15}s forwards`
|
|
11532
|
+
} : void 0
|
|
11533
|
+
}
|
|
11534
|
+
),
|
|
11535
|
+
s.points.map((point, j) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
|
|
11536
|
+
"g",
|
|
11537
|
+
{
|
|
11538
|
+
onMouseEnter: () => {
|
|
11539
|
+
const items = processedSeries.map((ps) => ({
|
|
11540
|
+
label: ps.name,
|
|
11541
|
+
value: ps.points[j]?.value ?? 0,
|
|
11542
|
+
color: ps.color
|
|
11543
|
+
}));
|
|
11544
|
+
setHoveredPoint({
|
|
11545
|
+
x: point.x,
|
|
11546
|
+
y: point.y,
|
|
11547
|
+
axis: series[0]?.data[j]?.axis ?? "",
|
|
11548
|
+
items
|
|
11549
|
+
});
|
|
11550
|
+
},
|
|
11551
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
11552
|
+
className: "cursor-pointer",
|
|
11553
|
+
children: [
|
|
11554
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
11555
|
+
"circle",
|
|
11556
|
+
{
|
|
11557
|
+
cx: point.x,
|
|
11558
|
+
cy: point.y,
|
|
11559
|
+
r: hoveredPoint?.axis === series[0]?.data[j]?.axis ? 6 : 4,
|
|
11560
|
+
fill: s.color,
|
|
11561
|
+
className: "transition-all duration-150",
|
|
11562
|
+
style: animated ? {
|
|
11563
|
+
opacity: 0,
|
|
11564
|
+
transform: "scale(0)",
|
|
11565
|
+
transformOrigin: `${point.x}px ${point.y}px`,
|
|
11566
|
+
animation: `dotPop 0.3s ease-out ${i * 0.15 + j * 0.05 + 0.3}s forwards`
|
|
11567
|
+
} : void 0
|
|
11568
|
+
}
|
|
11569
|
+
),
|
|
11570
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("circle", { cx: point.x, cy: point.y, r: 12, fill: "transparent" })
|
|
11571
|
+
]
|
|
11572
|
+
},
|
|
11573
|
+
j
|
|
11574
|
+
)),
|
|
11575
|
+
showValues && s.points.map((point, j) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
11576
|
+
"text",
|
|
11577
|
+
{
|
|
11578
|
+
x: point.x,
|
|
11579
|
+
y: point.y - 10,
|
|
11580
|
+
textAnchor: "middle",
|
|
11581
|
+
fontSize: "10",
|
|
11582
|
+
fontWeight: "500",
|
|
11583
|
+
className: "text-foreground",
|
|
11584
|
+
fill: "currentColor",
|
|
11585
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.15 + 0.5}s forwards` } : void 0,
|
|
11586
|
+
children: point.value
|
|
11587
|
+
},
|
|
11588
|
+
`val-${j}`
|
|
11589
|
+
))
|
|
11590
|
+
] }, i)),
|
|
11591
|
+
showLabels && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("g", { className: "text-muted-foreground", children: axes.map((axis, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("text", { x: axis.labelX, y: axis.labelY, textAnchor: "middle", dominantBaseline: "middle", fontSize: "11", fill: "currentColor", children: axis.label }, i)) }),
|
|
11592
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("style", { children: `
|
|
11593
|
+
@keyframes radarPop {
|
|
11594
|
+
from {
|
|
11595
|
+
opacity: 0;
|
|
11596
|
+
transform: scale(0);
|
|
11597
|
+
}
|
|
11598
|
+
to {
|
|
11599
|
+
opacity: 1;
|
|
11600
|
+
transform: scale(1);
|
|
11601
|
+
}
|
|
11602
|
+
}
|
|
11603
|
+
@keyframes dotPop {
|
|
11604
|
+
from {
|
|
11605
|
+
transform: scale(0);
|
|
11606
|
+
opacity: 0;
|
|
11607
|
+
}
|
|
11608
|
+
to {
|
|
11609
|
+
transform: scale(1);
|
|
11610
|
+
opacity: 1;
|
|
11611
|
+
}
|
|
11612
|
+
}
|
|
11613
|
+
@keyframes fadeIn {
|
|
11614
|
+
from { opacity: 0; }
|
|
11615
|
+
to { opacity: 1; }
|
|
11616
|
+
}
|
|
11617
|
+
` })
|
|
11618
|
+
] }),
|
|
11619
|
+
showLegend && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "flex items-center justify-center gap-6", children: series.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
|
|
11620
|
+
"div",
|
|
11621
|
+
{
|
|
11622
|
+
className: "flex items-center gap-2 text-sm",
|
|
11623
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.5}s forwards` } : void 0,
|
|
11624
|
+
children: [
|
|
11625
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "w-3 h-3 rounded-sm", style: { backgroundColor: s.color } }),
|
|
11626
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "text-muted-foreground", children: s.name })
|
|
11627
|
+
]
|
|
11628
|
+
},
|
|
11629
|
+
i
|
|
11630
|
+
)) }),
|
|
11631
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
11632
|
+
ChartTooltip,
|
|
11633
|
+
{
|
|
11634
|
+
x: hoveredPoint?.x ?? 0,
|
|
11635
|
+
y: hoveredPoint?.y ?? 0,
|
|
11636
|
+
visible: !!hoveredPoint,
|
|
11637
|
+
label: hoveredPoint?.axis,
|
|
11638
|
+
items: hoveredPoint?.items,
|
|
11639
|
+
containerRef
|
|
11640
|
+
}
|
|
11641
|
+
)
|
|
11642
|
+
] });
|
|
11643
|
+
}
|
|
11644
|
+
|
|
11645
|
+
// ../../components/ui/GaugeChart.tsx
|
|
11646
|
+
var import_react29 = require("react");
|
|
11647
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
11648
|
+
function GaugeChart({
|
|
11649
|
+
value,
|
|
11650
|
+
min = 0,
|
|
11651
|
+
max = 100,
|
|
11652
|
+
size = 200,
|
|
11653
|
+
thickness = 20,
|
|
11654
|
+
color = "currentColor",
|
|
11655
|
+
backgroundColor,
|
|
11656
|
+
showValue = true,
|
|
11657
|
+
showMinMax = true,
|
|
11658
|
+
label,
|
|
11659
|
+
animated = true,
|
|
11660
|
+
startAngle = -135,
|
|
11661
|
+
endAngle = 135,
|
|
11662
|
+
className = ""
|
|
11663
|
+
}) {
|
|
11664
|
+
const center = size / 2;
|
|
11665
|
+
const radius = center - thickness / 2 - 10;
|
|
11666
|
+
const { backgroundPath, valuePath, percentage, needleAngle } = (0, import_react29.useMemo)(() => {
|
|
11667
|
+
const normalizedValue = Math.min(Math.max(value, min), max);
|
|
11668
|
+
const pct = (normalizedValue - min) / (max - min);
|
|
11669
|
+
const totalAngle = endAngle - startAngle;
|
|
11670
|
+
const currentAngle = startAngle + pct * totalAngle;
|
|
11671
|
+
const polarToCartesian = (angle) => {
|
|
11672
|
+
const radians = angle * Math.PI / 180;
|
|
11673
|
+
return {
|
|
11674
|
+
x: center + radius * Math.cos(radians),
|
|
11675
|
+
y: center + radius * Math.sin(radians)
|
|
11676
|
+
};
|
|
11677
|
+
};
|
|
11678
|
+
const createArc = (start, end) => {
|
|
11679
|
+
const startPoint = polarToCartesian(start);
|
|
11680
|
+
const endPoint = polarToCartesian(end);
|
|
11681
|
+
const largeArc = Math.abs(end - start) > 180 ? 1 : 0;
|
|
11682
|
+
return `M ${startPoint.x} ${startPoint.y} A ${radius} ${radius} 0 ${largeArc} 1 ${endPoint.x} ${endPoint.y}`;
|
|
11683
|
+
};
|
|
11684
|
+
return {
|
|
11685
|
+
backgroundPath: createArc(startAngle, endAngle),
|
|
11686
|
+
valuePath: createArc(startAngle, currentAngle),
|
|
11687
|
+
percentage: pct,
|
|
11688
|
+
needleAngle: currentAngle
|
|
11689
|
+
};
|
|
11690
|
+
}, [value, min, max, center, radius, startAngle, endAngle]);
|
|
11691
|
+
const needleLength = radius - 10;
|
|
11692
|
+
const needleAngleRad = needleAngle * Math.PI / 180;
|
|
11693
|
+
const needleX = center + needleLength * Math.cos(needleAngleRad);
|
|
11694
|
+
const needleY = center + needleLength * Math.sin(needleAngleRad);
|
|
11695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("svg", { width: size, height: size * 0.7, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
11696
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11697
|
+
"path",
|
|
11698
|
+
{
|
|
11699
|
+
d: backgroundPath,
|
|
11700
|
+
fill: "none",
|
|
11701
|
+
stroke: backgroundColor || "currentColor",
|
|
11702
|
+
strokeWidth: thickness,
|
|
11703
|
+
strokeLinecap: "round",
|
|
11704
|
+
className: !backgroundColor ? "text-muted-foreground/20" : ""
|
|
11705
|
+
}
|
|
11706
|
+
),
|
|
11707
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11708
|
+
"path",
|
|
11709
|
+
{
|
|
11710
|
+
d: valuePath,
|
|
11711
|
+
fill: "none",
|
|
11712
|
+
stroke: color,
|
|
11713
|
+
strokeWidth: thickness,
|
|
11714
|
+
strokeLinecap: "round",
|
|
11715
|
+
style: animated ? {
|
|
11716
|
+
strokeDasharray: "1000",
|
|
11717
|
+
strokeDashoffset: 1e3,
|
|
11718
|
+
animation: "drawArc 1s ease-out forwards"
|
|
11719
|
+
} : void 0
|
|
11720
|
+
}
|
|
11721
|
+
),
|
|
11722
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
11723
|
+
"g",
|
|
11724
|
+
{
|
|
11725
|
+
style: animated ? {
|
|
11726
|
+
transform: `rotate(${startAngle}deg)`,
|
|
11727
|
+
transformOrigin: `${center}px ${center}px`,
|
|
11728
|
+
animation: `needleRotate 1s ease-out forwards`,
|
|
11729
|
+
["--needle-end"]: `${needleAngle}deg`
|
|
11730
|
+
} : {
|
|
11731
|
+
transform: `rotate(${needleAngle}deg)`,
|
|
11732
|
+
transformOrigin: `${center}px ${center}px`
|
|
11733
|
+
},
|
|
11734
|
+
children: [
|
|
11735
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("line", { x1: center, y1: center, x2: center + needleLength, y2: center, stroke: color, strokeWidth: 3, strokeLinecap: "round" }),
|
|
11736
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("circle", { cx: center, cy: center, r: 8, fill: color }),
|
|
11737
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("circle", { cx: center, cy: center, r: 4, className: "text-background", fill: "currentColor" })
|
|
11738
|
+
]
|
|
11739
|
+
}
|
|
11740
|
+
),
|
|
11741
|
+
showMinMax && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("g", { className: "text-muted-foreground", children: [
|
|
11742
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11743
|
+
"text",
|
|
11744
|
+
{
|
|
11745
|
+
x: center + (radius + 20) * Math.cos(startAngle * Math.PI / 180),
|
|
11746
|
+
y: center + (radius + 20) * Math.sin(startAngle * Math.PI / 180) + 5,
|
|
11747
|
+
textAnchor: "middle",
|
|
11748
|
+
fontSize: "10",
|
|
11749
|
+
fill: "currentColor",
|
|
11750
|
+
children: min
|
|
11751
|
+
}
|
|
11752
|
+
),
|
|
11753
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11754
|
+
"text",
|
|
11755
|
+
{
|
|
11756
|
+
x: center + (radius + 20) * Math.cos(endAngle * Math.PI / 180),
|
|
11757
|
+
y: center + (radius + 20) * Math.sin(endAngle * Math.PI / 180) + 5,
|
|
11758
|
+
textAnchor: "middle",
|
|
11759
|
+
fontSize: "10",
|
|
11760
|
+
fill: "currentColor",
|
|
11761
|
+
children: max
|
|
11762
|
+
}
|
|
11763
|
+
)
|
|
11764
|
+
] }),
|
|
11765
|
+
showValue && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("g", { children: [
|
|
11766
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11767
|
+
"text",
|
|
11768
|
+
{
|
|
11769
|
+
x: center,
|
|
11770
|
+
y: center + 35,
|
|
11771
|
+
textAnchor: "middle",
|
|
11772
|
+
fontSize: "24",
|
|
11773
|
+
fontWeight: "600",
|
|
11774
|
+
className: "text-foreground",
|
|
11775
|
+
fill: "currentColor",
|
|
11776
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.5s forwards" } : void 0,
|
|
11777
|
+
children: value
|
|
11778
|
+
}
|
|
11779
|
+
),
|
|
11780
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
11781
|
+
"text",
|
|
11782
|
+
{
|
|
11783
|
+
x: center,
|
|
11784
|
+
y: center + 55,
|
|
11785
|
+
textAnchor: "middle",
|
|
11786
|
+
fontSize: "12",
|
|
11787
|
+
className: "text-muted-foreground",
|
|
11788
|
+
fill: "currentColor",
|
|
11789
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.6s forwards" } : void 0,
|
|
11790
|
+
children: label
|
|
11791
|
+
}
|
|
11792
|
+
)
|
|
11793
|
+
] }),
|
|
11794
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("style", { children: `
|
|
11795
|
+
@keyframes drawArc {
|
|
11796
|
+
to {
|
|
11797
|
+
stroke-dashoffset: 0;
|
|
11798
|
+
}
|
|
11799
|
+
}
|
|
11800
|
+
@keyframes needleRotate {
|
|
11801
|
+
to {
|
|
11802
|
+
transform: rotate(var(--needle-end));
|
|
11803
|
+
}
|
|
11804
|
+
}
|
|
11805
|
+
@keyframes fadeIn {
|
|
11806
|
+
from { opacity: 0; }
|
|
11807
|
+
to { opacity: 1; }
|
|
11808
|
+
}
|
|
11809
|
+
` })
|
|
11810
|
+
] });
|
|
11811
|
+
}
|
|
11812
|
+
|
|
11813
|
+
// ../../components/ui/ClientOnly.tsx
|
|
11814
|
+
var import_react30 = require("react");
|
|
11815
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
11816
|
+
function ClientOnly({ children, fallback = null }) {
|
|
11817
|
+
const [hasMounted, setHasMounted] = (0, import_react30.useState)(false);
|
|
11818
|
+
(0, import_react30.useEffect)(() => {
|
|
10448
11819
|
setHasMounted(true);
|
|
10449
11820
|
}, []);
|
|
10450
11821
|
if (!hasMounted) {
|
|
10451
|
-
return /* @__PURE__ */ (0,
|
|
11822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children: fallback });
|
|
10452
11823
|
}
|
|
10453
|
-
return /* @__PURE__ */ (0,
|
|
11824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children });
|
|
10454
11825
|
}
|
|
10455
11826
|
|
|
10456
11827
|
// ../../components/ui/Loading.tsx
|
|
10457
11828
|
var import_lucide_react25 = require("lucide-react");
|
|
10458
|
-
var
|
|
11829
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
10459
11830
|
var LoadingSpinner = ({
|
|
10460
11831
|
size = "md",
|
|
10461
11832
|
className,
|
|
@@ -10471,7 +11842,7 @@ var LoadingSpinner = ({
|
|
|
10471
11842
|
foreground: "text-foreground",
|
|
10472
11843
|
muted: "text-muted-foreground"
|
|
10473
11844
|
};
|
|
10474
|
-
return /* @__PURE__ */ (0,
|
|
11845
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
10475
11846
|
import_lucide_react25.Activity,
|
|
10476
11847
|
{
|
|
10477
11848
|
className: cn(
|
|
@@ -10492,7 +11863,7 @@ var LoadingDots = ({
|
|
|
10492
11863
|
foreground: "bg-foreground",
|
|
10493
11864
|
muted: "bg-muted-foreground"
|
|
10494
11865
|
};
|
|
10495
|
-
return /* @__PURE__ */ (0,
|
|
11866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: cn("flex items-center space-x-1", className), children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
10496
11867
|
"div",
|
|
10497
11868
|
{
|
|
10498
11869
|
className: cn(
|
|
@@ -10514,7 +11885,7 @@ var LoadingBar = ({
|
|
|
10514
11885
|
label
|
|
10515
11886
|
}) => {
|
|
10516
11887
|
const pct = progress ? Math.min(Math.max(progress, 0), 100) : void 0;
|
|
10517
|
-
return /* @__PURE__ */ (0,
|
|
11888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
10518
11889
|
"div",
|
|
10519
11890
|
{
|
|
10520
11891
|
className: cn("w-full bg-muted rounded-full h-2", className),
|
|
@@ -10523,7 +11894,7 @@ var LoadingBar = ({
|
|
|
10523
11894
|
"aria-valuemax": pct === void 0 ? void 0 : 100,
|
|
10524
11895
|
"aria-valuenow": pct === void 0 ? void 0 : Math.round(pct),
|
|
10525
11896
|
"aria-label": label || "Loading",
|
|
10526
|
-
children: /* @__PURE__ */ (0,
|
|
11897
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
10527
11898
|
"div",
|
|
10528
11899
|
{
|
|
10529
11900
|
className: cn(
|
|
@@ -10540,9 +11911,9 @@ var LoadingBar = ({
|
|
|
10540
11911
|
};
|
|
10541
11912
|
|
|
10542
11913
|
// ../../components/ui/Table.tsx
|
|
10543
|
-
var
|
|
10544
|
-
var
|
|
10545
|
-
var Table =
|
|
11914
|
+
var import_react31 = __toESM(require("react"), 1);
|
|
11915
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
11916
|
+
var Table = import_react31.default.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
10546
11917
|
"div",
|
|
10547
11918
|
{
|
|
10548
11919
|
className: cn(
|
|
@@ -10552,20 +11923,20 @@ var Table = import_react23.default.forwardRef(({ className, containerClassName,
|
|
|
10552
11923
|
"backdrop-blur-sm transition-all duration-300",
|
|
10553
11924
|
containerClassName
|
|
10554
11925
|
),
|
|
10555
|
-
children: /* @__PURE__ */ (0,
|
|
11926
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props })
|
|
10556
11927
|
}
|
|
10557
11928
|
));
|
|
10558
11929
|
Table.displayName = "Table";
|
|
10559
|
-
var TableHeader =
|
|
11930
|
+
var TableHeader = import_react31.default.forwardRef(({ className, children, filterRow, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("thead", { ref, className: cn("[&_tr]:border-b [&_tr]:border-border", "bg-muted/50", className), ...props, children: [
|
|
10560
11931
|
children,
|
|
10561
11932
|
filterRow
|
|
10562
11933
|
] }));
|
|
10563
11934
|
TableHeader.displayName = "TableHeader";
|
|
10564
|
-
var TableBody =
|
|
11935
|
+
var TableBody = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
|
|
10565
11936
|
TableBody.displayName = "TableBody";
|
|
10566
|
-
var TableFooter =
|
|
11937
|
+
var TableFooter = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props }));
|
|
10567
11938
|
TableFooter.displayName = "TableFooter";
|
|
10568
|
-
var TableRow =
|
|
11939
|
+
var TableRow = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
10569
11940
|
"tr",
|
|
10570
11941
|
{
|
|
10571
11942
|
ref,
|
|
@@ -10579,7 +11950,7 @@ var TableRow = import_react23.default.forwardRef(({ className, ...props }, ref)
|
|
|
10579
11950
|
}
|
|
10580
11951
|
));
|
|
10581
11952
|
TableRow.displayName = "TableRow";
|
|
10582
|
-
var TableHead =
|
|
11953
|
+
var TableHead = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
10583
11954
|
"th",
|
|
10584
11955
|
{
|
|
10585
11956
|
ref,
|
|
@@ -10588,18 +11959,18 @@ var TableHead = import_react23.default.forwardRef(({ className, ...props }, ref)
|
|
|
10588
11959
|
}
|
|
10589
11960
|
));
|
|
10590
11961
|
TableHead.displayName = "TableHead";
|
|
10591
|
-
var TableCell =
|
|
11962
|
+
var TableCell = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props }));
|
|
10592
11963
|
TableCell.displayName = "TableCell";
|
|
10593
|
-
var TableCaption =
|
|
11964
|
+
var TableCaption = import_react31.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
|
|
10594
11965
|
TableCaption.displayName = "TableCaption";
|
|
10595
11966
|
|
|
10596
11967
|
// ../../components/ui/DataTable.tsx
|
|
10597
11968
|
var import_lucide_react26 = require("lucide-react");
|
|
10598
|
-
var
|
|
10599
|
-
var
|
|
11969
|
+
var import_react32 = __toESM(require("react"), 1);
|
|
11970
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
10600
11971
|
function useDebounced(value, delay = 300) {
|
|
10601
|
-
const [debounced, setDebounced] =
|
|
10602
|
-
|
|
11972
|
+
const [debounced, setDebounced] = import_react32.default.useState(value);
|
|
11973
|
+
import_react32.default.useEffect(() => {
|
|
10603
11974
|
const id = setTimeout(() => setDebounced(value), delay);
|
|
10604
11975
|
return () => clearTimeout(id);
|
|
10605
11976
|
}, [value, delay]);
|
|
@@ -10628,15 +11999,15 @@ function DataTable({
|
|
|
10628
11999
|
labels
|
|
10629
12000
|
}) {
|
|
10630
12001
|
const t = useTranslations("Common");
|
|
10631
|
-
const [headerAlign, setHeaderAlign] =
|
|
10632
|
-
const [visibleCols, setVisibleCols] =
|
|
10633
|
-
const [filters, setFilters] =
|
|
10634
|
-
const [sort, setSort] =
|
|
10635
|
-
const [density, setDensity] =
|
|
10636
|
-
const [curPage, setCurPage] =
|
|
10637
|
-
const hasMounted =
|
|
10638
|
-
const loadedFromStorage =
|
|
10639
|
-
const getInitialPageSize =
|
|
12002
|
+
const [headerAlign, setHeaderAlign] = import_react32.default.useState("left");
|
|
12003
|
+
const [visibleCols, setVisibleCols] = import_react32.default.useState(() => columns.filter((c) => c.visible !== false).map((c) => c.key));
|
|
12004
|
+
const [filters, setFilters] = import_react32.default.useState({});
|
|
12005
|
+
const [sort, setSort] = import_react32.default.useState(null);
|
|
12006
|
+
const [density, setDensity] = import_react32.default.useState("normal");
|
|
12007
|
+
const [curPage, setCurPage] = import_react32.default.useState(page);
|
|
12008
|
+
const hasMounted = import_react32.default.useRef(false);
|
|
12009
|
+
const loadedFromStorage = import_react32.default.useRef(false);
|
|
12010
|
+
const getInitialPageSize = import_react32.default.useCallback(() => {
|
|
10640
12011
|
if (typeof window === "undefined" || !storageKey) return pageSize;
|
|
10641
12012
|
try {
|
|
10642
12013
|
const saved = localStorage.getItem(`datatable_${storageKey}_pageSize`);
|
|
@@ -10651,8 +12022,8 @@ function DataTable({
|
|
|
10651
12022
|
}
|
|
10652
12023
|
return pageSize;
|
|
10653
12024
|
}, [storageKey, pageSize]);
|
|
10654
|
-
const [curPageSize, setCurPageSize] =
|
|
10655
|
-
|
|
12025
|
+
const [curPageSize, setCurPageSize] = import_react32.default.useState(getInitialPageSize);
|
|
12026
|
+
import_react32.default.useEffect(() => {
|
|
10656
12027
|
if (typeof window === "undefined" || !storageKey) return;
|
|
10657
12028
|
if (!hasMounted.current) return;
|
|
10658
12029
|
try {
|
|
@@ -10660,7 +12031,7 @@ function DataTable({
|
|
|
10660
12031
|
} catch {
|
|
10661
12032
|
}
|
|
10662
12033
|
}, [curPageSize, storageKey]);
|
|
10663
|
-
|
|
12034
|
+
import_react32.default.useEffect(() => {
|
|
10664
12035
|
const newColKeys = columns.filter((c) => c.visible !== false).map((c) => c.key);
|
|
10665
12036
|
setVisibleCols((prev) => {
|
|
10666
12037
|
const uniqueKeys = /* @__PURE__ */ new Set([...prev, ...newColKeys]);
|
|
@@ -10668,16 +12039,16 @@ function DataTable({
|
|
|
10668
12039
|
});
|
|
10669
12040
|
}, [columns]);
|
|
10670
12041
|
const debouncedFilters = useDebounced(filters, 350);
|
|
10671
|
-
|
|
12042
|
+
import_react32.default.useEffect(() => {
|
|
10672
12043
|
setCurPage(page);
|
|
10673
12044
|
}, [page]);
|
|
10674
|
-
|
|
12045
|
+
import_react32.default.useEffect(() => {
|
|
10675
12046
|
if (storageKey && loadedFromStorage.current) {
|
|
10676
12047
|
return;
|
|
10677
12048
|
}
|
|
10678
12049
|
setCurPageSize(pageSize);
|
|
10679
12050
|
}, [pageSize, storageKey]);
|
|
10680
|
-
|
|
12051
|
+
import_react32.default.useEffect(() => {
|
|
10681
12052
|
if (!onQueryChange) return;
|
|
10682
12053
|
if (!hasMounted.current) {
|
|
10683
12054
|
hasMounted.current = true;
|
|
@@ -10700,7 +12071,7 @@ function DataTable({
|
|
|
10700
12071
|
className: "h-8 w-full text-sm"
|
|
10701
12072
|
};
|
|
10702
12073
|
if (col.filter.type === "text") {
|
|
10703
|
-
return /* @__PURE__ */ (0,
|
|
12074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10704
12075
|
Input_default,
|
|
10705
12076
|
{
|
|
10706
12077
|
...commonProps,
|
|
@@ -10715,7 +12086,7 @@ function DataTable({
|
|
|
10715
12086
|
}
|
|
10716
12087
|
if (col.filter.type === "select") {
|
|
10717
12088
|
const options = col.filter.options || [];
|
|
10718
|
-
return /* @__PURE__ */ (0,
|
|
12089
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10719
12090
|
Combobox,
|
|
10720
12091
|
{
|
|
10721
12092
|
options: ["", ...options],
|
|
@@ -10731,7 +12102,7 @@ function DataTable({
|
|
|
10731
12102
|
);
|
|
10732
12103
|
}
|
|
10733
12104
|
if (col.filter.type === "date") {
|
|
10734
|
-
return /* @__PURE__ */ (0,
|
|
12105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10735
12106
|
DatePicker,
|
|
10736
12107
|
{
|
|
10737
12108
|
placeholder: col.filter.placeholder || `Select ${String(col.title)}`,
|
|
@@ -10745,7 +12116,7 @@ function DataTable({
|
|
|
10745
12116
|
}
|
|
10746
12117
|
return null;
|
|
10747
12118
|
};
|
|
10748
|
-
const renderHeader = /* @__PURE__ */ (0,
|
|
12119
|
+
const renderHeader = /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { children: visibleColumns.map((col, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10749
12120
|
TableHead,
|
|
10750
12121
|
{
|
|
10751
12122
|
style: { width: col.width },
|
|
@@ -10758,9 +12129,9 @@ function DataTable({
|
|
|
10758
12129
|
children: (() => {
|
|
10759
12130
|
const isRightAlign = col.align === "right" || !col.align && headerAlign === "right";
|
|
10760
12131
|
const isCenterAlign = col.align === "center" || !col.align && headerAlign === "center";
|
|
10761
|
-
const titleContent = /* @__PURE__ */ (0,
|
|
10762
|
-
/* @__PURE__ */ (0,
|
|
10763
|
-
col.sortable && /* @__PURE__ */ (0,
|
|
12132
|
+
const titleContent = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-1 min-w-0 shrink", children: [
|
|
12133
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "truncate font-medium text-sm", children: col.title }),
|
|
12134
|
+
col.sortable && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10764
12135
|
"button",
|
|
10765
12136
|
{
|
|
10766
12137
|
className: cn(
|
|
@@ -10777,8 +12148,8 @@ function DataTable({
|
|
|
10777
12148
|
},
|
|
10778
12149
|
"aria-label": "Sort",
|
|
10779
12150
|
title: `Sort by ${String(col.title)}`,
|
|
10780
|
-
children: /* @__PURE__ */ (0,
|
|
10781
|
-
/* @__PURE__ */ (0,
|
|
12151
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", className: "inline-block", children: [
|
|
12152
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10782
12153
|
"path",
|
|
10783
12154
|
{
|
|
10784
12155
|
d: "M7 8l3-3 3 3",
|
|
@@ -10789,7 +12160,7 @@ function DataTable({
|
|
|
10789
12160
|
opacity: sort?.key === col.key && sort.order === "asc" ? 1 : 0.4
|
|
10790
12161
|
}
|
|
10791
12162
|
),
|
|
10792
|
-
/* @__PURE__ */ (0,
|
|
12163
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10793
12164
|
"path",
|
|
10794
12165
|
{
|
|
10795
12166
|
d: "M7 12l3 3 3-3",
|
|
@@ -10804,11 +12175,11 @@ function DataTable({
|
|
|
10804
12175
|
}
|
|
10805
12176
|
)
|
|
10806
12177
|
] });
|
|
10807
|
-
const filterContent = col.filter && /* @__PURE__ */ (0,
|
|
12178
|
+
const filterContent = col.filter && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10808
12179
|
Popover,
|
|
10809
12180
|
{
|
|
10810
12181
|
placement: isRightAlign ? "bottom-end" : "bottom-start",
|
|
10811
|
-
trigger: /* @__PURE__ */ (0,
|
|
12182
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10812
12183
|
"button",
|
|
10813
12184
|
{
|
|
10814
12185
|
className: cn(
|
|
@@ -10818,16 +12189,16 @@ function DataTable({
|
|
|
10818
12189
|
),
|
|
10819
12190
|
"aria-label": "Filter",
|
|
10820
12191
|
title: "Filter",
|
|
10821
|
-
children: /* @__PURE__ */ (0,
|
|
12192
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react26.Filter, { className: "h-4 w-4" })
|
|
10822
12193
|
}
|
|
10823
12194
|
),
|
|
10824
|
-
children: /* @__PURE__ */ (0,
|
|
10825
|
-
/* @__PURE__ */ (0,
|
|
12195
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "w-48 p-2 space-y-2", children: [
|
|
12196
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: [
|
|
10826
12197
|
"Filter ",
|
|
10827
12198
|
col.title
|
|
10828
12199
|
] }),
|
|
10829
12200
|
renderFilterControl(col),
|
|
10830
|
-
filters[col.key] && /* @__PURE__ */ (0,
|
|
12201
|
+
filters[col.key] && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10831
12202
|
"button",
|
|
10832
12203
|
{
|
|
10833
12204
|
onClick: () => {
|
|
@@ -10845,7 +12216,7 @@ function DataTable({
|
|
|
10845
12216
|
] })
|
|
10846
12217
|
}
|
|
10847
12218
|
);
|
|
10848
|
-
return /* @__PURE__ */ (0,
|
|
12219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10849
12220
|
"div",
|
|
10850
12221
|
{
|
|
10851
12222
|
className: cn(
|
|
@@ -10854,10 +12225,10 @@ function DataTable({
|
|
|
10854
12225
|
isCenterAlign && "justify-center",
|
|
10855
12226
|
!isRightAlign && !isCenterAlign && "justify-between"
|
|
10856
12227
|
),
|
|
10857
|
-
children: isRightAlign ? /* @__PURE__ */ (0,
|
|
12228
|
+
children: isRightAlign ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10858
12229
|
filterContent,
|
|
10859
12230
|
titleContent
|
|
10860
|
-
] }) : /* @__PURE__ */ (0,
|
|
12231
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
10861
12232
|
titleContent,
|
|
10862
12233
|
filterContent
|
|
10863
12234
|
] })
|
|
@@ -10868,7 +12239,7 @@ function DataTable({
|
|
|
10868
12239
|
col.key
|
|
10869
12240
|
)) });
|
|
10870
12241
|
const isServerMode = Boolean(onQueryChange);
|
|
10871
|
-
const processedData =
|
|
12242
|
+
const processedData = import_react32.default.useMemo(() => {
|
|
10872
12243
|
if (isServerMode) return data;
|
|
10873
12244
|
let result = [...data];
|
|
10874
12245
|
if (Object.keys(filters).length > 0) {
|
|
@@ -10900,21 +12271,21 @@ function DataTable({
|
|
|
10900
12271
|
return result;
|
|
10901
12272
|
}, [data, isServerMode, filters, sort, columns]);
|
|
10902
12273
|
const totalItems = isServerMode ? total : processedData.length;
|
|
10903
|
-
const displayedData = isServerMode ? data :
|
|
12274
|
+
const displayedData = isServerMode ? data : import_react32.default.useMemo(() => {
|
|
10904
12275
|
const start = (curPage - 1) * curPageSize;
|
|
10905
12276
|
if (start >= processedData.length && curPage > 1) {
|
|
10906
12277
|
}
|
|
10907
12278
|
return processedData.slice(start, start + curPageSize);
|
|
10908
12279
|
}, [processedData, curPage, curPageSize]);
|
|
10909
|
-
return /* @__PURE__ */ (0,
|
|
10910
|
-
/* @__PURE__ */ (0,
|
|
10911
|
-
/* @__PURE__ */ (0,
|
|
10912
|
-
/* @__PURE__ */ (0,
|
|
10913
|
-
enableDensityToggle && /* @__PURE__ */ (0,
|
|
12280
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: cn("space-y-2", className), children: [
|
|
12281
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center justify-between gap-4 mb-1", children: [
|
|
12282
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "text-sm text-muted-foreground", children: caption }),
|
|
12283
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12284
|
+
enableDensityToggle && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10914
12285
|
DropdownMenu_default,
|
|
10915
12286
|
{
|
|
10916
|
-
trigger: /* @__PURE__ */ (0,
|
|
10917
|
-
/* @__PURE__ */ (0,
|
|
12287
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12288
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
10918
12289
|
labels?.density || t("density")
|
|
10919
12290
|
] }),
|
|
10920
12291
|
items: [
|
|
@@ -10924,11 +12295,11 @@ function DataTable({
|
|
|
10924
12295
|
]
|
|
10925
12296
|
}
|
|
10926
12297
|
),
|
|
10927
|
-
enableColumnVisibilityToggle && /* @__PURE__ */ (0,
|
|
12298
|
+
enableColumnVisibilityToggle && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10928
12299
|
DropdownMenu_default,
|
|
10929
12300
|
{
|
|
10930
|
-
trigger: /* @__PURE__ */ (0,
|
|
10931
|
-
/* @__PURE__ */ (0,
|
|
12301
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12302
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10932
12303
|
"path",
|
|
10933
12304
|
{
|
|
10934
12305
|
strokeLinecap: "round",
|
|
@@ -10939,26 +12310,26 @@ function DataTable({
|
|
|
10939
12310
|
) }),
|
|
10940
12311
|
labels?.columns || t("columns")
|
|
10941
12312
|
] }),
|
|
10942
|
-
children: columns.map((c) => /* @__PURE__ */ (0,
|
|
12313
|
+
children: columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
10943
12314
|
DropdownMenuItem,
|
|
10944
12315
|
{
|
|
10945
12316
|
onClick: () => {
|
|
10946
12317
|
setVisibleCols((prev) => prev.includes(c.key) ? prev.filter((k) => k !== c.key) : [...prev, c.key]);
|
|
10947
12318
|
},
|
|
10948
12319
|
children: [
|
|
10949
|
-
/* @__PURE__ */ (0,
|
|
10950
|
-
/* @__PURE__ */ (0,
|
|
12320
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("input", { type: "checkbox", className: "mr-2 rounded border-border", readOnly: true, checked: visibleCols.includes(c.key) }),
|
|
12321
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "truncate", children: c.title })
|
|
10951
12322
|
]
|
|
10952
12323
|
},
|
|
10953
12324
|
c.key
|
|
10954
12325
|
))
|
|
10955
12326
|
}
|
|
10956
12327
|
),
|
|
10957
|
-
enableHeaderAlignToggle && /* @__PURE__ */ (0,
|
|
12328
|
+
enableHeaderAlignToggle && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10958
12329
|
DropdownMenu_default,
|
|
10959
12330
|
{
|
|
10960
|
-
trigger: /* @__PURE__ */ (0,
|
|
10961
|
-
/* @__PURE__ */ (0,
|
|
12331
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12332
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h10M4 18h16" }) }),
|
|
10962
12333
|
labels?.headerAlign || t("headerAlign")
|
|
10963
12334
|
] }),
|
|
10964
12335
|
items: [
|
|
@@ -10971,17 +12342,17 @@ function DataTable({
|
|
|
10971
12342
|
toolbar
|
|
10972
12343
|
] })
|
|
10973
12344
|
] }),
|
|
10974
|
-
/* @__PURE__ */ (0,
|
|
12345
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: cn("relative rounded-md border border-border/50 overflow-hidden", loading2 && "opacity-60 pointer-events-none"), children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
10975
12346
|
Table,
|
|
10976
12347
|
{
|
|
10977
12348
|
containerClassName: "border-0 md:border-0 rounded-none md:rounded-none shadow-none bg-transparent",
|
|
10978
12349
|
className: "[&_thead]:sticky [&_thead]:top-0 [&_thead]:z-5 [&_thead]:bg-background [&_thead]:backdrop-blur-sm",
|
|
10979
12350
|
children: [
|
|
10980
|
-
/* @__PURE__ */ (0,
|
|
10981
|
-
/* @__PURE__ */ (0,
|
|
10982
|
-
/* @__PURE__ */ (0,
|
|
10983
|
-
/* @__PURE__ */ (0,
|
|
10984
|
-
/* @__PURE__ */ (0,
|
|
12351
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableHeader, { children: renderHeader }),
|
|
12352
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableBody, { children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-8", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center justify-center gap-2 text-muted-foreground", children: [
|
|
12353
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
12354
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
12355
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10985
12356
|
"path",
|
|
10986
12357
|
{
|
|
10987
12358
|
className: "opacity-75",
|
|
@@ -10990,12 +12361,12 @@ function DataTable({
|
|
|
10990
12361
|
}
|
|
10991
12362
|
)
|
|
10992
12363
|
] }),
|
|
10993
|
-
/* @__PURE__ */ (0,
|
|
10994
|
-
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0,
|
|
12364
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "text-sm", children: "Loading..." })
|
|
12365
|
+
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: "No data" }) }) : displayedData.map((row, idx) => {
|
|
10995
12366
|
const isLastRow = idx === displayedData.length - 1;
|
|
10996
|
-
return /* @__PURE__ */ (0,
|
|
12367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/50"), children: visibleColumns.map((col, colIdx) => {
|
|
10997
12368
|
const value = col.dataIndex ? row[col.dataIndex] : void 0;
|
|
10998
|
-
return /* @__PURE__ */ (0,
|
|
12369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
10999
12370
|
TableCell,
|
|
11000
12371
|
{
|
|
11001
12372
|
className: cn(
|
|
@@ -11015,7 +12386,7 @@ function DataTable({
|
|
|
11015
12386
|
]
|
|
11016
12387
|
}
|
|
11017
12388
|
) }),
|
|
11018
|
-
totalItems > 0 && /* @__PURE__ */ (0,
|
|
12389
|
+
totalItems > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "border-t bg-muted/30 p-4 rounded-b-md", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
11019
12390
|
Pagination,
|
|
11020
12391
|
{
|
|
11021
12392
|
page: curPage,
|
|
@@ -11037,10 +12408,10 @@ function DataTable({
|
|
|
11037
12408
|
var DataTable_default = DataTable;
|
|
11038
12409
|
|
|
11039
12410
|
// ../../components/ui/Form.tsx
|
|
11040
|
-
var
|
|
12411
|
+
var React48 = __toESM(require("react"), 1);
|
|
11041
12412
|
var import_react_hook_form = require("react-hook-form");
|
|
11042
|
-
var
|
|
11043
|
-
var FormConfigContext =
|
|
12413
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
12414
|
+
var FormConfigContext = React48.createContext({ size: "md" });
|
|
11044
12415
|
var FormWrapper = ({
|
|
11045
12416
|
children,
|
|
11046
12417
|
onSubmit,
|
|
@@ -11053,24 +12424,24 @@ var FormWrapper = ({
|
|
|
11053
12424
|
const methods = (0, import_react_hook_form.useForm)({
|
|
11054
12425
|
defaultValues: initialValues
|
|
11055
12426
|
});
|
|
11056
|
-
|
|
12427
|
+
React48.useEffect(() => {
|
|
11057
12428
|
if (initialValues) {
|
|
11058
12429
|
methods.reset(initialValues);
|
|
11059
12430
|
}
|
|
11060
12431
|
}, [JSON.stringify(initialValues)]);
|
|
11061
12432
|
const { validationSchema: _, ...formProps } = props;
|
|
11062
|
-
return /* @__PURE__ */ (0,
|
|
12433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_hook_form.FormProvider, { ...methods, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormConfigContext.Provider, { value: { size }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("form", { onSubmit: methods.handleSubmit(onSubmit), className, ...formProps, children }) }) });
|
|
11063
12434
|
};
|
|
11064
12435
|
var Form = FormWrapper;
|
|
11065
|
-
var FormFieldContext =
|
|
12436
|
+
var FormFieldContext = React48.createContext({});
|
|
11066
12437
|
var FormField = ({
|
|
11067
12438
|
...props
|
|
11068
12439
|
}) => {
|
|
11069
|
-
return /* @__PURE__ */ (0,
|
|
12440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_hook_form.Controller, { ...props }) });
|
|
11070
12441
|
};
|
|
11071
12442
|
var useFormField = () => {
|
|
11072
|
-
const fieldContext =
|
|
11073
|
-
const itemContext =
|
|
12443
|
+
const fieldContext = React48.useContext(FormFieldContext);
|
|
12444
|
+
const itemContext = React48.useContext(FormItemContext);
|
|
11074
12445
|
const { getFieldState, formState } = (0, import_react_hook_form.useFormContext)();
|
|
11075
12446
|
if (!fieldContext) {
|
|
11076
12447
|
try {
|
|
@@ -11091,27 +12462,27 @@ var useFormField = () => {
|
|
|
11091
12462
|
...fieldState
|
|
11092
12463
|
};
|
|
11093
12464
|
};
|
|
11094
|
-
var FormItemContext =
|
|
11095
|
-
var FormItem =
|
|
11096
|
-
const id =
|
|
11097
|
-
return /* @__PURE__ */ (0,
|
|
12465
|
+
var FormItemContext = React48.createContext({});
|
|
12466
|
+
var FormItem = React48.forwardRef(({ className, ...props }, ref) => {
|
|
12467
|
+
const id = React48.useId();
|
|
12468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { ref, className: cn("space-y-2", className), ...props }) });
|
|
11098
12469
|
});
|
|
11099
12470
|
FormItem.displayName = "FormItem";
|
|
11100
|
-
var FormLabel =
|
|
12471
|
+
var FormLabel = React48.forwardRef(
|
|
11101
12472
|
({ className, children, required, ...props }, ref) => {
|
|
11102
12473
|
const { error, formItemId } = useFormField();
|
|
11103
|
-
const config =
|
|
12474
|
+
const config = React48.useContext(FormConfigContext);
|
|
11104
12475
|
const sizeClass = config.size === "sm" ? "text-xs" : config.size === "lg" ? "text-base" : "text-sm";
|
|
11105
|
-
return /* @__PURE__ */ (0,
|
|
12476
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Label, { ref, className: cn(sizeClass, error && "text-destructive", className), htmlFor: formItemId, ...props, children: [
|
|
11106
12477
|
children,
|
|
11107
|
-
required && /* @__PURE__ */ (0,
|
|
12478
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { className: "text-destructive ml-1", children: "*" })
|
|
11108
12479
|
] });
|
|
11109
12480
|
}
|
|
11110
12481
|
);
|
|
11111
12482
|
FormLabel.displayName = "FormLabel";
|
|
11112
|
-
var FormControl =
|
|
12483
|
+
var FormControl = React48.forwardRef(({ ...props }, ref) => {
|
|
11113
12484
|
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
11114
|
-
return /* @__PURE__ */ (0,
|
|
12485
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
11115
12486
|
"div",
|
|
11116
12487
|
{
|
|
11117
12488
|
ref,
|
|
@@ -11123,37 +12494,37 @@ var FormControl = React40.forwardRef(({ ...props }, ref) => {
|
|
|
11123
12494
|
);
|
|
11124
12495
|
});
|
|
11125
12496
|
FormControl.displayName = "FormControl";
|
|
11126
|
-
var FormDescription =
|
|
12497
|
+
var FormDescription = React48.forwardRef(({ className, ...props }, ref) => {
|
|
11127
12498
|
const { formDescriptionId } = useFormField();
|
|
11128
|
-
return /* @__PURE__ */ (0,
|
|
12499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { ref, id: formDescriptionId, className: cn("text-sm text-muted-foreground", className), ...props });
|
|
11129
12500
|
});
|
|
11130
12501
|
FormDescription.displayName = "FormDescription";
|
|
11131
|
-
var FormMessage =
|
|
12502
|
+
var FormMessage = React48.forwardRef(({ className, children, ...props }, ref) => {
|
|
11132
12503
|
const { error, formMessageId } = useFormField();
|
|
11133
12504
|
const body = error ? String(error?.message) : children;
|
|
11134
12505
|
if (!body) {
|
|
11135
12506
|
return null;
|
|
11136
12507
|
}
|
|
11137
|
-
return /* @__PURE__ */ (0,
|
|
12508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { ref, id: formMessageId, className: cn("text-sm font-medium text-destructive", className), ...props, children: body });
|
|
11138
12509
|
});
|
|
11139
12510
|
FormMessage.displayName = "FormMessage";
|
|
11140
|
-
var FormInput =
|
|
12511
|
+
var FormInput = React48.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
11141
12512
|
FormField,
|
|
11142
12513
|
{
|
|
11143
12514
|
name,
|
|
11144
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
11145
|
-
/* @__PURE__ */ (0,
|
|
11146
|
-
/* @__PURE__ */ (0,
|
|
12515
|
+
render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(FormItem, { children: [
|
|
12516
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormControl, { children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Input_default, { size: props.size ?? size, ...field, ...props }) }),
|
|
12517
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormMessage, {})
|
|
11147
12518
|
] })
|
|
11148
12519
|
}
|
|
11149
12520
|
) }));
|
|
11150
12521
|
FormInput.displayName = "FormInput";
|
|
11151
|
-
var FormCheckbox =
|
|
12522
|
+
var FormCheckbox = React48.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
11152
12523
|
FormField,
|
|
11153
12524
|
{
|
|
11154
12525
|
name,
|
|
11155
|
-
render: ({ field }) => /* @__PURE__ */ (0,
|
|
11156
|
-
/* @__PURE__ */ (0,
|
|
12526
|
+
render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(FormItem, { children: [
|
|
12527
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormControl, { children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
11157
12528
|
Checkbox,
|
|
11158
12529
|
{
|
|
11159
12530
|
ref,
|
|
@@ -11167,21 +12538,21 @@ var FormCheckbox = React40.forwardRef(({ name, ...props }, ref) => /* @__PURE__
|
|
|
11167
12538
|
...props
|
|
11168
12539
|
}
|
|
11169
12540
|
) }),
|
|
11170
|
-
/* @__PURE__ */ (0,
|
|
12541
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormMessage, {})
|
|
11171
12542
|
] })
|
|
11172
12543
|
}
|
|
11173
12544
|
) }));
|
|
11174
12545
|
FormCheckbox.displayName = "FormCheckbox";
|
|
11175
|
-
var FormActions =
|
|
12546
|
+
var FormActions = React48.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { ref, className: cn("flex gap-2 justify-end", className), ...props }));
|
|
11176
12547
|
FormActions.displayName = "FormActions";
|
|
11177
|
-
var FormSubmitButton =
|
|
11178
|
-
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ (0,
|
|
12548
|
+
var FormSubmitButton = React48.forwardRef(
|
|
12549
|
+
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Button_default, { ref, type: "submit", size: props.size ?? size, disabled: loading2, ...props, children }) })
|
|
11179
12550
|
);
|
|
11180
12551
|
FormSubmitButton.displayName = "FormSubmitButton";
|
|
11181
12552
|
|
|
11182
12553
|
// ../../components/ui/NotificationModal.tsx
|
|
11183
12554
|
var import_lucide_react27 = require("lucide-react");
|
|
11184
|
-
var
|
|
12555
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
11185
12556
|
function NotificationModal({ isOpen, onClose, notification, titleText, openLinkText, closeText }) {
|
|
11186
12557
|
const t = useTranslations("Common");
|
|
11187
12558
|
if (!notification) return null;
|
|
@@ -11202,20 +12573,20 @@ function NotificationModal({ isOpen, onClose, notification, titleText, openLinkT
|
|
|
11202
12573
|
onClose();
|
|
11203
12574
|
}
|
|
11204
12575
|
};
|
|
11205
|
-
return /* @__PURE__ */ (0,
|
|
11206
|
-
/* @__PURE__ */ (0,
|
|
11207
|
-
/* @__PURE__ */ (0,
|
|
11208
|
-
/* @__PURE__ */ (0,
|
|
12576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Modal_default, { isOpen, onClose, title: titleText || t("notifications"), size: "md", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "space-y-4", children: [
|
|
12577
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex items-center gap-2 pb-2 border-b border-border", children: [
|
|
12578
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: cn("w-2 h-2 rounded-full", !notification.is_read ? "bg-primary" : "bg-border") }),
|
|
12579
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { className: "text-xs text-muted-foreground", children: !notification.is_read ? t("newNotification") : t("readStatus") })
|
|
11209
12580
|
] }),
|
|
11210
|
-
notification.title && /* @__PURE__ */ (0,
|
|
11211
|
-
notification.body && /* @__PURE__ */ (0,
|
|
11212
|
-
/* @__PURE__ */ (0,
|
|
11213
|
-
/* @__PURE__ */ (0,
|
|
11214
|
-
hasLink && /* @__PURE__ */ (0,
|
|
11215
|
-
/* @__PURE__ */ (0,
|
|
12581
|
+
notification.title && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: notification.title }),
|
|
12582
|
+
notification.body && /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "text-sm text-muted-foreground whitespace-pre-wrap leading-relaxed", children: notification.body }),
|
|
12583
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "text-xs text-muted-foreground border-t border-border pt-2", children: formatTime3(notification.created_at) }),
|
|
12584
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "flex gap-2 justify-end pt-2", children: [
|
|
12585
|
+
hasLink && /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Button_default, { variant: "primary", size: "sm", onClick: handleLinkClick, className: "gap-2", children: [
|
|
12586
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_lucide_react27.ExternalLink, { className: "w-4 h-4" }),
|
|
11216
12587
|
openLinkText || t("openLink")
|
|
11217
12588
|
] }),
|
|
11218
|
-
/* @__PURE__ */ (0,
|
|
12589
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(Button_default, { variant: "ghost", size: "sm", onClick: onClose, children: closeText || t("close") })
|
|
11219
12590
|
] })
|
|
11220
12591
|
] }) });
|
|
11221
12592
|
}
|
|
@@ -11225,9 +12596,9 @@ var NotificationModal_default = NotificationModal;
|
|
|
11225
12596
|
var import_link2 = __toESM(require("next/link"), 1);
|
|
11226
12597
|
var import_navigation = require("next/navigation");
|
|
11227
12598
|
var import_lucide_react28 = require("lucide-react");
|
|
11228
|
-
var
|
|
12599
|
+
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
11229
12600
|
function MessengerIcon(props) {
|
|
11230
|
-
return /* @__PURE__ */ (0,
|
|
12601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("svg", { viewBox: "0 0 24 24", width: 24, height: 24, "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
11231
12602
|
"path",
|
|
11232
12603
|
{
|
|
11233
12604
|
d: "M12 2C6.477 2 2 6.145 2 11.235c0 2.93 1.35 5.542 3.464 7.25v3.515l3.344-1.836c.894.247 1.843.375 2.192.375 5.523 0 10-4.145 10-9.235S17.523 2 12 2zm.994 12.444l-2.563-2.73-5.004 2.73 5.507-5.84 2.626 2.729 4.942-2.729-5.508 5.84z",
|
|
@@ -11236,7 +12607,7 @@ function MessengerIcon(props) {
|
|
|
11236
12607
|
) });
|
|
11237
12608
|
}
|
|
11238
12609
|
function ZaloIcon(props) {
|
|
11239
|
-
return /* @__PURE__ */ (0,
|
|
12610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("svg", { viewBox: "0 0 48 48", width: 20, height: 20, "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
11240
12611
|
"path",
|
|
11241
12612
|
{
|
|
11242
12613
|
fill: "white",
|
|
@@ -11245,7 +12616,7 @@ function ZaloIcon(props) {
|
|
|
11245
12616
|
) });
|
|
11246
12617
|
}
|
|
11247
12618
|
function InstagramIcon(props) {
|
|
11248
|
-
return /* @__PURE__ */ (0,
|
|
12619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("svg", { viewBox: "0 0 24 24", width: 20, height: 20, "aria-hidden": "true", fill: "white", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("path", { d: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" }) });
|
|
11249
12620
|
}
|
|
11250
12621
|
function FloatingContacts({ className }) {
|
|
11251
12622
|
const pathname = (0, import_navigation.usePathname)();
|
|
@@ -11280,8 +12651,8 @@ function FloatingContacts({ className }) {
|
|
|
11280
12651
|
external: true
|
|
11281
12652
|
}
|
|
11282
12653
|
];
|
|
11283
|
-
return /* @__PURE__ */ (0,
|
|
11284
|
-
/* @__PURE__ */ (0,
|
|
12654
|
+
return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cn("fixed bottom-6 right-4 z-100000", "flex flex-col items-end gap-3", className), "aria-label": "Quick contacts", children: [
|
|
12655
|
+
/* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
11285
12656
|
import_link2.default,
|
|
11286
12657
|
{
|
|
11287
12658
|
href: `tel:${hotline.replace(/\D/g, "")}`,
|
|
@@ -11292,10 +12663,10 @@ function FloatingContacts({ className }) {
|
|
|
11292
12663
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
11293
12664
|
"bg-[#22c55e]"
|
|
11294
12665
|
),
|
|
11295
|
-
children: /* @__PURE__ */ (0,
|
|
12666
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(import_lucide_react28.Phone, { className: "w-6 h-6" })
|
|
11296
12667
|
}
|
|
11297
12668
|
),
|
|
11298
|
-
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */ (0,
|
|
12669
|
+
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
|
|
11299
12670
|
import_link2.default,
|
|
11300
12671
|
{
|
|
11301
12672
|
href,
|
|
@@ -11307,7 +12678,7 @@ function FloatingContacts({ className }) {
|
|
|
11307
12678
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
11308
12679
|
bg
|
|
11309
12680
|
),
|
|
11310
|
-
children: /* @__PURE__ */ (0,
|
|
12681
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Icon, { className: "w-6 h-6" })
|
|
11311
12682
|
},
|
|
11312
12683
|
key
|
|
11313
12684
|
))
|
|
@@ -11316,7 +12687,7 @@ function FloatingContacts({ className }) {
|
|
|
11316
12687
|
|
|
11317
12688
|
// ../../components/ui/AccessDenied.tsx
|
|
11318
12689
|
var import_lucide_react29 = require("lucide-react");
|
|
11319
|
-
var
|
|
12690
|
+
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
11320
12691
|
var VARIANT_STYLES = {
|
|
11321
12692
|
destructive: { bg: "bg-destructive/5", border: "border-destructive/20", text: "text-destructive" },
|
|
11322
12693
|
warning: { bg: "bg-warning/5", border: "border-warning/20", text: "text-warning" },
|
|
@@ -11337,32 +12708,32 @@ function AccessDenied({
|
|
|
11337
12708
|
}) {
|
|
11338
12709
|
const styles = VARIANT_STYLES[variant];
|
|
11339
12710
|
const UsedIcon = Icon || DEFAULT_ICONS[variant];
|
|
11340
|
-
return /* @__PURE__ */ (0,
|
|
11341
|
-
/* @__PURE__ */ (0,
|
|
11342
|
-
/* @__PURE__ */ (0,
|
|
11343
|
-
/* @__PURE__ */ (0,
|
|
11344
|
-
/* @__PURE__ */ (0,
|
|
12711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Card_default, { className: cn("p-8 text-center shadow-sm", styles.bg, styles.border, className), children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
12712
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: cn("p-3 rounded-lg", styles.bg.replace("/5", "/10")), children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(UsedIcon, { className: cn("w-8 h-8", styles.text) }) }),
|
|
12713
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { children: [
|
|
12714
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)("h3", { className: cn("font-semibold mb-2", styles.text), children: title }),
|
|
12715
|
+
/* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: cn(styles.text.replace("text-", "text-") + "/80", "text-sm"), children: description })
|
|
11345
12716
|
] }),
|
|
11346
|
-
children && /* @__PURE__ */ (0,
|
|
12717
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "mt-2 flex flex-wrap gap-2 justify-center", children })
|
|
11347
12718
|
] }) });
|
|
11348
12719
|
}
|
|
11349
12720
|
|
|
11350
12721
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
11351
12722
|
var import_lucide_react30 = require("lucide-react");
|
|
11352
|
-
var
|
|
11353
|
-
var
|
|
11354
|
-
var
|
|
12723
|
+
var import_react33 = require("react");
|
|
12724
|
+
var import_react_dom11 = require("react-dom");
|
|
12725
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
11355
12726
|
function ThemeToggleHeadless({
|
|
11356
12727
|
theme,
|
|
11357
12728
|
onChange,
|
|
11358
12729
|
labels,
|
|
11359
12730
|
className
|
|
11360
12731
|
}) {
|
|
11361
|
-
const [isOpen, setIsOpen] = (0,
|
|
11362
|
-
const [mounted, setMounted] = (0,
|
|
11363
|
-
const triggerRef = (0,
|
|
11364
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
11365
|
-
(0,
|
|
12732
|
+
const [isOpen, setIsOpen] = (0, import_react33.useState)(false);
|
|
12733
|
+
const [mounted, setMounted] = (0, import_react33.useState)(false);
|
|
12734
|
+
const triggerRef = (0, import_react33.useRef)(null);
|
|
12735
|
+
const [dropdownPosition, setDropdownPosition] = (0, import_react33.useState)(null);
|
|
12736
|
+
(0, import_react33.useEffect)(() => setMounted(true), []);
|
|
11366
12737
|
const themes = [
|
|
11367
12738
|
{ value: "light", label: labels?.light ?? "Light", icon: import_lucide_react30.Sun },
|
|
11368
12739
|
{ value: "dark", label: labels?.dark ?? "Dark", icon: import_lucide_react30.Moon },
|
|
@@ -11380,8 +12751,8 @@ function ThemeToggleHeadless({
|
|
|
11380
12751
|
const top = rect.bottom + scrollTop + 8;
|
|
11381
12752
|
return { top, left, width };
|
|
11382
12753
|
};
|
|
11383
|
-
return /* @__PURE__ */ (0,
|
|
11384
|
-
/* @__PURE__ */ (0,
|
|
12754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: cn("relative", className), children: [
|
|
12755
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
11385
12756
|
Button_default,
|
|
11386
12757
|
{
|
|
11387
12758
|
variant: "ghost",
|
|
@@ -11399,25 +12770,25 @@ function ThemeToggleHeadless({
|
|
|
11399
12770
|
"aria-haspopup": "menu",
|
|
11400
12771
|
"aria-expanded": isOpen,
|
|
11401
12772
|
"aria-label": labels?.heading ?? "Theme",
|
|
11402
|
-
children: /* @__PURE__ */ (0,
|
|
12773
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(CurrentIcon, { className: "h-5 w-5" })
|
|
11403
12774
|
}
|
|
11404
12775
|
),
|
|
11405
|
-
isOpen && /* @__PURE__ */ (0,
|
|
11406
|
-
typeof window !== "undefined" && (0,
|
|
11407
|
-
typeof window !== "undefined" && dropdownPosition && (0,
|
|
11408
|
-
/* @__PURE__ */ (0,
|
|
12776
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
|
|
12777
|
+
typeof window !== "undefined" && (0, import_react_dom11.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
12778
|
+
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom11.createPortal)(
|
|
12779
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
11409
12780
|
"div",
|
|
11410
12781
|
{
|
|
11411
12782
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
11412
12783
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
11413
12784
|
onMouseDown: (e) => e.stopPropagation(),
|
|
11414
12785
|
role: "menu",
|
|
11415
|
-
children: /* @__PURE__ */ (0,
|
|
11416
|
-
/* @__PURE__ */ (0,
|
|
12786
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "p-2", children: [
|
|
12787
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Theme" }),
|
|
11417
12788
|
themes.map((opt) => {
|
|
11418
12789
|
const Icon = opt.icon;
|
|
11419
12790
|
const active = theme === opt.value;
|
|
11420
|
-
return /* @__PURE__ */ (0,
|
|
12791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
|
|
11421
12792
|
Button_default,
|
|
11422
12793
|
{
|
|
11423
12794
|
variant: "ghost",
|
|
@@ -11433,9 +12804,9 @@ function ThemeToggleHeadless({
|
|
|
11433
12804
|
role: "menuitemradio",
|
|
11434
12805
|
"aria-checked": active,
|
|
11435
12806
|
children: [
|
|
11436
|
-
/* @__PURE__ */ (0,
|
|
11437
|
-
/* @__PURE__ */ (0,
|
|
11438
|
-
active && /* @__PURE__ */ (0,
|
|
12807
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Icon, { className: "h-4 w-4" }),
|
|
12808
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "flex-1 text-left", children: opt.label }),
|
|
12809
|
+
active && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
11439
12810
|
]
|
|
11440
12811
|
},
|
|
11441
12812
|
opt.value
|
|
@@ -11451,10 +12822,10 @@ function ThemeToggleHeadless({
|
|
|
11451
12822
|
}
|
|
11452
12823
|
|
|
11453
12824
|
// ../../components/ui/LanguageSwitcherHeadless.tsx
|
|
11454
|
-
var
|
|
11455
|
-
var
|
|
12825
|
+
var import_react34 = require("react");
|
|
12826
|
+
var import_react_dom12 = require("react-dom");
|
|
11456
12827
|
var import_lucide_react31 = require("lucide-react");
|
|
11457
|
-
var
|
|
12828
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
11458
12829
|
function LanguageSwitcherHeadless({
|
|
11459
12830
|
locales,
|
|
11460
12831
|
currentLocale,
|
|
@@ -11462,9 +12833,9 @@ function LanguageSwitcherHeadless({
|
|
|
11462
12833
|
labels,
|
|
11463
12834
|
className
|
|
11464
12835
|
}) {
|
|
11465
|
-
const [isOpen, setIsOpen] = (0,
|
|
11466
|
-
const [dropdownPosition, setDropdownPosition] = (0,
|
|
11467
|
-
const triggerButtonRef = (0,
|
|
12836
|
+
const [isOpen, setIsOpen] = (0, import_react34.useState)(false);
|
|
12837
|
+
const [dropdownPosition, setDropdownPosition] = (0, import_react34.useState)(null);
|
|
12838
|
+
const triggerButtonRef = (0, import_react34.useRef)(null);
|
|
11468
12839
|
const currentLanguage = locales.find((l) => l.code === currentLocale) || locales[0];
|
|
11469
12840
|
const calculatePosition = () => {
|
|
11470
12841
|
const rect = triggerButtonRef.current?.getBoundingClientRect();
|
|
@@ -11476,8 +12847,8 @@ function LanguageSwitcherHeadless({
|
|
|
11476
12847
|
const top = rect.bottom + scrollTop + 8;
|
|
11477
12848
|
return { top, left, width };
|
|
11478
12849
|
};
|
|
11479
|
-
return /* @__PURE__ */ (0,
|
|
11480
|
-
/* @__PURE__ */ (0,
|
|
12850
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: cn("relative", className), children: [
|
|
12851
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
11481
12852
|
Button_default,
|
|
11482
12853
|
{
|
|
11483
12854
|
variant: "ghost",
|
|
@@ -11496,22 +12867,22 @@ function LanguageSwitcherHeadless({
|
|
|
11496
12867
|
"aria-expanded": isOpen,
|
|
11497
12868
|
"aria-label": labels?.heading ?? "Language",
|
|
11498
12869
|
title: labels?.heading ?? "Language",
|
|
11499
|
-
children: /* @__PURE__ */ (0,
|
|
12870
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react31.Globe, { className: "h-5 w-5" })
|
|
11500
12871
|
}
|
|
11501
12872
|
),
|
|
11502
|
-
isOpen && /* @__PURE__ */ (0,
|
|
11503
|
-
typeof window !== "undefined" && (0,
|
|
11504
|
-
typeof window !== "undefined" && dropdownPosition && (0,
|
|
11505
|
-
/* @__PURE__ */ (0,
|
|
12873
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(import_jsx_runtime62.Fragment, { children: [
|
|
12874
|
+
typeof window !== "undefined" && (0, import_react_dom12.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
12875
|
+
typeof window !== "undefined" && dropdownPosition && (0, import_react_dom12.createPortal)(
|
|
12876
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
11506
12877
|
"div",
|
|
11507
12878
|
{
|
|
11508
12879
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
11509
12880
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
11510
12881
|
onMouseDown: (e) => e.stopPropagation(),
|
|
11511
12882
|
role: "menu",
|
|
11512
|
-
children: /* @__PURE__ */ (0,
|
|
11513
|
-
/* @__PURE__ */ (0,
|
|
11514
|
-
locales.map((language) => /* @__PURE__ */ (0,
|
|
12883
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "p-2", children: [
|
|
12884
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Language" }),
|
|
12885
|
+
locales.map((language) => /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
11515
12886
|
Button_default,
|
|
11516
12887
|
{
|
|
11517
12888
|
variant: "ghost",
|
|
@@ -11524,9 +12895,9 @@ function LanguageSwitcherHeadless({
|
|
|
11524
12895
|
role: "menuitemradio",
|
|
11525
12896
|
"aria-checked": currentLocale === language.code,
|
|
11526
12897
|
children: [
|
|
11527
|
-
language.flag && /* @__PURE__ */ (0,
|
|
11528
|
-
/* @__PURE__ */ (0,
|
|
11529
|
-
currentLocale === language.code && /* @__PURE__ */ (0,
|
|
12898
|
+
language.flag && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "text-lg", children: language.flag }),
|
|
12899
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "flex-1 text-left", children: language.name }),
|
|
12900
|
+
currentLocale === language.code && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
11530
12901
|
]
|
|
11531
12902
|
},
|
|
11532
12903
|
language.code
|
|
@@ -11956,7 +13327,7 @@ var VARIANT_STYLES_ALERT = {
|
|
|
11956
13327
|
};
|
|
11957
13328
|
|
|
11958
13329
|
// src/contexts/TranslationContext.tsx
|
|
11959
|
-
var
|
|
13330
|
+
var React50 = __toESM(require("react"), 1);
|
|
11960
13331
|
|
|
11961
13332
|
// locales/en.json
|
|
11962
13333
|
var en_default = {
|
|
@@ -12211,16 +13582,16 @@ var ja_default = {
|
|
|
12211
13582
|
};
|
|
12212
13583
|
|
|
12213
13584
|
// src/contexts/TranslationContext.tsx
|
|
12214
|
-
var
|
|
13585
|
+
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
12215
13586
|
var defaultTranslations2 = {
|
|
12216
13587
|
en: en_default,
|
|
12217
13588
|
vi: vi_default,
|
|
12218
13589
|
ko: ko_default,
|
|
12219
13590
|
ja: ja_default
|
|
12220
13591
|
};
|
|
12221
|
-
var TranslationContext2 =
|
|
13592
|
+
var TranslationContext2 = React50.createContext(null);
|
|
12222
13593
|
var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
12223
|
-
const t =
|
|
13594
|
+
const t = React50.useCallback(
|
|
12224
13595
|
(namespace) => {
|
|
12225
13596
|
return (key) => {
|
|
12226
13597
|
const mergedTranslations = {
|
|
@@ -12245,10 +13616,10 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
|
12245
13616
|
},
|
|
12246
13617
|
[locale, translations]
|
|
12247
13618
|
);
|
|
12248
|
-
return /* @__PURE__ */ (0,
|
|
13619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TranslationContext2.Provider, { value: { locale, t }, children });
|
|
12249
13620
|
};
|
|
12250
13621
|
var useUnderverseTranslations = (namespace) => {
|
|
12251
|
-
const context =
|
|
13622
|
+
const context = React50.useContext(TranslationContext2);
|
|
12252
13623
|
if (!context) {
|
|
12253
13624
|
return (key) => {
|
|
12254
13625
|
const parts = namespace.split(".");
|
|
@@ -12270,13 +13641,13 @@ var useUnderverseTranslations = (namespace) => {
|
|
|
12270
13641
|
return context.t(namespace);
|
|
12271
13642
|
};
|
|
12272
13643
|
var useUnderverseLocale = () => {
|
|
12273
|
-
const context =
|
|
13644
|
+
const context = React50.useContext(TranslationContext2);
|
|
12274
13645
|
return context?.locale || "en";
|
|
12275
13646
|
};
|
|
12276
13647
|
|
|
12277
13648
|
// src/hooks/useSmartTranslations.tsx
|
|
12278
|
-
var
|
|
12279
|
-
var
|
|
13649
|
+
var React51 = __toESM(require("react"), 1);
|
|
13650
|
+
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
12280
13651
|
var nextIntlHooks = null;
|
|
12281
13652
|
try {
|
|
12282
13653
|
const nextIntl = require("next-intl");
|
|
@@ -12287,12 +13658,12 @@ try {
|
|
|
12287
13658
|
} catch {
|
|
12288
13659
|
nextIntlHooks = null;
|
|
12289
13660
|
}
|
|
12290
|
-
var ForceInternalContext =
|
|
13661
|
+
var ForceInternalContext = React51.createContext(false);
|
|
12291
13662
|
var ForceInternalTranslationsProvider = ({ children }) => {
|
|
12292
|
-
return /* @__PURE__ */ (0,
|
|
13663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(ForceInternalContext.Provider, { value: true, children });
|
|
12293
13664
|
};
|
|
12294
13665
|
function useSmartTranslations(namespace) {
|
|
12295
|
-
const forceInternal =
|
|
13666
|
+
const forceInternal = React51.useContext(ForceInternalContext);
|
|
12296
13667
|
const internalT = useUnderverseTranslations(namespace);
|
|
12297
13668
|
if (forceInternal || !nextIntlHooks?.useTranslations) {
|
|
12298
13669
|
return internalT;
|
|
@@ -12305,7 +13676,7 @@ function useSmartTranslations(namespace) {
|
|
|
12305
13676
|
}
|
|
12306
13677
|
}
|
|
12307
13678
|
function useSmartLocale() {
|
|
12308
|
-
const forceInternal =
|
|
13679
|
+
const forceInternal = React51.useContext(ForceInternalContext);
|
|
12309
13680
|
const internalLocale = useUnderverseLocale();
|
|
12310
13681
|
if (forceInternal || !nextIntlHooks?.useLocale) {
|
|
12311
13682
|
return internalLocale;
|
|
@@ -12327,9 +13698,11 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12327
13698
|
0 && (module.exports = {
|
|
12328
13699
|
AccessDenied,
|
|
12329
13700
|
Alert,
|
|
13701
|
+
AreaChart,
|
|
12330
13702
|
Avatar,
|
|
12331
13703
|
Badge,
|
|
12332
13704
|
BadgeBase,
|
|
13705
|
+
BarChart,
|
|
12333
13706
|
BatteryProgress,
|
|
12334
13707
|
BottomSheet,
|
|
12335
13708
|
Breadcrumb,
|
|
@@ -12367,6 +13740,7 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12367
13740
|
FormLabel,
|
|
12368
13741
|
FormMessage,
|
|
12369
13742
|
FormSubmitButton,
|
|
13743
|
+
GaugeChart,
|
|
12370
13744
|
GlobalLoading,
|
|
12371
13745
|
GradientBadge,
|
|
12372
13746
|
Grid,
|
|
@@ -12378,6 +13752,7 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12378
13752
|
Label,
|
|
12379
13753
|
LanguageSwitcher,
|
|
12380
13754
|
LanguageSwitcherHeadless,
|
|
13755
|
+
LineChart,
|
|
12381
13756
|
List,
|
|
12382
13757
|
ListItem,
|
|
12383
13758
|
LoadingBar,
|
|
@@ -12394,10 +13769,12 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12394
13769
|
PageLoading,
|
|
12395
13770
|
Pagination,
|
|
12396
13771
|
PasswordInput,
|
|
13772
|
+
PieChart,
|
|
12397
13773
|
PillTabs,
|
|
12398
13774
|
Popover,
|
|
12399
13775
|
Progress,
|
|
12400
13776
|
PulseBadge,
|
|
13777
|
+
RadarChart,
|
|
12401
13778
|
RadioGroup,
|
|
12402
13779
|
RadioGroupItem,
|
|
12403
13780
|
SIZE_STYLES_BTN,
|
|
@@ -12422,6 +13799,7 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12422
13799
|
SlideOver,
|
|
12423
13800
|
Slider,
|
|
12424
13801
|
SmartImage,
|
|
13802
|
+
Sparkline,
|
|
12425
13803
|
StatusBadge,
|
|
12426
13804
|
StepProgress,
|
|
12427
13805
|
Switch,
|