@underverse-ui/underverse 0.2.39 → 0.2.41
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/README.md +1 -1
- 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 +2 -2
package/dist/index.js
CHANGED
|
@@ -10274,23 +10274,1387 @@ GridItem.displayName = "Grid.Item";
|
|
|
10274
10274
|
var Grid = Object.assign(GridRoot, { Item: GridItem });
|
|
10275
10275
|
var Grid_default = Grid;
|
|
10276
10276
|
|
|
10277
|
-
// ../../components/ui/
|
|
10277
|
+
// ../../components/ui/LineChart.tsx
|
|
10278
|
+
import { useMemo as useMemo6, useState as useState33, useRef as useRef14 } from "react";
|
|
10279
|
+
|
|
10280
|
+
// ../../components/ui/ChartTooltip.tsx
|
|
10278
10281
|
import { useEffect as useEffect18, useState as useState32 } from "react";
|
|
10279
|
-
import {
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
+
import { createPortal as createPortal10 } from "react-dom";
|
|
10283
|
+
import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
10284
|
+
function ChartTooltip({ x, y, visible, label, value, color, secondaryLabel, secondaryValue, items, containerRef }) {
|
|
10285
|
+
const [isMounted, setIsMounted] = useState32(false);
|
|
10286
|
+
const [position, setPosition] = useState32(null);
|
|
10282
10287
|
useEffect18(() => {
|
|
10288
|
+
setIsMounted(true);
|
|
10289
|
+
}, []);
|
|
10290
|
+
useEffect18(() => {
|
|
10291
|
+
if (visible && containerRef?.current) {
|
|
10292
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
10293
|
+
setPosition({
|
|
10294
|
+
top: rect.top + y,
|
|
10295
|
+
left: rect.left + x
|
|
10296
|
+
});
|
|
10297
|
+
}
|
|
10298
|
+
}, [visible, x, y, containerRef]);
|
|
10299
|
+
if (!visible || !isMounted || !position) return null;
|
|
10300
|
+
const tooltipContent = /* @__PURE__ */ jsxs40(
|
|
10301
|
+
"div",
|
|
10302
|
+
{
|
|
10303
|
+
style: {
|
|
10304
|
+
position: "fixed",
|
|
10305
|
+
top: position.top,
|
|
10306
|
+
left: position.left + 12,
|
|
10307
|
+
zIndex: 99999,
|
|
10308
|
+
pointerEvents: "none",
|
|
10309
|
+
animation: "chartTooltipFadeIn 0.15s ease-out"
|
|
10310
|
+
},
|
|
10311
|
+
children: [
|
|
10312
|
+
/* @__PURE__ */ jsxs40(
|
|
10313
|
+
"div",
|
|
10314
|
+
{
|
|
10315
|
+
className: cn("bg-popover text-popover-foreground border border-border", "rounded-lg shadow-xl px-3 py-2 text-sm", "backdrop-blur-sm"),
|
|
10316
|
+
style: {
|
|
10317
|
+
minWidth: "80px",
|
|
10318
|
+
width: "max-content",
|
|
10319
|
+
boxShadow: "0 10px 25px -3px rgba(0, 0, 0, 0.5), 0 4px 10px -2px rgba(0, 0, 0, 0.3)"
|
|
10320
|
+
},
|
|
10321
|
+
children: [
|
|
10322
|
+
label && /* @__PURE__ */ jsx45("div", { className: "text-muted-foreground text-xs mb-1", children: label }),
|
|
10323
|
+
items && items.length > 0 ? /* @__PURE__ */ jsx45("div", { className: "flex flex-col gap-1", children: items.map((item, i) => /* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-2", children: [
|
|
10324
|
+
item.color && /* @__PURE__ */ jsx45("div", { className: "w-2 h-2 rounded-full shrink-0", style: { backgroundColor: item.color } }),
|
|
10325
|
+
/* @__PURE__ */ jsxs40("span", { className: "text-muted-foreground", children: [
|
|
10326
|
+
item.label,
|
|
10327
|
+
":"
|
|
10328
|
+
] }),
|
|
10329
|
+
/* @__PURE__ */ jsx45("span", { className: "font-semibold ml-auto", children: item.value })
|
|
10330
|
+
] }, i)) }) : /* @__PURE__ */ jsxs40(Fragment16, { children: [
|
|
10331
|
+
/* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-2", children: [
|
|
10332
|
+
color && /* @__PURE__ */ jsx45("div", { className: "w-2 h-2 rounded-full shrink-0", style: { backgroundColor: color } }),
|
|
10333
|
+
/* @__PURE__ */ jsx45("span", { className: "font-semibold", children: value })
|
|
10334
|
+
] }),
|
|
10335
|
+
secondaryLabel && /* @__PURE__ */ jsxs40("div", { className: "text-muted-foreground text-xs mt-1", children: [
|
|
10336
|
+
secondaryLabel,
|
|
10337
|
+
": ",
|
|
10338
|
+
secondaryValue
|
|
10339
|
+
] })
|
|
10340
|
+
] })
|
|
10341
|
+
]
|
|
10342
|
+
}
|
|
10343
|
+
),
|
|
10344
|
+
/* @__PURE__ */ jsx45("style", { children: `
|
|
10345
|
+
@keyframes chartTooltipFadeIn {
|
|
10346
|
+
from { opacity: 0; transform: translateX(-5px); }
|
|
10347
|
+
to { opacity: 1; transform: translateX(0); }
|
|
10348
|
+
}
|
|
10349
|
+
` })
|
|
10350
|
+
]
|
|
10351
|
+
}
|
|
10352
|
+
);
|
|
10353
|
+
return createPortal10(tooltipContent, document.body);
|
|
10354
|
+
}
|
|
10355
|
+
|
|
10356
|
+
// ../../components/ui/LineChart.tsx
|
|
10357
|
+
import { Fragment as Fragment17, jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
10358
|
+
function LineChart({
|
|
10359
|
+
data,
|
|
10360
|
+
width = 400,
|
|
10361
|
+
height = 200,
|
|
10362
|
+
color = "currentColor",
|
|
10363
|
+
fillColor,
|
|
10364
|
+
showDots = true,
|
|
10365
|
+
showGrid = true,
|
|
10366
|
+
showLabels = true,
|
|
10367
|
+
showValues = false,
|
|
10368
|
+
animated = true,
|
|
10369
|
+
curved = true,
|
|
10370
|
+
className = ""
|
|
10371
|
+
}) {
|
|
10372
|
+
const svgRef = useRef14(null);
|
|
10373
|
+
const padding = { top: 20, right: 20, bottom: 40, left: 40 };
|
|
10374
|
+
const chartWidth = width - padding.left - padding.right;
|
|
10375
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
10376
|
+
const [hoveredPoint, setHoveredPoint] = useState33(null);
|
|
10377
|
+
const { minValue, maxValue, points, linePath, areaPath } = useMemo6(() => {
|
|
10378
|
+
if (!data.length) return { minValue: 0, maxValue: 0, points: [], linePath: "", areaPath: "" };
|
|
10379
|
+
const values = data.map((d) => d.value);
|
|
10380
|
+
const min = Math.min(...values);
|
|
10381
|
+
const max = Math.max(...values);
|
|
10382
|
+
const range = max - min || 1;
|
|
10383
|
+
const pts = data.map((d, i) => ({
|
|
10384
|
+
x: padding.left + i / (data.length - 1 || 1) * chartWidth,
|
|
10385
|
+
y: padding.top + chartHeight - (d.value - min) / range * chartHeight,
|
|
10386
|
+
...d
|
|
10387
|
+
}));
|
|
10388
|
+
let path = "";
|
|
10389
|
+
let area = "";
|
|
10390
|
+
if (curved && pts.length > 2) {
|
|
10391
|
+
path = `M ${pts[0].x} ${pts[0].y}`;
|
|
10392
|
+
area = `M ${pts[0].x} ${padding.top + chartHeight} L ${pts[0].x} ${pts[0].y}`;
|
|
10393
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
10394
|
+
const p0 = pts[Math.max(0, i - 1)];
|
|
10395
|
+
const p1 = pts[i];
|
|
10396
|
+
const p2 = pts[i + 1];
|
|
10397
|
+
const p3 = pts[Math.min(pts.length - 1, i + 2)];
|
|
10398
|
+
const cp1x = p1.x + (p2.x - p0.x) / 6;
|
|
10399
|
+
const cp1y = p1.y + (p2.y - p0.y) / 6;
|
|
10400
|
+
const cp2x = p2.x - (p3.x - p1.x) / 6;
|
|
10401
|
+
const cp2y = p2.y - (p3.y - p1.y) / 6;
|
|
10402
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
10403
|
+
area += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
10404
|
+
}
|
|
10405
|
+
area += ` L ${pts[pts.length - 1].x} ${padding.top + chartHeight} Z`;
|
|
10406
|
+
} else {
|
|
10407
|
+
path = pts.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
|
|
10408
|
+
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`;
|
|
10409
|
+
}
|
|
10410
|
+
return { minValue: min, maxValue: max, points: pts, linePath: path, areaPath: area };
|
|
10411
|
+
}, [data, chartWidth, chartHeight, curved, padding.left, padding.top]);
|
|
10412
|
+
const gridLines = useMemo6(() => {
|
|
10413
|
+
const lines = [];
|
|
10414
|
+
const steps = 5;
|
|
10415
|
+
for (let i = 0; i <= steps; i++) {
|
|
10416
|
+
const y = padding.top + i / steps * chartHeight;
|
|
10417
|
+
const value = maxValue - i / steps * (maxValue - minValue);
|
|
10418
|
+
lines.push({ y, value });
|
|
10419
|
+
}
|
|
10420
|
+
return lines;
|
|
10421
|
+
}, [minValue, maxValue, chartHeight, padding.top]);
|
|
10422
|
+
return /* @__PURE__ */ jsxs41(Fragment17, { children: [
|
|
10423
|
+
/* @__PURE__ */ jsxs41("svg", { ref: svgRef, width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
10424
|
+
showGrid && /* @__PURE__ */ jsx46("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ jsxs41("g", { children: [
|
|
10425
|
+
/* @__PURE__ */ jsx46("line", { x1: padding.left, y1: line.y, x2: width - padding.right, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10426
|
+
/* @__PURE__ */ jsx46("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", fill: "currentColor", className: "text-muted-foreground", children: line.value.toFixed(0) })
|
|
10427
|
+
] }, i)) }),
|
|
10428
|
+
fillColor && areaPath && /* @__PURE__ */ jsx46("path", { d: areaPath, fill: fillColor, opacity: 0.2, className: animated ? "animate-[fadeIn_0.6s_ease-out]" : "" }),
|
|
10429
|
+
linePath && /* @__PURE__ */ jsx46(
|
|
10430
|
+
"path",
|
|
10431
|
+
{
|
|
10432
|
+
d: linePath,
|
|
10433
|
+
fill: "none",
|
|
10434
|
+
stroke: color,
|
|
10435
|
+
strokeWidth: 2,
|
|
10436
|
+
strokeLinecap: "round",
|
|
10437
|
+
strokeLinejoin: "round",
|
|
10438
|
+
className: animated ? "animate-[drawLine_1s_ease-out]" : "",
|
|
10439
|
+
style: animated ? {
|
|
10440
|
+
strokeDasharray: 1e3,
|
|
10441
|
+
strokeDashoffset: 0,
|
|
10442
|
+
animation: "drawLine 1s ease-out forwards"
|
|
10443
|
+
} : void 0
|
|
10444
|
+
}
|
|
10445
|
+
),
|
|
10446
|
+
showDots && points.map((point, i) => /* @__PURE__ */ jsxs41(
|
|
10447
|
+
"g",
|
|
10448
|
+
{
|
|
10449
|
+
onMouseEnter: () => setHoveredPoint({ x: point.x, y: point.y, label: point.label, value: point.value }),
|
|
10450
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
10451
|
+
className: "cursor-pointer",
|
|
10452
|
+
children: [
|
|
10453
|
+
/* @__PURE__ */ jsx46(
|
|
10454
|
+
"circle",
|
|
10455
|
+
{
|
|
10456
|
+
cx: point.x,
|
|
10457
|
+
cy: point.y,
|
|
10458
|
+
r: hoveredPoint?.x === point.x ? 6 : 4,
|
|
10459
|
+
fill: color,
|
|
10460
|
+
className: `transition-all duration-150 ${animated ? "animate-[scaleIn_0.3s_ease-out]" : ""}`,
|
|
10461
|
+
style: animated ? { animationDelay: `${i * 0.05}s`, animationFillMode: "both" } : void 0
|
|
10462
|
+
}
|
|
10463
|
+
),
|
|
10464
|
+
/* @__PURE__ */ jsx46("circle", { cx: point.x, cy: point.y, r: 16, fill: "transparent" }),
|
|
10465
|
+
showValues && /* @__PURE__ */ jsx46("text", { x: point.x, y: point.y - 12, textAnchor: "middle", fontSize: "10", fontWeight: "500", className: "text-foreground", fill: "currentColor", children: point.value })
|
|
10466
|
+
]
|
|
10467
|
+
},
|
|
10468
|
+
i
|
|
10469
|
+
)),
|
|
10470
|
+
hoveredPoint && /* @__PURE__ */ jsxs41("g", { className: "pointer-events-none", children: [
|
|
10471
|
+
/* @__PURE__ */ jsx46(
|
|
10472
|
+
"line",
|
|
10473
|
+
{
|
|
10474
|
+
x1: hoveredPoint.x,
|
|
10475
|
+
y1: padding.top,
|
|
10476
|
+
x2: hoveredPoint.x,
|
|
10477
|
+
y2: padding.top + chartHeight,
|
|
10478
|
+
stroke: color,
|
|
10479
|
+
strokeWidth: 1,
|
|
10480
|
+
strokeDasharray: "4 4",
|
|
10481
|
+
opacity: 0.5
|
|
10482
|
+
}
|
|
10483
|
+
),
|
|
10484
|
+
/* @__PURE__ */ jsx46(
|
|
10485
|
+
"line",
|
|
10486
|
+
{
|
|
10487
|
+
x1: padding.left,
|
|
10488
|
+
y1: hoveredPoint.y,
|
|
10489
|
+
x2: padding.left + chartWidth,
|
|
10490
|
+
y2: hoveredPoint.y,
|
|
10491
|
+
stroke: color,
|
|
10492
|
+
strokeWidth: 1,
|
|
10493
|
+
strokeDasharray: "4 4",
|
|
10494
|
+
opacity: 0.5
|
|
10495
|
+
}
|
|
10496
|
+
)
|
|
10497
|
+
] }),
|
|
10498
|
+
showLabels && points.map((point, i) => /* @__PURE__ */ jsx46("text", { x: point.x, y: height - 10, textAnchor: "middle", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: point.label }, i)),
|
|
10499
|
+
/* @__PURE__ */ jsx46("style", { children: `
|
|
10500
|
+
@keyframes drawLine {
|
|
10501
|
+
from { stroke-dashoffset: 1000; }
|
|
10502
|
+
to { stroke-dashoffset: 0; }
|
|
10503
|
+
}
|
|
10504
|
+
@keyframes scaleIn {
|
|
10505
|
+
from { transform: scale(0); opacity: 0; }
|
|
10506
|
+
to { transform: scale(1); opacity: 1; }
|
|
10507
|
+
}
|
|
10508
|
+
@keyframes fadeIn {
|
|
10509
|
+
from { opacity: 0; }
|
|
10510
|
+
to { opacity: 0.2; }
|
|
10511
|
+
}
|
|
10512
|
+
` })
|
|
10513
|
+
] }),
|
|
10514
|
+
/* @__PURE__ */ jsx46(
|
|
10515
|
+
ChartTooltip,
|
|
10516
|
+
{
|
|
10517
|
+
x: hoveredPoint?.x ?? 0,
|
|
10518
|
+
y: hoveredPoint?.y ?? 0,
|
|
10519
|
+
visible: !!hoveredPoint,
|
|
10520
|
+
label: hoveredPoint?.label,
|
|
10521
|
+
value: hoveredPoint?.value,
|
|
10522
|
+
color,
|
|
10523
|
+
containerRef: svgRef
|
|
10524
|
+
}
|
|
10525
|
+
)
|
|
10526
|
+
] });
|
|
10527
|
+
}
|
|
10528
|
+
|
|
10529
|
+
// ../../components/ui/BarChart.tsx
|
|
10530
|
+
import { useMemo as useMemo7, useState as useState34, useRef as useRef15 } from "react";
|
|
10531
|
+
import { Fragment as Fragment18, jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
10532
|
+
function BarChart({
|
|
10533
|
+
data,
|
|
10534
|
+
width = 400,
|
|
10535
|
+
height = 200,
|
|
10536
|
+
color = "currentColor",
|
|
10537
|
+
showLabels = true,
|
|
10538
|
+
showValues = true,
|
|
10539
|
+
showGrid = true,
|
|
10540
|
+
horizontal = false,
|
|
10541
|
+
animated = true,
|
|
10542
|
+
barRadius = 4,
|
|
10543
|
+
barGap = 0.3,
|
|
10544
|
+
className = ""
|
|
10545
|
+
}) {
|
|
10546
|
+
const svgRef = useRef15(null);
|
|
10547
|
+
const padding = horizontal ? { top: 20, right: 40, bottom: 20, left: 80 } : { top: 20, right: 20, bottom: 40, left: 40 };
|
|
10548
|
+
const chartWidth = width - padding.left - padding.right;
|
|
10549
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
10550
|
+
const [hoveredBar, setHoveredBar] = useState34(null);
|
|
10551
|
+
const { maxValue, bars, gridLines } = useMemo7(() => {
|
|
10552
|
+
if (!data.length) return { maxValue: 0, bars: [], gridLines: [] };
|
|
10553
|
+
const max = Math.max(...data.map((d) => d.value));
|
|
10554
|
+
const barCount = data.length;
|
|
10555
|
+
const barsData = data.map((d, i) => {
|
|
10556
|
+
if (horizontal) {
|
|
10557
|
+
const barHeight = chartHeight / barCount * (1 - barGap);
|
|
10558
|
+
const gap = chartHeight / barCount * barGap;
|
|
10559
|
+
return {
|
|
10560
|
+
x: padding.left,
|
|
10561
|
+
y: padding.top + i * (barHeight + gap) + gap / 2,
|
|
10562
|
+
width: d.value / max * chartWidth,
|
|
10563
|
+
height: barHeight,
|
|
10564
|
+
...d
|
|
10565
|
+
};
|
|
10566
|
+
} else {
|
|
10567
|
+
const barWidth = chartWidth / barCount * (1 - barGap);
|
|
10568
|
+
const gap = chartWidth / barCount * barGap;
|
|
10569
|
+
return {
|
|
10570
|
+
x: padding.left + i * (barWidth + gap) + gap / 2,
|
|
10571
|
+
y: padding.top + chartHeight - d.value / max * chartHeight,
|
|
10572
|
+
width: barWidth,
|
|
10573
|
+
height: d.value / max * chartHeight,
|
|
10574
|
+
...d
|
|
10575
|
+
};
|
|
10576
|
+
}
|
|
10577
|
+
});
|
|
10578
|
+
const lines = [];
|
|
10579
|
+
const steps = 5;
|
|
10580
|
+
for (let i = 0; i <= steps; i++) {
|
|
10581
|
+
const value = i / steps * max;
|
|
10582
|
+
if (horizontal) {
|
|
10583
|
+
lines.push({
|
|
10584
|
+
x: padding.left + i / steps * chartWidth,
|
|
10585
|
+
y1: padding.top,
|
|
10586
|
+
y2: height - padding.bottom,
|
|
10587
|
+
value
|
|
10588
|
+
});
|
|
10589
|
+
} else {
|
|
10590
|
+
lines.push({
|
|
10591
|
+
y: padding.top + chartHeight - i / steps * chartHeight,
|
|
10592
|
+
x1: padding.left,
|
|
10593
|
+
x2: width - padding.right,
|
|
10594
|
+
value
|
|
10595
|
+
});
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
return { maxValue: max, bars: barsData, gridLines: lines };
|
|
10599
|
+
}, [data, chartWidth, chartHeight, horizontal, barGap, padding, width, height]);
|
|
10600
|
+
return /* @__PURE__ */ jsxs42(Fragment18, { children: [
|
|
10601
|
+
/* @__PURE__ */ jsxs42("svg", { ref: svgRef, width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
10602
|
+
showGrid && /* @__PURE__ */ jsx47("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ jsx47("g", { children: horizontal ? /* @__PURE__ */ jsxs42(Fragment18, { children: [
|
|
10603
|
+
/* @__PURE__ */ jsx47("line", { x1: line.x, y1: line.y1, x2: line.x, y2: line.y2, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10604
|
+
/* @__PURE__ */ jsx47("text", { x: line.x, y: height - 8, textAnchor: "middle", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
10605
|
+
] }) : /* @__PURE__ */ jsxs42(Fragment18, { children: [
|
|
10606
|
+
/* @__PURE__ */ jsx47("line", { x1: line.x1, y1: line.y, x2: line.x2, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10607
|
+
/* @__PURE__ */ jsx47("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
10608
|
+
] }) }, i)) }),
|
|
10609
|
+
bars.map((bar, i) => /* @__PURE__ */ jsxs42(
|
|
10610
|
+
"g",
|
|
10611
|
+
{
|
|
10612
|
+
onMouseEnter: () => setHoveredBar({
|
|
10613
|
+
x: horizontal ? bar.x + bar.width : bar.x + bar.width / 2,
|
|
10614
|
+
y: horizontal ? bar.y + bar.height / 2 : bar.y,
|
|
10615
|
+
label: bar.label,
|
|
10616
|
+
value: bar.value,
|
|
10617
|
+
color: bar.color || color
|
|
10618
|
+
}),
|
|
10619
|
+
onMouseLeave: () => setHoveredBar(null),
|
|
10620
|
+
className: "cursor-pointer",
|
|
10621
|
+
children: [
|
|
10622
|
+
/* @__PURE__ */ jsxs42(
|
|
10623
|
+
"rect",
|
|
10624
|
+
{
|
|
10625
|
+
x: bar.x,
|
|
10626
|
+
y: horizontal ? bar.y : bar.y,
|
|
10627
|
+
width: animated && !horizontal ? 0 : bar.width,
|
|
10628
|
+
height: animated && horizontal ? bar.height : horizontal ? bar.height : 0,
|
|
10629
|
+
rx: barRadius,
|
|
10630
|
+
ry: barRadius,
|
|
10631
|
+
fill: bar.color || color,
|
|
10632
|
+
className: `transition-all duration-150 ${hoveredBar?.label === bar.label ? "opacity-80" : ""}`,
|
|
10633
|
+
style: animated ? {
|
|
10634
|
+
animation: horizontal ? `growWidth 0.5s ease-out ${i * 0.1}s forwards` : `growHeight 0.5s ease-out ${i * 0.1}s forwards`,
|
|
10635
|
+
...horizontal ? { width: 0 } : { height: 0, y: padding.top + chartHeight }
|
|
10636
|
+
} : void 0,
|
|
10637
|
+
children: [
|
|
10638
|
+
/* @__PURE__ */ jsx47(
|
|
10639
|
+
"animate",
|
|
10640
|
+
{
|
|
10641
|
+
attributeName: horizontal ? "width" : "height",
|
|
10642
|
+
from: "0",
|
|
10643
|
+
to: horizontal ? bar.width : bar.height,
|
|
10644
|
+
dur: "0.5s",
|
|
10645
|
+
begin: `${i * 0.1}s`,
|
|
10646
|
+
fill: "freeze"
|
|
10647
|
+
}
|
|
10648
|
+
),
|
|
10649
|
+
!horizontal && /* @__PURE__ */ jsx47("animate", { attributeName: "y", from: padding.top + chartHeight, to: bar.y, dur: "0.5s", begin: `${i * 0.1}s`, fill: "freeze" })
|
|
10650
|
+
]
|
|
10651
|
+
}
|
|
10652
|
+
),
|
|
10653
|
+
showValues && /* @__PURE__ */ jsx47(
|
|
10654
|
+
"text",
|
|
10655
|
+
{
|
|
10656
|
+
x: horizontal ? bar.x + bar.width + 8 : bar.x + bar.width / 2,
|
|
10657
|
+
y: horizontal ? bar.y + bar.height / 2 + 4 : bar.y - 8,
|
|
10658
|
+
textAnchor: horizontal ? "start" : "middle",
|
|
10659
|
+
fontSize: "11",
|
|
10660
|
+
fontWeight: "500",
|
|
10661
|
+
className: "text-foreground",
|
|
10662
|
+
fill: "currentColor",
|
|
10663
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
10664
|
+
children: bar.value
|
|
10665
|
+
}
|
|
10666
|
+
),
|
|
10667
|
+
showLabels && /* @__PURE__ */ jsx47(
|
|
10668
|
+
"text",
|
|
10669
|
+
{
|
|
10670
|
+
x: horizontal ? padding.left - 8 : bar.x + bar.width / 2,
|
|
10671
|
+
y: horizontal ? bar.y + bar.height / 2 + 4 : height - 10,
|
|
10672
|
+
textAnchor: horizontal ? "end" : "middle",
|
|
10673
|
+
fontSize: "10",
|
|
10674
|
+
className: "text-muted-foreground",
|
|
10675
|
+
fill: "currentColor",
|
|
10676
|
+
children: bar.label
|
|
10677
|
+
}
|
|
10678
|
+
)
|
|
10679
|
+
]
|
|
10680
|
+
},
|
|
10681
|
+
i
|
|
10682
|
+
)),
|
|
10683
|
+
/* @__PURE__ */ jsx47("style", { children: `
|
|
10684
|
+
@keyframes growHeight {
|
|
10685
|
+
from { height: 0; }
|
|
10686
|
+
}
|
|
10687
|
+
@keyframes growWidth {
|
|
10688
|
+
from { width: 0; }
|
|
10689
|
+
}
|
|
10690
|
+
@keyframes fadeIn {
|
|
10691
|
+
from { opacity: 0; }
|
|
10692
|
+
to { opacity: 1; }
|
|
10693
|
+
}
|
|
10694
|
+
` })
|
|
10695
|
+
] }),
|
|
10696
|
+
/* @__PURE__ */ jsx47(
|
|
10697
|
+
ChartTooltip,
|
|
10698
|
+
{
|
|
10699
|
+
x: hoveredBar?.x ?? 0,
|
|
10700
|
+
y: hoveredBar?.y ?? 0,
|
|
10701
|
+
visible: !!hoveredBar,
|
|
10702
|
+
label: hoveredBar?.label,
|
|
10703
|
+
value: hoveredBar?.value,
|
|
10704
|
+
color: hoveredBar?.color,
|
|
10705
|
+
containerRef: svgRef
|
|
10706
|
+
}
|
|
10707
|
+
)
|
|
10708
|
+
] });
|
|
10709
|
+
}
|
|
10710
|
+
|
|
10711
|
+
// ../../components/ui/PieChart.tsx
|
|
10712
|
+
import { useMemo as useMemo8, useState as useState35, useRef as useRef16 } from "react";
|
|
10713
|
+
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
10714
|
+
function PieChart({
|
|
10715
|
+
data,
|
|
10716
|
+
size = 200,
|
|
10717
|
+
donut = false,
|
|
10718
|
+
donutWidth = 40,
|
|
10719
|
+
showLabels = true,
|
|
10720
|
+
showLegend = true,
|
|
10721
|
+
showPercentage = true,
|
|
10722
|
+
animated = true,
|
|
10723
|
+
startAngle = -90,
|
|
10724
|
+
className = ""
|
|
10725
|
+
}) {
|
|
10726
|
+
const containerRef = useRef16(null);
|
|
10727
|
+
const center = size / 2;
|
|
10728
|
+
const radius = size / 2 - 10;
|
|
10729
|
+
const innerRadius = donut ? radius - donutWidth : 0;
|
|
10730
|
+
const { segments, total } = useMemo8(() => {
|
|
10731
|
+
if (!data.length) return { segments: [], total: 0 };
|
|
10732
|
+
const sum = data.reduce((acc, d) => acc + d.value, 0);
|
|
10733
|
+
let currentAngle = startAngle;
|
|
10734
|
+
const segs = data.map((d, i) => {
|
|
10735
|
+
const percentage = d.value / sum;
|
|
10736
|
+
const angle = percentage * 360;
|
|
10737
|
+
const startRad = currentAngle * Math.PI / 180;
|
|
10738
|
+
const endRad = (currentAngle + angle) * Math.PI / 180;
|
|
10739
|
+
const midRad = (currentAngle + angle / 2) * Math.PI / 180;
|
|
10740
|
+
const largeArc = angle > 180 ? 1 : 0;
|
|
10741
|
+
const x1 = center + radius * Math.cos(startRad);
|
|
10742
|
+
const y1 = center + radius * Math.sin(startRad);
|
|
10743
|
+
const x2 = center + radius * Math.cos(endRad);
|
|
10744
|
+
const y2 = center + radius * Math.sin(endRad);
|
|
10745
|
+
const x3 = center + innerRadius * Math.cos(endRad);
|
|
10746
|
+
const y3 = center + innerRadius * Math.sin(endRad);
|
|
10747
|
+
const x4 = center + innerRadius * Math.cos(startRad);
|
|
10748
|
+
const y4 = center + innerRadius * Math.sin(startRad);
|
|
10749
|
+
const labelRadius = radius + 20;
|
|
10750
|
+
const labelX = center + labelRadius * Math.cos(midRad);
|
|
10751
|
+
const labelY = center + labelRadius * Math.sin(midRad);
|
|
10752
|
+
let path;
|
|
10753
|
+
if (donut) {
|
|
10754
|
+
path = [
|
|
10755
|
+
`M ${x1} ${y1}`,
|
|
10756
|
+
`A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`,
|
|
10757
|
+
`L ${x3} ${y3}`,
|
|
10758
|
+
`A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${x4} ${y4}`,
|
|
10759
|
+
"Z"
|
|
10760
|
+
].join(" ");
|
|
10761
|
+
} else {
|
|
10762
|
+
path = [`M ${center} ${center}`, `L ${x1} ${y1}`, `A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2}`, "Z"].join(" ");
|
|
10763
|
+
}
|
|
10764
|
+
currentAngle += angle;
|
|
10765
|
+
return {
|
|
10766
|
+
path,
|
|
10767
|
+
...d,
|
|
10768
|
+
percentage,
|
|
10769
|
+
labelX,
|
|
10770
|
+
labelY,
|
|
10771
|
+
midAngle: currentAngle - angle / 2
|
|
10772
|
+
};
|
|
10773
|
+
});
|
|
10774
|
+
return { segments: segs, total: sum };
|
|
10775
|
+
}, [data, center, radius, innerRadius, donut, startAngle]);
|
|
10776
|
+
const [hoveredSegment, setHoveredSegment] = useState35(null);
|
|
10777
|
+
return /* @__PURE__ */ jsxs43("div", { ref: containerRef, className: `relative flex items-center gap-6 ${className}`, children: [
|
|
10778
|
+
/* @__PURE__ */ jsxs43("svg", { width: size + 40, height: size + 40, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
10779
|
+
/* @__PURE__ */ jsxs43("g", { transform: `translate(20, 20)`, children: [
|
|
10780
|
+
segments.map((seg, i) => /* @__PURE__ */ jsxs43(
|
|
10781
|
+
"g",
|
|
10782
|
+
{
|
|
10783
|
+
onMouseEnter: () => setHoveredSegment({
|
|
10784
|
+
x: seg.labelX + 20,
|
|
10785
|
+
y: seg.labelY + 20,
|
|
10786
|
+
label: seg.label,
|
|
10787
|
+
value: seg.value,
|
|
10788
|
+
percentage: seg.percentage,
|
|
10789
|
+
color: seg.color
|
|
10790
|
+
}),
|
|
10791
|
+
onMouseLeave: () => setHoveredSegment(null),
|
|
10792
|
+
children: [
|
|
10793
|
+
/* @__PURE__ */ jsx48(
|
|
10794
|
+
"path",
|
|
10795
|
+
{
|
|
10796
|
+
d: seg.path,
|
|
10797
|
+
fill: seg.color,
|
|
10798
|
+
className: `transition-all duration-150 cursor-pointer ${hoveredSegment?.label === seg.label ? "opacity-80" : ""}`,
|
|
10799
|
+
style: {
|
|
10800
|
+
transformOrigin: `${center}px ${center}px`,
|
|
10801
|
+
transform: hoveredSegment?.label === seg.label ? "scale(1.05)" : "scale(1)",
|
|
10802
|
+
...animated ? {
|
|
10803
|
+
opacity: hoveredSegment?.label === seg.label ? 0.8 : 0,
|
|
10804
|
+
animation: `pieSlice 0.5s ease-out ${i * 0.1}s forwards`
|
|
10805
|
+
} : void 0
|
|
10806
|
+
}
|
|
10807
|
+
}
|
|
10808
|
+
),
|
|
10809
|
+
showLabels && /* @__PURE__ */ jsx48(
|
|
10810
|
+
"text",
|
|
10811
|
+
{
|
|
10812
|
+
x: seg.labelX,
|
|
10813
|
+
y: seg.labelY,
|
|
10814
|
+
textAnchor: seg.labelX > center ? "start" : "end",
|
|
10815
|
+
fontSize: "10",
|
|
10816
|
+
className: "text-foreground",
|
|
10817
|
+
fill: "currentColor",
|
|
10818
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
10819
|
+
children: showPercentage ? `${(seg.percentage * 100).toFixed(0)}%` : seg.value
|
|
10820
|
+
}
|
|
10821
|
+
)
|
|
10822
|
+
]
|
|
10823
|
+
},
|
|
10824
|
+
i
|
|
10825
|
+
)),
|
|
10826
|
+
donut && /* @__PURE__ */ jsxs43("g", { children: [
|
|
10827
|
+
/* @__PURE__ */ jsx48("text", { x: center, y: center - 5, textAnchor: "middle", fontSize: "12", className: "text-muted-foreground", fill: "currentColor", children: "Total" }),
|
|
10828
|
+
/* @__PURE__ */ jsx48("text", { x: center, y: center + 15, textAnchor: "middle", fontSize: "18", fontWeight: "600", className: "text-foreground", fill: "currentColor", children: total })
|
|
10829
|
+
] })
|
|
10830
|
+
] }),
|
|
10831
|
+
/* @__PURE__ */ jsx48("style", { children: `
|
|
10832
|
+
@keyframes pieSlice {
|
|
10833
|
+
from {
|
|
10834
|
+
opacity: 0;
|
|
10835
|
+
transform: scale(0);
|
|
10836
|
+
}
|
|
10837
|
+
to {
|
|
10838
|
+
opacity: 1;
|
|
10839
|
+
transform: scale(1);
|
|
10840
|
+
}
|
|
10841
|
+
}
|
|
10842
|
+
@keyframes fadeIn {
|
|
10843
|
+
from { opacity: 0; }
|
|
10844
|
+
to { opacity: 1; }
|
|
10845
|
+
}
|
|
10846
|
+
` })
|
|
10847
|
+
] }),
|
|
10848
|
+
showLegend && /* @__PURE__ */ jsx48("div", { className: "flex flex-col gap-2", children: segments.map((seg, i) => /* @__PURE__ */ jsxs43(
|
|
10849
|
+
"div",
|
|
10850
|
+
{
|
|
10851
|
+
className: "flex items-center gap-2 text-sm",
|
|
10852
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.3}s forwards` } : void 0,
|
|
10853
|
+
children: [
|
|
10854
|
+
/* @__PURE__ */ jsx48("div", { className: "w-3 h-3 rounded-sm shrink-0", style: { backgroundColor: seg.color } }),
|
|
10855
|
+
/* @__PURE__ */ jsx48("span", { className: "text-muted-foreground", children: seg.label }),
|
|
10856
|
+
/* @__PURE__ */ jsx48("span", { className: "text-foreground font-medium ml-auto", children: showPercentage ? `${(seg.percentage * 100).toFixed(0)}%` : seg.value })
|
|
10857
|
+
]
|
|
10858
|
+
},
|
|
10859
|
+
i
|
|
10860
|
+
)) }),
|
|
10861
|
+
/* @__PURE__ */ jsx48(
|
|
10862
|
+
ChartTooltip,
|
|
10863
|
+
{
|
|
10864
|
+
x: hoveredSegment?.x ?? center,
|
|
10865
|
+
y: hoveredSegment?.y ?? center,
|
|
10866
|
+
visible: !!hoveredSegment,
|
|
10867
|
+
label: hoveredSegment?.label,
|
|
10868
|
+
value: `${hoveredSegment?.value} (${((hoveredSegment?.percentage ?? 0) * 100).toFixed(1)}%)`,
|
|
10869
|
+
color: hoveredSegment?.color,
|
|
10870
|
+
containerRef
|
|
10871
|
+
}
|
|
10872
|
+
)
|
|
10873
|
+
] });
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10876
|
+
// ../../components/ui/AreaChart.tsx
|
|
10877
|
+
import { useMemo as useMemo9, useState as useState36, useRef as useRef17 } from "react";
|
|
10878
|
+
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
10879
|
+
function getCatmullRomSpline(points) {
|
|
10880
|
+
if (points.length < 2) return "";
|
|
10881
|
+
if (points.length === 2) {
|
|
10882
|
+
return `M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y}`;
|
|
10883
|
+
}
|
|
10884
|
+
let path = `M ${points[0].x} ${points[0].y}`;
|
|
10885
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
10886
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
10887
|
+
const p1 = points[i];
|
|
10888
|
+
const p2 = points[i + 1];
|
|
10889
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
10890
|
+
const tension = 0.5;
|
|
10891
|
+
const cp1x = p1.x + (p2.x - p0.x) * tension / 6;
|
|
10892
|
+
const cp1y = p1.y + (p2.y - p0.y) * tension / 6;
|
|
10893
|
+
const cp2x = p2.x - (p3.x - p1.x) * tension / 6;
|
|
10894
|
+
const cp2y = p2.y - (p3.y - p1.y) * tension / 6;
|
|
10895
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
10896
|
+
}
|
|
10897
|
+
return path;
|
|
10898
|
+
}
|
|
10899
|
+
function AreaChart({
|
|
10900
|
+
series,
|
|
10901
|
+
width = 400,
|
|
10902
|
+
height = 200,
|
|
10903
|
+
showDots = true,
|
|
10904
|
+
showGrid = true,
|
|
10905
|
+
showLabels = true,
|
|
10906
|
+
showLegend = true,
|
|
10907
|
+
animated = true,
|
|
10908
|
+
stacked = false,
|
|
10909
|
+
curved = true,
|
|
10910
|
+
className = ""
|
|
10911
|
+
}) {
|
|
10912
|
+
const containerRef = useRef17(null);
|
|
10913
|
+
const padding = { top: 20, right: 20, bottom: 40, left: 50 };
|
|
10914
|
+
const chartWidth = width - padding.left - padding.right;
|
|
10915
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
10916
|
+
const [hoveredPoint, setHoveredPoint] = useState36(null);
|
|
10917
|
+
const { processedSeries, gridLines, maxValue, labels } = useMemo9(() => {
|
|
10918
|
+
if (!series.length || !series[0]?.data?.length) {
|
|
10919
|
+
return { processedSeries: [], gridLines: [], maxValue: 0, labels: [] };
|
|
10920
|
+
}
|
|
10921
|
+
const allLabels = series[0].data.map((d) => d.label);
|
|
10922
|
+
const dataLength = series[0].data.length;
|
|
10923
|
+
let max = 0;
|
|
10924
|
+
if (stacked) {
|
|
10925
|
+
for (let i = 0; i < dataLength; i++) {
|
|
10926
|
+
const stackedValue = series.reduce((sum, s) => sum + (s.data[i]?.value || 0), 0);
|
|
10927
|
+
max = Math.max(max, stackedValue);
|
|
10928
|
+
}
|
|
10929
|
+
} else {
|
|
10930
|
+
max = Math.max(...series.flatMap((s) => s.data.map((d) => d.value)));
|
|
10931
|
+
}
|
|
10932
|
+
const processed = series.map((s, seriesIndex) => {
|
|
10933
|
+
const points = s.data.map((d, i) => {
|
|
10934
|
+
const x = padding.left + i / (dataLength - 1) * chartWidth;
|
|
10935
|
+
let y;
|
|
10936
|
+
if (stacked && seriesIndex > 0) {
|
|
10937
|
+
const stackedBase = series.slice(0, seriesIndex).reduce((sum, prevS) => sum + (prevS.data[i]?.value || 0), 0);
|
|
10938
|
+
const stackedValue = stackedBase + d.value;
|
|
10939
|
+
y = padding.top + chartHeight - stackedValue / max * chartHeight;
|
|
10940
|
+
} else {
|
|
10941
|
+
y = padding.top + chartHeight - d.value / max * chartHeight;
|
|
10942
|
+
}
|
|
10943
|
+
return { x, y, value: d.value, label: d.label };
|
|
10944
|
+
});
|
|
10945
|
+
const linePath = curved ? getCatmullRomSpline(points) : `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")}`;
|
|
10946
|
+
let areaPath;
|
|
10947
|
+
if (stacked && seriesIndex > 0) {
|
|
10948
|
+
const prevSeriesPoints = series.slice(0, seriesIndex).reduce((acc, prevS) => {
|
|
10949
|
+
return prevS.data.map((d, i) => {
|
|
10950
|
+
const prevVal = acc[i] || 0;
|
|
10951
|
+
return prevVal + d.value;
|
|
10952
|
+
});
|
|
10953
|
+
}, []).map((val, i) => ({
|
|
10954
|
+
x: padding.left + i / (dataLength - 1) * chartWidth,
|
|
10955
|
+
y: padding.top + chartHeight - val / max * chartHeight
|
|
10956
|
+
}));
|
|
10957
|
+
const reversedPrevPoints = [...prevSeriesPoints].reverse();
|
|
10958
|
+
areaPath = `${linePath} L ${reversedPrevPoints.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`;
|
|
10959
|
+
} else {
|
|
10960
|
+
areaPath = `${linePath} L ${padding.left + chartWidth} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
10961
|
+
}
|
|
10962
|
+
return {
|
|
10963
|
+
...s,
|
|
10964
|
+
points,
|
|
10965
|
+
linePath,
|
|
10966
|
+
areaPath,
|
|
10967
|
+
lineLength: points.reduce((acc, p, i) => {
|
|
10968
|
+
if (i === 0) return 0;
|
|
10969
|
+
const prev = points[i - 1];
|
|
10970
|
+
return acc + Math.sqrt(Math.pow(p.x - prev.x, 2) + Math.pow(p.y - prev.y, 2));
|
|
10971
|
+
}, 0)
|
|
10972
|
+
};
|
|
10973
|
+
});
|
|
10974
|
+
const lines = [];
|
|
10975
|
+
const steps = 5;
|
|
10976
|
+
for (let i = 0; i <= steps; i++) {
|
|
10977
|
+
const value = i / steps * max;
|
|
10978
|
+
lines.push({
|
|
10979
|
+
y: padding.top + chartHeight - i / steps * chartHeight,
|
|
10980
|
+
value
|
|
10981
|
+
});
|
|
10982
|
+
}
|
|
10983
|
+
return { processedSeries: processed, gridLines: lines, maxValue: max, labels: allLabels };
|
|
10984
|
+
}, [series, chartWidth, chartHeight, padding, stacked, curved]);
|
|
10985
|
+
return /* @__PURE__ */ jsxs44("div", { ref: containerRef, className: `relative flex flex-col gap-4 ${className}`, children: [
|
|
10986
|
+
/* @__PURE__ */ jsxs44("svg", { width, height, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
10987
|
+
showGrid && /* @__PURE__ */ jsx49("g", { className: "text-muted-foreground/20", children: gridLines.map((line, i) => /* @__PURE__ */ jsxs44("g", { children: [
|
|
10988
|
+
/* @__PURE__ */ jsx49("line", { x1: padding.left, y1: line.y, x2: width - padding.right, y2: line.y, stroke: "currentColor", strokeDasharray: "4 4" }),
|
|
10989
|
+
/* @__PURE__ */ jsx49("text", { x: padding.left - 8, y: line.y + 4, textAnchor: "end", fontSize: "10", className: "text-muted-foreground", fill: "currentColor", children: line.value.toFixed(0) })
|
|
10990
|
+
] }, i)) }),
|
|
10991
|
+
[...processedSeries].reverse().map((s, i) => /* @__PURE__ */ jsx49(
|
|
10992
|
+
"path",
|
|
10993
|
+
{
|
|
10994
|
+
d: s.areaPath,
|
|
10995
|
+
fill: s.color,
|
|
10996
|
+
fillOpacity: s.fillOpacity ?? 0.3,
|
|
10997
|
+
className: "transition-all duration-300",
|
|
10998
|
+
style: animated ? {
|
|
10999
|
+
opacity: 0,
|
|
11000
|
+
animation: `fadeIn 0.5s ease-out ${i * 0.1}s forwards`
|
|
11001
|
+
} : void 0
|
|
11002
|
+
},
|
|
11003
|
+
`area-${i}`
|
|
11004
|
+
)),
|
|
11005
|
+
processedSeries.map((s, i) => /* @__PURE__ */ jsx49(
|
|
11006
|
+
"path",
|
|
11007
|
+
{
|
|
11008
|
+
d: s.linePath,
|
|
11009
|
+
fill: "none",
|
|
11010
|
+
stroke: s.color,
|
|
11011
|
+
strokeWidth: 2,
|
|
11012
|
+
strokeLinecap: "round",
|
|
11013
|
+
strokeLinejoin: "round",
|
|
11014
|
+
style: animated ? {
|
|
11015
|
+
strokeDasharray: s.lineLength,
|
|
11016
|
+
strokeDashoffset: s.lineLength,
|
|
11017
|
+
animation: `drawLine 1s ease-out ${i * 0.1}s forwards`
|
|
11018
|
+
} : void 0
|
|
11019
|
+
},
|
|
11020
|
+
`line-${i}`
|
|
11021
|
+
)),
|
|
11022
|
+
showDots && processedSeries.map(
|
|
11023
|
+
(s, seriesIdx) => s.points.map((point, i) => /* @__PURE__ */ jsxs44(
|
|
11024
|
+
"g",
|
|
11025
|
+
{
|
|
11026
|
+
onMouseEnter: () => {
|
|
11027
|
+
const items = processedSeries.map((ps) => ({
|
|
11028
|
+
label: ps.name,
|
|
11029
|
+
value: ps.points[i]?.value ?? 0,
|
|
11030
|
+
color: ps.color
|
|
11031
|
+
}));
|
|
11032
|
+
setHoveredPoint({
|
|
11033
|
+
x: point.x,
|
|
11034
|
+
y: point.y,
|
|
11035
|
+
label: point.label,
|
|
11036
|
+
items
|
|
11037
|
+
});
|
|
11038
|
+
},
|
|
11039
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
11040
|
+
className: "cursor-pointer",
|
|
11041
|
+
children: [
|
|
11042
|
+
/* @__PURE__ */ jsx49(
|
|
11043
|
+
"circle",
|
|
11044
|
+
{
|
|
11045
|
+
cx: point.x,
|
|
11046
|
+
cy: point.y,
|
|
11047
|
+
r: hoveredPoint?.x === point.x ? 6 : 4,
|
|
11048
|
+
fill: s.color,
|
|
11049
|
+
className: "transition-all duration-150",
|
|
11050
|
+
style: animated ? {
|
|
11051
|
+
transform: "scale(0)",
|
|
11052
|
+
opacity: 0,
|
|
11053
|
+
transformOrigin: `${point.x}px ${point.y}px`,
|
|
11054
|
+
animation: `dotPop 0.3s ease-out ${seriesIdx * 0.1 + i * 0.05 + 0.5}s forwards`
|
|
11055
|
+
} : void 0
|
|
11056
|
+
}
|
|
11057
|
+
),
|
|
11058
|
+
/* @__PURE__ */ jsx49("circle", { cx: point.x, cy: point.y, r: 12, fill: "transparent" })
|
|
11059
|
+
]
|
|
11060
|
+
},
|
|
11061
|
+
`dot-${seriesIdx}-${i}`
|
|
11062
|
+
))
|
|
11063
|
+
),
|
|
11064
|
+
showLabels && /* @__PURE__ */ jsx49("g", { className: "text-muted-foreground", children: labels.map((label, i) => {
|
|
11065
|
+
const x = padding.left + i / (labels.length - 1) * chartWidth;
|
|
11066
|
+
return /* @__PURE__ */ jsx49("text", { x, y: height - 10, textAnchor: "middle", fontSize: "10", fill: "currentColor", children: label }, i);
|
|
11067
|
+
}) }),
|
|
11068
|
+
hoveredPoint && /* @__PURE__ */ jsx49("g", { className: "pointer-events-none", children: /* @__PURE__ */ jsx49(
|
|
11069
|
+
"line",
|
|
11070
|
+
{
|
|
11071
|
+
x1: hoveredPoint.x,
|
|
11072
|
+
y1: padding.top,
|
|
11073
|
+
x2: hoveredPoint.x,
|
|
11074
|
+
y2: padding.top + chartHeight,
|
|
11075
|
+
stroke: "currentColor",
|
|
11076
|
+
strokeWidth: 1,
|
|
11077
|
+
strokeDasharray: "4 4",
|
|
11078
|
+
opacity: 0.3,
|
|
11079
|
+
className: "text-foreground"
|
|
11080
|
+
}
|
|
11081
|
+
) }),
|
|
11082
|
+
/* @__PURE__ */ jsx49("style", { children: `
|
|
11083
|
+
@keyframes drawLine {
|
|
11084
|
+
to {
|
|
11085
|
+
stroke-dashoffset: 0;
|
|
11086
|
+
}
|
|
11087
|
+
}
|
|
11088
|
+
@keyframes fadeIn {
|
|
11089
|
+
from { opacity: 0; }
|
|
11090
|
+
to { opacity: 1; }
|
|
11091
|
+
}
|
|
11092
|
+
@keyframes dotPop {
|
|
11093
|
+
from {
|
|
11094
|
+
transform: scale(0);
|
|
11095
|
+
opacity: 0;
|
|
11096
|
+
}
|
|
11097
|
+
to {
|
|
11098
|
+
transform: scale(1);
|
|
11099
|
+
opacity: 1;
|
|
11100
|
+
}
|
|
11101
|
+
}
|
|
11102
|
+
` })
|
|
11103
|
+
] }),
|
|
11104
|
+
showLegend && /* @__PURE__ */ jsx49("div", { className: "flex items-center justify-center gap-6", children: series.map((s, i) => /* @__PURE__ */ jsxs44(
|
|
11105
|
+
"div",
|
|
11106
|
+
{
|
|
11107
|
+
className: "flex items-center gap-2 text-sm",
|
|
11108
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.5}s forwards` } : void 0,
|
|
11109
|
+
children: [
|
|
11110
|
+
/* @__PURE__ */ jsx49("div", { className: "w-3 h-3 rounded-sm", style: { backgroundColor: s.color } }),
|
|
11111
|
+
/* @__PURE__ */ jsx49("span", { className: "text-muted-foreground", children: s.name })
|
|
11112
|
+
]
|
|
11113
|
+
},
|
|
11114
|
+
i
|
|
11115
|
+
)) }),
|
|
11116
|
+
/* @__PURE__ */ jsx49(
|
|
11117
|
+
ChartTooltip,
|
|
11118
|
+
{
|
|
11119
|
+
x: hoveredPoint?.x ?? 0,
|
|
11120
|
+
y: hoveredPoint?.y ?? 0,
|
|
11121
|
+
visible: !!hoveredPoint,
|
|
11122
|
+
label: hoveredPoint?.label,
|
|
11123
|
+
items: hoveredPoint?.items,
|
|
11124
|
+
containerRef
|
|
11125
|
+
}
|
|
11126
|
+
)
|
|
11127
|
+
] });
|
|
11128
|
+
}
|
|
11129
|
+
|
|
11130
|
+
// ../../components/ui/Sparkline.tsx
|
|
11131
|
+
import { useMemo as useMemo10 } from "react";
|
|
11132
|
+
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
11133
|
+
function getCatmullRomSpline2(points) {
|
|
11134
|
+
if (points.length < 2) return "";
|
|
11135
|
+
if (points.length === 2) {
|
|
11136
|
+
return `M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y}`;
|
|
11137
|
+
}
|
|
11138
|
+
let path = `M ${points[0].x} ${points[0].y}`;
|
|
11139
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
11140
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
11141
|
+
const p1 = points[i];
|
|
11142
|
+
const p2 = points[i + 1];
|
|
11143
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
11144
|
+
const tension = 0.5;
|
|
11145
|
+
const cp1x = p1.x + (p2.x - p0.x) * tension / 6;
|
|
11146
|
+
const cp1y = p1.y + (p2.y - p0.y) * tension / 6;
|
|
11147
|
+
const cp2x = p2.x - (p3.x - p1.x) * tension / 6;
|
|
11148
|
+
const cp2y = p2.y - (p3.y - p1.y) * tension / 6;
|
|
11149
|
+
path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;
|
|
11150
|
+
}
|
|
11151
|
+
return path;
|
|
11152
|
+
}
|
|
11153
|
+
function Sparkline({
|
|
11154
|
+
data,
|
|
11155
|
+
width = 100,
|
|
11156
|
+
height = 30,
|
|
11157
|
+
color = "currentColor",
|
|
11158
|
+
fillColor,
|
|
11159
|
+
showFill = true,
|
|
11160
|
+
showDots = false,
|
|
11161
|
+
showEndDot = true,
|
|
11162
|
+
animated = true,
|
|
11163
|
+
curved = true,
|
|
11164
|
+
strokeWidth = 2,
|
|
11165
|
+
className = ""
|
|
11166
|
+
}) {
|
|
11167
|
+
const padding = 4;
|
|
11168
|
+
const chartWidth = width - padding * 2;
|
|
11169
|
+
const chartHeight = height - padding * 2;
|
|
11170
|
+
const { points, linePath, areaPath, lineLength, trend } = useMemo10(() => {
|
|
11171
|
+
const normalizedData = data.map((d) => typeof d === "number" ? d : d.value);
|
|
11172
|
+
if (!normalizedData.length) {
|
|
11173
|
+
return { points: [], linePath: "", areaPath: "", lineLength: 0, trend: 0 };
|
|
11174
|
+
}
|
|
11175
|
+
const min = Math.min(...normalizedData);
|
|
11176
|
+
const max = Math.max(...normalizedData);
|
|
11177
|
+
const range = max - min || 1;
|
|
11178
|
+
const pts = normalizedData.map((value, i) => ({
|
|
11179
|
+
x: padding + i / (normalizedData.length - 1) * chartWidth,
|
|
11180
|
+
y: padding + chartHeight - (value - min) / range * chartHeight,
|
|
11181
|
+
value
|
|
11182
|
+
}));
|
|
11183
|
+
const line = curved ? getCatmullRomSpline2(pts) : `M ${pts.map((p) => `${p.x} ${p.y}`).join(" L ")}`;
|
|
11184
|
+
const area = `${line} L ${padding + chartWidth} ${padding + chartHeight} L ${padding} ${padding + chartHeight} Z`;
|
|
11185
|
+
const length = pts.reduce((acc, p, i) => {
|
|
11186
|
+
if (i === 0) return 0;
|
|
11187
|
+
const prev = pts[i - 1];
|
|
11188
|
+
return acc + Math.sqrt(Math.pow(p.x - prev.x, 2) + Math.pow(p.y - prev.y, 2));
|
|
11189
|
+
}, 0);
|
|
11190
|
+
const trendValue = normalizedData[normalizedData.length - 1] - normalizedData[0];
|
|
11191
|
+
return { points: pts, linePath: line, areaPath: area, lineLength: length, trend: trendValue };
|
|
11192
|
+
}, [data, chartWidth, chartHeight, padding, curved]);
|
|
11193
|
+
const effectiveFillColor = fillColor || color;
|
|
11194
|
+
return /* @__PURE__ */ jsxs45("svg", { width, height, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
11195
|
+
showFill && /* @__PURE__ */ jsx50(
|
|
11196
|
+
"path",
|
|
11197
|
+
{
|
|
11198
|
+
d: areaPath,
|
|
11199
|
+
fill: effectiveFillColor,
|
|
11200
|
+
fillOpacity: 0.1,
|
|
11201
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.3s forwards" } : void 0
|
|
11202
|
+
}
|
|
11203
|
+
),
|
|
11204
|
+
/* @__PURE__ */ jsx50(
|
|
11205
|
+
"path",
|
|
11206
|
+
{
|
|
11207
|
+
d: linePath,
|
|
11208
|
+
fill: "none",
|
|
11209
|
+
stroke: color,
|
|
11210
|
+
strokeWidth,
|
|
11211
|
+
strokeLinecap: "round",
|
|
11212
|
+
strokeLinejoin: "round",
|
|
11213
|
+
style: animated ? {
|
|
11214
|
+
strokeDasharray: lineLength,
|
|
11215
|
+
strokeDashoffset: lineLength,
|
|
11216
|
+
animation: "drawLine 0.8s ease-out forwards"
|
|
11217
|
+
} : void 0
|
|
11218
|
+
}
|
|
11219
|
+
),
|
|
11220
|
+
showDots && points.map((point, i) => /* @__PURE__ */ jsx50(
|
|
11221
|
+
"circle",
|
|
11222
|
+
{
|
|
11223
|
+
cx: point.x,
|
|
11224
|
+
cy: point.y,
|
|
11225
|
+
r: 2,
|
|
11226
|
+
fill: color,
|
|
11227
|
+
style: animated ? {
|
|
11228
|
+
opacity: 0,
|
|
11229
|
+
animation: `fadeIn 0.3s ease-out ${i * 0.05 + 0.5}s forwards`
|
|
11230
|
+
} : void 0
|
|
11231
|
+
},
|
|
11232
|
+
i
|
|
11233
|
+
)),
|
|
11234
|
+
showEndDot && !showDots && points.length > 0 && /* @__PURE__ */ jsx50(
|
|
11235
|
+
"circle",
|
|
11236
|
+
{
|
|
11237
|
+
cx: points[points.length - 1].x,
|
|
11238
|
+
cy: points[points.length - 1].y,
|
|
11239
|
+
r: 3,
|
|
11240
|
+
fill: color,
|
|
11241
|
+
style: animated ? {
|
|
11242
|
+
opacity: 0,
|
|
11243
|
+
transform: "scale(0)",
|
|
11244
|
+
transformOrigin: `${points[points.length - 1].x}px ${points[points.length - 1].y}px`,
|
|
11245
|
+
animation: "dotPop 0.3s ease-out 0.6s forwards"
|
|
11246
|
+
} : void 0
|
|
11247
|
+
}
|
|
11248
|
+
),
|
|
11249
|
+
/* @__PURE__ */ jsx50("style", { children: `
|
|
11250
|
+
@keyframes drawLine {
|
|
11251
|
+
to {
|
|
11252
|
+
stroke-dashoffset: 0;
|
|
11253
|
+
}
|
|
11254
|
+
}
|
|
11255
|
+
@keyframes fadeIn {
|
|
11256
|
+
from { opacity: 0; }
|
|
11257
|
+
to { opacity: 1; }
|
|
11258
|
+
}
|
|
11259
|
+
@keyframes dotPop {
|
|
11260
|
+
from {
|
|
11261
|
+
transform: scale(0);
|
|
11262
|
+
opacity: 0;
|
|
11263
|
+
}
|
|
11264
|
+
to {
|
|
11265
|
+
transform: scale(1);
|
|
11266
|
+
opacity: 1;
|
|
11267
|
+
}
|
|
11268
|
+
}
|
|
11269
|
+
` })
|
|
11270
|
+
] });
|
|
11271
|
+
}
|
|
11272
|
+
|
|
11273
|
+
// ../../components/ui/RadarChart.tsx
|
|
11274
|
+
import { useMemo as useMemo11, useState as useState37, useRef as useRef18 } from "react";
|
|
11275
|
+
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
11276
|
+
function RadarChart({
|
|
11277
|
+
series,
|
|
11278
|
+
size = 300,
|
|
11279
|
+
levels = 5,
|
|
11280
|
+
showLabels = true,
|
|
11281
|
+
showLegend = true,
|
|
11282
|
+
showValues = false,
|
|
11283
|
+
animated = true,
|
|
11284
|
+
className = ""
|
|
11285
|
+
}) {
|
|
11286
|
+
const containerRef = useRef18(null);
|
|
11287
|
+
const center = size / 2;
|
|
11288
|
+
const radius = size / 2 - 40;
|
|
11289
|
+
const [hoveredPoint, setHoveredPoint] = useState37(null);
|
|
11290
|
+
const { axes, processedSeries, levelPaths } = useMemo11(() => {
|
|
11291
|
+
if (!series.length || !series[0]?.data?.length) {
|
|
11292
|
+
return { axes: [], processedSeries: [], levelPaths: [] };
|
|
11293
|
+
}
|
|
11294
|
+
const axisLabels = series[0].data.map((d) => d.axis);
|
|
11295
|
+
const axisCount = axisLabels.length;
|
|
11296
|
+
const angleStep = 2 * Math.PI / axisCount;
|
|
11297
|
+
const maxValue = Math.max(...series.flatMap((s) => s.data.map((d) => d.value)));
|
|
11298
|
+
const axesData = axisLabels.map((label, i) => {
|
|
11299
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11300
|
+
const x = center + radius * Math.cos(angle);
|
|
11301
|
+
const y = center + radius * Math.sin(angle);
|
|
11302
|
+
const labelX = center + (radius + 20) * Math.cos(angle);
|
|
11303
|
+
const labelY = center + (radius + 20) * Math.sin(angle);
|
|
11304
|
+
return { label, x, y, labelX, labelY, angle };
|
|
11305
|
+
});
|
|
11306
|
+
const levelsData = [];
|
|
11307
|
+
for (let l = 1; l <= levels; l++) {
|
|
11308
|
+
const levelRadius = l / levels * radius;
|
|
11309
|
+
const points = axisLabels.map((_, i) => {
|
|
11310
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11311
|
+
return {
|
|
11312
|
+
x: center + levelRadius * Math.cos(angle),
|
|
11313
|
+
y: center + levelRadius * Math.sin(angle)
|
|
11314
|
+
};
|
|
11315
|
+
});
|
|
11316
|
+
levelsData.push({
|
|
11317
|
+
path: `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`,
|
|
11318
|
+
level: l,
|
|
11319
|
+
value: l / levels * maxValue
|
|
11320
|
+
});
|
|
11321
|
+
}
|
|
11322
|
+
const processed = series.map((s) => {
|
|
11323
|
+
const points = s.data.map((d, i) => {
|
|
11324
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
11325
|
+
const r = d.value / maxValue * radius;
|
|
11326
|
+
return {
|
|
11327
|
+
x: center + r * Math.cos(angle),
|
|
11328
|
+
y: center + r * Math.sin(angle),
|
|
11329
|
+
value: d.value
|
|
11330
|
+
};
|
|
11331
|
+
});
|
|
11332
|
+
return {
|
|
11333
|
+
...s,
|
|
11334
|
+
points,
|
|
11335
|
+
path: `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")} Z`
|
|
11336
|
+
};
|
|
11337
|
+
});
|
|
11338
|
+
return { axes: axesData, processedSeries: processed, levelPaths: levelsData };
|
|
11339
|
+
}, [series, center, radius, levels]);
|
|
11340
|
+
return /* @__PURE__ */ jsxs46("div", { ref: containerRef, className: `relative flex flex-col gap-4 ${className}`, children: [
|
|
11341
|
+
/* @__PURE__ */ jsxs46("svg", { width: size, height: size, className: "overflow-visible", style: { fontFamily: "inherit" }, children: [
|
|
11342
|
+
/* @__PURE__ */ jsx51("g", { className: "text-muted-foreground/20", children: levelPaths.map((level, i) => /* @__PURE__ */ jsx51("path", { d: level.path, fill: "none", stroke: "currentColor", strokeWidth: 1 }, i)) }),
|
|
11343
|
+
/* @__PURE__ */ jsx51("g", { className: "text-muted-foreground/30", children: axes.map((axis, i) => /* @__PURE__ */ jsx51("line", { x1: center, y1: center, x2: axis.x, y2: axis.y, stroke: "currentColor", strokeWidth: 1 }, i)) }),
|
|
11344
|
+
processedSeries.map((s, i) => /* @__PURE__ */ jsxs46("g", { children: [
|
|
11345
|
+
/* @__PURE__ */ jsx51(
|
|
11346
|
+
"path",
|
|
11347
|
+
{
|
|
11348
|
+
d: s.path,
|
|
11349
|
+
fill: s.color,
|
|
11350
|
+
fillOpacity: s.fillOpacity ?? 0.2,
|
|
11351
|
+
stroke: s.color,
|
|
11352
|
+
strokeWidth: 2,
|
|
11353
|
+
strokeLinejoin: "round",
|
|
11354
|
+
className: "transition-all duration-300",
|
|
11355
|
+
style: animated ? {
|
|
11356
|
+
opacity: 0,
|
|
11357
|
+
transform: "scale(0)",
|
|
11358
|
+
transformOrigin: `${center}px ${center}px`,
|
|
11359
|
+
animation: `radarPop 0.5s ease-out ${i * 0.15}s forwards`
|
|
11360
|
+
} : void 0
|
|
11361
|
+
}
|
|
11362
|
+
),
|
|
11363
|
+
s.points.map((point, j) => /* @__PURE__ */ jsxs46(
|
|
11364
|
+
"g",
|
|
11365
|
+
{
|
|
11366
|
+
onMouseEnter: () => {
|
|
11367
|
+
const items = processedSeries.map((ps) => ({
|
|
11368
|
+
label: ps.name,
|
|
11369
|
+
value: ps.points[j]?.value ?? 0,
|
|
11370
|
+
color: ps.color
|
|
11371
|
+
}));
|
|
11372
|
+
setHoveredPoint({
|
|
11373
|
+
x: point.x,
|
|
11374
|
+
y: point.y,
|
|
11375
|
+
axis: series[0]?.data[j]?.axis ?? "",
|
|
11376
|
+
items
|
|
11377
|
+
});
|
|
11378
|
+
},
|
|
11379
|
+
onMouseLeave: () => setHoveredPoint(null),
|
|
11380
|
+
className: "cursor-pointer",
|
|
11381
|
+
children: [
|
|
11382
|
+
/* @__PURE__ */ jsx51(
|
|
11383
|
+
"circle",
|
|
11384
|
+
{
|
|
11385
|
+
cx: point.x,
|
|
11386
|
+
cy: point.y,
|
|
11387
|
+
r: hoveredPoint?.axis === series[0]?.data[j]?.axis ? 6 : 4,
|
|
11388
|
+
fill: s.color,
|
|
11389
|
+
className: "transition-all duration-150",
|
|
11390
|
+
style: animated ? {
|
|
11391
|
+
opacity: 0,
|
|
11392
|
+
transform: "scale(0)",
|
|
11393
|
+
transformOrigin: `${point.x}px ${point.y}px`,
|
|
11394
|
+
animation: `dotPop 0.3s ease-out ${i * 0.15 + j * 0.05 + 0.3}s forwards`
|
|
11395
|
+
} : void 0
|
|
11396
|
+
}
|
|
11397
|
+
),
|
|
11398
|
+
/* @__PURE__ */ jsx51("circle", { cx: point.x, cy: point.y, r: 12, fill: "transparent" })
|
|
11399
|
+
]
|
|
11400
|
+
},
|
|
11401
|
+
j
|
|
11402
|
+
)),
|
|
11403
|
+
showValues && s.points.map((point, j) => /* @__PURE__ */ jsx51(
|
|
11404
|
+
"text",
|
|
11405
|
+
{
|
|
11406
|
+
x: point.x,
|
|
11407
|
+
y: point.y - 10,
|
|
11408
|
+
textAnchor: "middle",
|
|
11409
|
+
fontSize: "10",
|
|
11410
|
+
fontWeight: "500",
|
|
11411
|
+
className: "text-foreground",
|
|
11412
|
+
fill: "currentColor",
|
|
11413
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.15 + 0.5}s forwards` } : void 0,
|
|
11414
|
+
children: point.value
|
|
11415
|
+
},
|
|
11416
|
+
`val-${j}`
|
|
11417
|
+
))
|
|
11418
|
+
] }, i)),
|
|
11419
|
+
showLabels && /* @__PURE__ */ jsx51("g", { className: "text-muted-foreground", children: axes.map((axis, i) => /* @__PURE__ */ jsx51("text", { x: axis.labelX, y: axis.labelY, textAnchor: "middle", dominantBaseline: "middle", fontSize: "11", fill: "currentColor", children: axis.label }, i)) }),
|
|
11420
|
+
/* @__PURE__ */ jsx51("style", { children: `
|
|
11421
|
+
@keyframes radarPop {
|
|
11422
|
+
from {
|
|
11423
|
+
opacity: 0;
|
|
11424
|
+
transform: scale(0);
|
|
11425
|
+
}
|
|
11426
|
+
to {
|
|
11427
|
+
opacity: 1;
|
|
11428
|
+
transform: scale(1);
|
|
11429
|
+
}
|
|
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
|
+
@keyframes fadeIn {
|
|
11442
|
+
from { opacity: 0; }
|
|
11443
|
+
to { opacity: 1; }
|
|
11444
|
+
}
|
|
11445
|
+
` })
|
|
11446
|
+
] }),
|
|
11447
|
+
showLegend && /* @__PURE__ */ jsx51("div", { className: "flex items-center justify-center gap-6", children: series.map((s, i) => /* @__PURE__ */ jsxs46(
|
|
11448
|
+
"div",
|
|
11449
|
+
{
|
|
11450
|
+
className: "flex items-center gap-2 text-sm",
|
|
11451
|
+
style: animated ? { opacity: 0, animation: `fadeIn 0.3s ease-out ${i * 0.1 + 0.5}s forwards` } : void 0,
|
|
11452
|
+
children: [
|
|
11453
|
+
/* @__PURE__ */ jsx51("div", { className: "w-3 h-3 rounded-sm", style: { backgroundColor: s.color } }),
|
|
11454
|
+
/* @__PURE__ */ jsx51("span", { className: "text-muted-foreground", children: s.name })
|
|
11455
|
+
]
|
|
11456
|
+
},
|
|
11457
|
+
i
|
|
11458
|
+
)) }),
|
|
11459
|
+
/* @__PURE__ */ jsx51(
|
|
11460
|
+
ChartTooltip,
|
|
11461
|
+
{
|
|
11462
|
+
x: hoveredPoint?.x ?? 0,
|
|
11463
|
+
y: hoveredPoint?.y ?? 0,
|
|
11464
|
+
visible: !!hoveredPoint,
|
|
11465
|
+
label: hoveredPoint?.axis,
|
|
11466
|
+
items: hoveredPoint?.items,
|
|
11467
|
+
containerRef
|
|
11468
|
+
}
|
|
11469
|
+
)
|
|
11470
|
+
] });
|
|
11471
|
+
}
|
|
11472
|
+
|
|
11473
|
+
// ../../components/ui/GaugeChart.tsx
|
|
11474
|
+
import { useMemo as useMemo12 } from "react";
|
|
11475
|
+
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
11476
|
+
function GaugeChart({
|
|
11477
|
+
value,
|
|
11478
|
+
min = 0,
|
|
11479
|
+
max = 100,
|
|
11480
|
+
size = 200,
|
|
11481
|
+
thickness = 20,
|
|
11482
|
+
color = "currentColor",
|
|
11483
|
+
backgroundColor,
|
|
11484
|
+
showValue = true,
|
|
11485
|
+
showMinMax = true,
|
|
11486
|
+
label,
|
|
11487
|
+
animated = true,
|
|
11488
|
+
startAngle = -135,
|
|
11489
|
+
endAngle = 135,
|
|
11490
|
+
className = ""
|
|
11491
|
+
}) {
|
|
11492
|
+
const center = size / 2;
|
|
11493
|
+
const radius = center - thickness / 2 - 10;
|
|
11494
|
+
const { backgroundPath, valuePath, percentage, needleAngle } = useMemo12(() => {
|
|
11495
|
+
const normalizedValue = Math.min(Math.max(value, min), max);
|
|
11496
|
+
const pct = (normalizedValue - min) / (max - min);
|
|
11497
|
+
const totalAngle = endAngle - startAngle;
|
|
11498
|
+
const currentAngle = startAngle + pct * totalAngle;
|
|
11499
|
+
const polarToCartesian = (angle) => {
|
|
11500
|
+
const radians = angle * Math.PI / 180;
|
|
11501
|
+
return {
|
|
11502
|
+
x: center + radius * Math.cos(radians),
|
|
11503
|
+
y: center + radius * Math.sin(radians)
|
|
11504
|
+
};
|
|
11505
|
+
};
|
|
11506
|
+
const createArc = (start, end) => {
|
|
11507
|
+
const startPoint = polarToCartesian(start);
|
|
11508
|
+
const endPoint = polarToCartesian(end);
|
|
11509
|
+
const largeArc = Math.abs(end - start) > 180 ? 1 : 0;
|
|
11510
|
+
return `M ${startPoint.x} ${startPoint.y} A ${radius} ${radius} 0 ${largeArc} 1 ${endPoint.x} ${endPoint.y}`;
|
|
11511
|
+
};
|
|
11512
|
+
return {
|
|
11513
|
+
backgroundPath: createArc(startAngle, endAngle),
|
|
11514
|
+
valuePath: createArc(startAngle, currentAngle),
|
|
11515
|
+
percentage: pct,
|
|
11516
|
+
needleAngle: currentAngle
|
|
11517
|
+
};
|
|
11518
|
+
}, [value, min, max, center, radius, startAngle, endAngle]);
|
|
11519
|
+
const needleLength = radius - 10;
|
|
11520
|
+
const needleAngleRad = needleAngle * Math.PI / 180;
|
|
11521
|
+
const needleX = center + needleLength * Math.cos(needleAngleRad);
|
|
11522
|
+
const needleY = center + needleLength * Math.sin(needleAngleRad);
|
|
11523
|
+
return /* @__PURE__ */ jsxs47("svg", { width: size, height: size * 0.7, className: `overflow-visible ${className}`, style: { fontFamily: "inherit" }, children: [
|
|
11524
|
+
/* @__PURE__ */ jsx52(
|
|
11525
|
+
"path",
|
|
11526
|
+
{
|
|
11527
|
+
d: backgroundPath,
|
|
11528
|
+
fill: "none",
|
|
11529
|
+
stroke: backgroundColor || "currentColor",
|
|
11530
|
+
strokeWidth: thickness,
|
|
11531
|
+
strokeLinecap: "round",
|
|
11532
|
+
className: !backgroundColor ? "text-muted-foreground/20" : ""
|
|
11533
|
+
}
|
|
11534
|
+
),
|
|
11535
|
+
/* @__PURE__ */ jsx52(
|
|
11536
|
+
"path",
|
|
11537
|
+
{
|
|
11538
|
+
d: valuePath,
|
|
11539
|
+
fill: "none",
|
|
11540
|
+
stroke: color,
|
|
11541
|
+
strokeWidth: thickness,
|
|
11542
|
+
strokeLinecap: "round",
|
|
11543
|
+
style: animated ? {
|
|
11544
|
+
strokeDasharray: "1000",
|
|
11545
|
+
strokeDashoffset: 1e3,
|
|
11546
|
+
animation: "drawArc 1s ease-out forwards"
|
|
11547
|
+
} : void 0
|
|
11548
|
+
}
|
|
11549
|
+
),
|
|
11550
|
+
/* @__PURE__ */ jsxs47(
|
|
11551
|
+
"g",
|
|
11552
|
+
{
|
|
11553
|
+
style: animated ? {
|
|
11554
|
+
transform: `rotate(${startAngle}deg)`,
|
|
11555
|
+
transformOrigin: `${center}px ${center}px`,
|
|
11556
|
+
animation: `needleRotate 1s ease-out forwards`,
|
|
11557
|
+
["--needle-end"]: `${needleAngle}deg`
|
|
11558
|
+
} : {
|
|
11559
|
+
transform: `rotate(${needleAngle}deg)`,
|
|
11560
|
+
transformOrigin: `${center}px ${center}px`
|
|
11561
|
+
},
|
|
11562
|
+
children: [
|
|
11563
|
+
/* @__PURE__ */ jsx52("line", { x1: center, y1: center, x2: center + needleLength, y2: center, stroke: color, strokeWidth: 3, strokeLinecap: "round" }),
|
|
11564
|
+
/* @__PURE__ */ jsx52("circle", { cx: center, cy: center, r: 8, fill: color }),
|
|
11565
|
+
/* @__PURE__ */ jsx52("circle", { cx: center, cy: center, r: 4, className: "text-background", fill: "currentColor" })
|
|
11566
|
+
]
|
|
11567
|
+
}
|
|
11568
|
+
),
|
|
11569
|
+
showMinMax && /* @__PURE__ */ jsxs47("g", { className: "text-muted-foreground", children: [
|
|
11570
|
+
/* @__PURE__ */ jsx52(
|
|
11571
|
+
"text",
|
|
11572
|
+
{
|
|
11573
|
+
x: center + (radius + 20) * Math.cos(startAngle * Math.PI / 180),
|
|
11574
|
+
y: center + (radius + 20) * Math.sin(startAngle * Math.PI / 180) + 5,
|
|
11575
|
+
textAnchor: "middle",
|
|
11576
|
+
fontSize: "10",
|
|
11577
|
+
fill: "currentColor",
|
|
11578
|
+
children: min
|
|
11579
|
+
}
|
|
11580
|
+
),
|
|
11581
|
+
/* @__PURE__ */ jsx52(
|
|
11582
|
+
"text",
|
|
11583
|
+
{
|
|
11584
|
+
x: center + (radius + 20) * Math.cos(endAngle * Math.PI / 180),
|
|
11585
|
+
y: center + (radius + 20) * Math.sin(endAngle * Math.PI / 180) + 5,
|
|
11586
|
+
textAnchor: "middle",
|
|
11587
|
+
fontSize: "10",
|
|
11588
|
+
fill: "currentColor",
|
|
11589
|
+
children: max
|
|
11590
|
+
}
|
|
11591
|
+
)
|
|
11592
|
+
] }),
|
|
11593
|
+
showValue && /* @__PURE__ */ jsxs47("g", { children: [
|
|
11594
|
+
/* @__PURE__ */ jsx52(
|
|
11595
|
+
"text",
|
|
11596
|
+
{
|
|
11597
|
+
x: center,
|
|
11598
|
+
y: center + 35,
|
|
11599
|
+
textAnchor: "middle",
|
|
11600
|
+
fontSize: "24",
|
|
11601
|
+
fontWeight: "600",
|
|
11602
|
+
className: "text-foreground",
|
|
11603
|
+
fill: "currentColor",
|
|
11604
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.5s forwards" } : void 0,
|
|
11605
|
+
children: value
|
|
11606
|
+
}
|
|
11607
|
+
),
|
|
11608
|
+
label && /* @__PURE__ */ jsx52(
|
|
11609
|
+
"text",
|
|
11610
|
+
{
|
|
11611
|
+
x: center,
|
|
11612
|
+
y: center + 55,
|
|
11613
|
+
textAnchor: "middle",
|
|
11614
|
+
fontSize: "12",
|
|
11615
|
+
className: "text-muted-foreground",
|
|
11616
|
+
fill: "currentColor",
|
|
11617
|
+
style: animated ? { opacity: 0, animation: "fadeIn 0.5s ease-out 0.6s forwards" } : void 0,
|
|
11618
|
+
children: label
|
|
11619
|
+
}
|
|
11620
|
+
)
|
|
11621
|
+
] }),
|
|
11622
|
+
/* @__PURE__ */ jsx52("style", { children: `
|
|
11623
|
+
@keyframes drawArc {
|
|
11624
|
+
to {
|
|
11625
|
+
stroke-dashoffset: 0;
|
|
11626
|
+
}
|
|
11627
|
+
}
|
|
11628
|
+
@keyframes needleRotate {
|
|
11629
|
+
to {
|
|
11630
|
+
transform: rotate(var(--needle-end));
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11633
|
+
@keyframes fadeIn {
|
|
11634
|
+
from { opacity: 0; }
|
|
11635
|
+
to { opacity: 1; }
|
|
11636
|
+
}
|
|
11637
|
+
` })
|
|
11638
|
+
] });
|
|
11639
|
+
}
|
|
11640
|
+
|
|
11641
|
+
// ../../components/ui/ClientOnly.tsx
|
|
11642
|
+
import { useEffect as useEffect19, useState as useState38 } from "react";
|
|
11643
|
+
import { Fragment as Fragment19, jsx as jsx53 } from "react/jsx-runtime";
|
|
11644
|
+
function ClientOnly({ children, fallback = null }) {
|
|
11645
|
+
const [hasMounted, setHasMounted] = useState38(false);
|
|
11646
|
+
useEffect19(() => {
|
|
10283
11647
|
setHasMounted(true);
|
|
10284
11648
|
}, []);
|
|
10285
11649
|
if (!hasMounted) {
|
|
10286
|
-
return /* @__PURE__ */
|
|
11650
|
+
return /* @__PURE__ */ jsx53(Fragment19, { children: fallback });
|
|
10287
11651
|
}
|
|
10288
|
-
return /* @__PURE__ */
|
|
11652
|
+
return /* @__PURE__ */ jsx53(Fragment19, { children });
|
|
10289
11653
|
}
|
|
10290
11654
|
|
|
10291
11655
|
// ../../components/ui/Loading.tsx
|
|
10292
11656
|
import { Activity as Activity3 } from "lucide-react";
|
|
10293
|
-
import { jsx as
|
|
11657
|
+
import { jsx as jsx54, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
10294
11658
|
var LoadingSpinner = ({
|
|
10295
11659
|
size = "md",
|
|
10296
11660
|
className,
|
|
@@ -10306,7 +11670,7 @@ var LoadingSpinner = ({
|
|
|
10306
11670
|
foreground: "text-foreground",
|
|
10307
11671
|
muted: "text-muted-foreground"
|
|
10308
11672
|
};
|
|
10309
|
-
return /* @__PURE__ */
|
|
11673
|
+
return /* @__PURE__ */ jsx54(
|
|
10310
11674
|
Activity3,
|
|
10311
11675
|
{
|
|
10312
11676
|
className: cn(
|
|
@@ -10327,7 +11691,7 @@ var LoadingDots = ({
|
|
|
10327
11691
|
foreground: "bg-foreground",
|
|
10328
11692
|
muted: "bg-muted-foreground"
|
|
10329
11693
|
};
|
|
10330
|
-
return /* @__PURE__ */
|
|
11694
|
+
return /* @__PURE__ */ jsx54("div", { className: cn("flex items-center space-x-1", className), children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx54(
|
|
10331
11695
|
"div",
|
|
10332
11696
|
{
|
|
10333
11697
|
className: cn(
|
|
@@ -10349,7 +11713,7 @@ var LoadingBar = ({
|
|
|
10349
11713
|
label
|
|
10350
11714
|
}) => {
|
|
10351
11715
|
const pct = progress ? Math.min(Math.max(progress, 0), 100) : void 0;
|
|
10352
|
-
return /* @__PURE__ */
|
|
11716
|
+
return /* @__PURE__ */ jsx54(
|
|
10353
11717
|
"div",
|
|
10354
11718
|
{
|
|
10355
11719
|
className: cn("w-full bg-muted rounded-full h-2", className),
|
|
@@ -10358,7 +11722,7 @@ var LoadingBar = ({
|
|
|
10358
11722
|
"aria-valuemax": pct === void 0 ? void 0 : 100,
|
|
10359
11723
|
"aria-valuenow": pct === void 0 ? void 0 : Math.round(pct),
|
|
10360
11724
|
"aria-label": label || "Loading",
|
|
10361
|
-
children: /* @__PURE__ */
|
|
11725
|
+
children: /* @__PURE__ */ jsx54(
|
|
10362
11726
|
"div",
|
|
10363
11727
|
{
|
|
10364
11728
|
className: cn(
|
|
@@ -10375,9 +11739,9 @@ var LoadingBar = ({
|
|
|
10375
11739
|
};
|
|
10376
11740
|
|
|
10377
11741
|
// ../../components/ui/Table.tsx
|
|
10378
|
-
import
|
|
10379
|
-
import { jsx as
|
|
10380
|
-
var Table =
|
|
11742
|
+
import React46 from "react";
|
|
11743
|
+
import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
11744
|
+
var Table = React46.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ jsx55(
|
|
10381
11745
|
"div",
|
|
10382
11746
|
{
|
|
10383
11747
|
className: cn(
|
|
@@ -10387,20 +11751,20 @@ var Table = React38.forwardRef(({ className, containerClassName, ...props }, ref
|
|
|
10387
11751
|
"backdrop-blur-sm transition-all duration-300",
|
|
10388
11752
|
containerClassName
|
|
10389
11753
|
),
|
|
10390
|
-
children: /* @__PURE__ */
|
|
11754
|
+
children: /* @__PURE__ */ jsx55("table", { ref, className: cn("w-full caption-bottom text-sm", className), ...props })
|
|
10391
11755
|
}
|
|
10392
11756
|
));
|
|
10393
11757
|
Table.displayName = "Table";
|
|
10394
|
-
var TableHeader =
|
|
11758
|
+
var TableHeader = React46.forwardRef(({ className, children, filterRow, ...props }, ref) => /* @__PURE__ */ jsxs49("thead", { ref, className: cn("[&_tr]:border-b [&_tr]:border-border", "bg-muted/50", className), ...props, children: [
|
|
10395
11759
|
children,
|
|
10396
11760
|
filterRow
|
|
10397
11761
|
] }));
|
|
10398
11762
|
TableHeader.displayName = "TableHeader";
|
|
10399
|
-
var TableBody =
|
|
11763
|
+
var TableBody = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
|
|
10400
11764
|
TableBody.displayName = "TableBody";
|
|
10401
|
-
var TableFooter =
|
|
11765
|
+
var TableFooter = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55("tfoot", { ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props }));
|
|
10402
11766
|
TableFooter.displayName = "TableFooter";
|
|
10403
|
-
var TableRow =
|
|
11767
|
+
var TableRow = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55(
|
|
10404
11768
|
"tr",
|
|
10405
11769
|
{
|
|
10406
11770
|
ref,
|
|
@@ -10414,7 +11778,7 @@ var TableRow = React38.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
10414
11778
|
}
|
|
10415
11779
|
));
|
|
10416
11780
|
TableRow.displayName = "TableRow";
|
|
10417
|
-
var TableHead =
|
|
11781
|
+
var TableHead = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55(
|
|
10418
11782
|
"th",
|
|
10419
11783
|
{
|
|
10420
11784
|
ref,
|
|
@@ -10423,18 +11787,18 @@ var TableHead = React38.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
10423
11787
|
}
|
|
10424
11788
|
));
|
|
10425
11789
|
TableHead.displayName = "TableHead";
|
|
10426
|
-
var TableCell =
|
|
11790
|
+
var TableCell = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55("td", { ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className), ...props }));
|
|
10427
11791
|
TableCell.displayName = "TableCell";
|
|
10428
|
-
var TableCaption =
|
|
11792
|
+
var TableCaption = React46.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx55("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
|
|
10429
11793
|
TableCaption.displayName = "TableCaption";
|
|
10430
11794
|
|
|
10431
11795
|
// ../../components/ui/DataTable.tsx
|
|
10432
11796
|
import { Filter as FilterIcon } from "lucide-react";
|
|
10433
|
-
import
|
|
10434
|
-
import { Fragment as
|
|
11797
|
+
import React47 from "react";
|
|
11798
|
+
import { Fragment as Fragment20, jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
10435
11799
|
function useDebounced(value, delay = 300) {
|
|
10436
|
-
const [debounced, setDebounced] =
|
|
10437
|
-
|
|
11800
|
+
const [debounced, setDebounced] = React47.useState(value);
|
|
11801
|
+
React47.useEffect(() => {
|
|
10438
11802
|
const id = setTimeout(() => setDebounced(value), delay);
|
|
10439
11803
|
return () => clearTimeout(id);
|
|
10440
11804
|
}, [value, delay]);
|
|
@@ -10463,15 +11827,15 @@ function DataTable({
|
|
|
10463
11827
|
labels
|
|
10464
11828
|
}) {
|
|
10465
11829
|
const t = useTranslations("Common");
|
|
10466
|
-
const [headerAlign, setHeaderAlign] =
|
|
10467
|
-
const [visibleCols, setVisibleCols] =
|
|
10468
|
-
const [filters, setFilters] =
|
|
10469
|
-
const [sort, setSort] =
|
|
10470
|
-
const [density, setDensity] =
|
|
10471
|
-
const [curPage, setCurPage] =
|
|
10472
|
-
const hasMounted =
|
|
10473
|
-
const loadedFromStorage =
|
|
10474
|
-
const getInitialPageSize =
|
|
11830
|
+
const [headerAlign, setHeaderAlign] = React47.useState("left");
|
|
11831
|
+
const [visibleCols, setVisibleCols] = React47.useState(() => columns.filter((c) => c.visible !== false).map((c) => c.key));
|
|
11832
|
+
const [filters, setFilters] = React47.useState({});
|
|
11833
|
+
const [sort, setSort] = React47.useState(null);
|
|
11834
|
+
const [density, setDensity] = React47.useState("normal");
|
|
11835
|
+
const [curPage, setCurPage] = React47.useState(page);
|
|
11836
|
+
const hasMounted = React47.useRef(false);
|
|
11837
|
+
const loadedFromStorage = React47.useRef(false);
|
|
11838
|
+
const getInitialPageSize = React47.useCallback(() => {
|
|
10475
11839
|
if (typeof window === "undefined" || !storageKey) return pageSize;
|
|
10476
11840
|
try {
|
|
10477
11841
|
const saved = localStorage.getItem(`datatable_${storageKey}_pageSize`);
|
|
@@ -10486,8 +11850,8 @@ function DataTable({
|
|
|
10486
11850
|
}
|
|
10487
11851
|
return pageSize;
|
|
10488
11852
|
}, [storageKey, pageSize]);
|
|
10489
|
-
const [curPageSize, setCurPageSize] =
|
|
10490
|
-
|
|
11853
|
+
const [curPageSize, setCurPageSize] = React47.useState(getInitialPageSize);
|
|
11854
|
+
React47.useEffect(() => {
|
|
10491
11855
|
if (typeof window === "undefined" || !storageKey) return;
|
|
10492
11856
|
if (!hasMounted.current) return;
|
|
10493
11857
|
try {
|
|
@@ -10495,7 +11859,7 @@ function DataTable({
|
|
|
10495
11859
|
} catch {
|
|
10496
11860
|
}
|
|
10497
11861
|
}, [curPageSize, storageKey]);
|
|
10498
|
-
|
|
11862
|
+
React47.useEffect(() => {
|
|
10499
11863
|
const newColKeys = columns.filter((c) => c.visible !== false).map((c) => c.key);
|
|
10500
11864
|
setVisibleCols((prev) => {
|
|
10501
11865
|
const uniqueKeys = /* @__PURE__ */ new Set([...prev, ...newColKeys]);
|
|
@@ -10503,16 +11867,16 @@ function DataTable({
|
|
|
10503
11867
|
});
|
|
10504
11868
|
}, [columns]);
|
|
10505
11869
|
const debouncedFilters = useDebounced(filters, 350);
|
|
10506
|
-
|
|
11870
|
+
React47.useEffect(() => {
|
|
10507
11871
|
setCurPage(page);
|
|
10508
11872
|
}, [page]);
|
|
10509
|
-
|
|
11873
|
+
React47.useEffect(() => {
|
|
10510
11874
|
if (storageKey && loadedFromStorage.current) {
|
|
10511
11875
|
return;
|
|
10512
11876
|
}
|
|
10513
11877
|
setCurPageSize(pageSize);
|
|
10514
11878
|
}, [pageSize, storageKey]);
|
|
10515
|
-
|
|
11879
|
+
React47.useEffect(() => {
|
|
10516
11880
|
if (!onQueryChange) return;
|
|
10517
11881
|
if (!hasMounted.current) {
|
|
10518
11882
|
hasMounted.current = true;
|
|
@@ -10535,7 +11899,7 @@ function DataTable({
|
|
|
10535
11899
|
className: "h-8 w-full text-sm"
|
|
10536
11900
|
};
|
|
10537
11901
|
if (col.filter.type === "text") {
|
|
10538
|
-
return /* @__PURE__ */
|
|
11902
|
+
return /* @__PURE__ */ jsx56(
|
|
10539
11903
|
Input_default,
|
|
10540
11904
|
{
|
|
10541
11905
|
...commonProps,
|
|
@@ -10550,7 +11914,7 @@ function DataTable({
|
|
|
10550
11914
|
}
|
|
10551
11915
|
if (col.filter.type === "select") {
|
|
10552
11916
|
const options = col.filter.options || [];
|
|
10553
|
-
return /* @__PURE__ */
|
|
11917
|
+
return /* @__PURE__ */ jsx56(
|
|
10554
11918
|
Combobox,
|
|
10555
11919
|
{
|
|
10556
11920
|
options: ["", ...options],
|
|
@@ -10566,7 +11930,7 @@ function DataTable({
|
|
|
10566
11930
|
);
|
|
10567
11931
|
}
|
|
10568
11932
|
if (col.filter.type === "date") {
|
|
10569
|
-
return /* @__PURE__ */
|
|
11933
|
+
return /* @__PURE__ */ jsx56(
|
|
10570
11934
|
DatePicker,
|
|
10571
11935
|
{
|
|
10572
11936
|
placeholder: col.filter.placeholder || `Select ${String(col.title)}`,
|
|
@@ -10580,7 +11944,7 @@ function DataTable({
|
|
|
10580
11944
|
}
|
|
10581
11945
|
return null;
|
|
10582
11946
|
};
|
|
10583
|
-
const renderHeader = /* @__PURE__ */
|
|
11947
|
+
const renderHeader = /* @__PURE__ */ jsx56(TableRow, { children: visibleColumns.map((col, colIdx) => /* @__PURE__ */ jsx56(
|
|
10584
11948
|
TableHead,
|
|
10585
11949
|
{
|
|
10586
11950
|
style: { width: col.width },
|
|
@@ -10593,9 +11957,9 @@ function DataTable({
|
|
|
10593
11957
|
children: (() => {
|
|
10594
11958
|
const isRightAlign = col.align === "right" || !col.align && headerAlign === "right";
|
|
10595
11959
|
const isCenterAlign = col.align === "center" || !col.align && headerAlign === "center";
|
|
10596
|
-
const titleContent = /* @__PURE__ */
|
|
10597
|
-
/* @__PURE__ */
|
|
10598
|
-
col.sortable && /* @__PURE__ */
|
|
11960
|
+
const titleContent = /* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-1 min-w-0 shrink", children: [
|
|
11961
|
+
/* @__PURE__ */ jsx56("span", { className: "truncate font-medium text-sm", children: col.title }),
|
|
11962
|
+
col.sortable && /* @__PURE__ */ jsx56(
|
|
10599
11963
|
"button",
|
|
10600
11964
|
{
|
|
10601
11965
|
className: cn(
|
|
@@ -10612,8 +11976,8 @@ function DataTable({
|
|
|
10612
11976
|
},
|
|
10613
11977
|
"aria-label": "Sort",
|
|
10614
11978
|
title: `Sort by ${String(col.title)}`,
|
|
10615
|
-
children: /* @__PURE__ */
|
|
10616
|
-
/* @__PURE__ */
|
|
11979
|
+
children: /* @__PURE__ */ jsxs50("svg", { width: "14", height: "14", viewBox: "0 0 20 20", fill: "none", className: "inline-block", children: [
|
|
11980
|
+
/* @__PURE__ */ jsx56(
|
|
10617
11981
|
"path",
|
|
10618
11982
|
{
|
|
10619
11983
|
d: "M7 8l3-3 3 3",
|
|
@@ -10624,7 +11988,7 @@ function DataTable({
|
|
|
10624
11988
|
opacity: sort?.key === col.key && sort.order === "asc" ? 1 : 0.4
|
|
10625
11989
|
}
|
|
10626
11990
|
),
|
|
10627
|
-
/* @__PURE__ */
|
|
11991
|
+
/* @__PURE__ */ jsx56(
|
|
10628
11992
|
"path",
|
|
10629
11993
|
{
|
|
10630
11994
|
d: "M7 12l3 3 3-3",
|
|
@@ -10639,11 +12003,11 @@ function DataTable({
|
|
|
10639
12003
|
}
|
|
10640
12004
|
)
|
|
10641
12005
|
] });
|
|
10642
|
-
const filterContent = col.filter && /* @__PURE__ */
|
|
12006
|
+
const filterContent = col.filter && /* @__PURE__ */ jsx56(
|
|
10643
12007
|
Popover,
|
|
10644
12008
|
{
|
|
10645
12009
|
placement: isRightAlign ? "bottom-end" : "bottom-start",
|
|
10646
|
-
trigger: /* @__PURE__ */
|
|
12010
|
+
trigger: /* @__PURE__ */ jsx56(
|
|
10647
12011
|
"button",
|
|
10648
12012
|
{
|
|
10649
12013
|
className: cn(
|
|
@@ -10653,16 +12017,16 @@ function DataTable({
|
|
|
10653
12017
|
),
|
|
10654
12018
|
"aria-label": "Filter",
|
|
10655
12019
|
title: "Filter",
|
|
10656
|
-
children: /* @__PURE__ */
|
|
12020
|
+
children: /* @__PURE__ */ jsx56(FilterIcon, { className: "h-4 w-4" })
|
|
10657
12021
|
}
|
|
10658
12022
|
),
|
|
10659
|
-
children: /* @__PURE__ */
|
|
10660
|
-
/* @__PURE__ */
|
|
12023
|
+
children: /* @__PURE__ */ jsxs50("div", { className: "w-48 p-2 space-y-2", children: [
|
|
12024
|
+
/* @__PURE__ */ jsxs50("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: [
|
|
10661
12025
|
"Filter ",
|
|
10662
12026
|
col.title
|
|
10663
12027
|
] }),
|
|
10664
12028
|
renderFilterControl(col),
|
|
10665
|
-
filters[col.key] && /* @__PURE__ */
|
|
12029
|
+
filters[col.key] && /* @__PURE__ */ jsx56(
|
|
10666
12030
|
"button",
|
|
10667
12031
|
{
|
|
10668
12032
|
onClick: () => {
|
|
@@ -10680,7 +12044,7 @@ function DataTable({
|
|
|
10680
12044
|
] })
|
|
10681
12045
|
}
|
|
10682
12046
|
);
|
|
10683
|
-
return /* @__PURE__ */
|
|
12047
|
+
return /* @__PURE__ */ jsx56(
|
|
10684
12048
|
"div",
|
|
10685
12049
|
{
|
|
10686
12050
|
className: cn(
|
|
@@ -10689,10 +12053,10 @@ function DataTable({
|
|
|
10689
12053
|
isCenterAlign && "justify-center",
|
|
10690
12054
|
!isRightAlign && !isCenterAlign && "justify-between"
|
|
10691
12055
|
),
|
|
10692
|
-
children: isRightAlign ? /* @__PURE__ */
|
|
12056
|
+
children: isRightAlign ? /* @__PURE__ */ jsxs50(Fragment20, { children: [
|
|
10693
12057
|
filterContent,
|
|
10694
12058
|
titleContent
|
|
10695
|
-
] }) : /* @__PURE__ */
|
|
12059
|
+
] }) : /* @__PURE__ */ jsxs50(Fragment20, { children: [
|
|
10696
12060
|
titleContent,
|
|
10697
12061
|
filterContent
|
|
10698
12062
|
] })
|
|
@@ -10703,7 +12067,7 @@ function DataTable({
|
|
|
10703
12067
|
col.key
|
|
10704
12068
|
)) });
|
|
10705
12069
|
const isServerMode = Boolean(onQueryChange);
|
|
10706
|
-
const processedData =
|
|
12070
|
+
const processedData = React47.useMemo(() => {
|
|
10707
12071
|
if (isServerMode) return data;
|
|
10708
12072
|
let result = [...data];
|
|
10709
12073
|
if (Object.keys(filters).length > 0) {
|
|
@@ -10735,21 +12099,21 @@ function DataTable({
|
|
|
10735
12099
|
return result;
|
|
10736
12100
|
}, [data, isServerMode, filters, sort, columns]);
|
|
10737
12101
|
const totalItems = isServerMode ? total : processedData.length;
|
|
10738
|
-
const displayedData = isServerMode ? data :
|
|
12102
|
+
const displayedData = isServerMode ? data : React47.useMemo(() => {
|
|
10739
12103
|
const start = (curPage - 1) * curPageSize;
|
|
10740
12104
|
if (start >= processedData.length && curPage > 1) {
|
|
10741
12105
|
}
|
|
10742
12106
|
return processedData.slice(start, start + curPageSize);
|
|
10743
12107
|
}, [processedData, curPage, curPageSize]);
|
|
10744
|
-
return /* @__PURE__ */
|
|
10745
|
-
/* @__PURE__ */
|
|
10746
|
-
/* @__PURE__ */
|
|
10747
|
-
/* @__PURE__ */
|
|
10748
|
-
enableDensityToggle && /* @__PURE__ */
|
|
12108
|
+
return /* @__PURE__ */ jsxs50("div", { className: cn("space-y-2", className), children: [
|
|
12109
|
+
/* @__PURE__ */ jsxs50("div", { className: "flex items-center justify-between gap-4 mb-1", children: [
|
|
12110
|
+
/* @__PURE__ */ jsx56("div", { className: "text-sm text-muted-foreground", children: caption }),
|
|
12111
|
+
/* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-2", children: [
|
|
12112
|
+
enableDensityToggle && /* @__PURE__ */ jsx56(
|
|
10749
12113
|
DropdownMenu_default,
|
|
10750
12114
|
{
|
|
10751
|
-
trigger: /* @__PURE__ */
|
|
10752
|
-
/* @__PURE__ */
|
|
12115
|
+
trigger: /* @__PURE__ */ jsxs50(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12116
|
+
/* @__PURE__ */ jsx56("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx56("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
|
|
10753
12117
|
labels?.density || t("density")
|
|
10754
12118
|
] }),
|
|
10755
12119
|
items: [
|
|
@@ -10759,11 +12123,11 @@ function DataTable({
|
|
|
10759
12123
|
]
|
|
10760
12124
|
}
|
|
10761
12125
|
),
|
|
10762
|
-
enableColumnVisibilityToggle && /* @__PURE__ */
|
|
12126
|
+
enableColumnVisibilityToggle && /* @__PURE__ */ jsx56(
|
|
10763
12127
|
DropdownMenu_default,
|
|
10764
12128
|
{
|
|
10765
|
-
trigger: /* @__PURE__ */
|
|
10766
|
-
/* @__PURE__ */
|
|
12129
|
+
trigger: /* @__PURE__ */ jsxs50(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12130
|
+
/* @__PURE__ */ jsx56("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx56(
|
|
10767
12131
|
"path",
|
|
10768
12132
|
{
|
|
10769
12133
|
strokeLinecap: "round",
|
|
@@ -10774,26 +12138,26 @@ function DataTable({
|
|
|
10774
12138
|
) }),
|
|
10775
12139
|
labels?.columns || t("columns")
|
|
10776
12140
|
] }),
|
|
10777
|
-
children: columns.map((c) => /* @__PURE__ */
|
|
12141
|
+
children: columns.map((c) => /* @__PURE__ */ jsxs50(
|
|
10778
12142
|
DropdownMenuItem,
|
|
10779
12143
|
{
|
|
10780
12144
|
onClick: () => {
|
|
10781
12145
|
setVisibleCols((prev) => prev.includes(c.key) ? prev.filter((k) => k !== c.key) : [...prev, c.key]);
|
|
10782
12146
|
},
|
|
10783
12147
|
children: [
|
|
10784
|
-
/* @__PURE__ */
|
|
10785
|
-
/* @__PURE__ */
|
|
12148
|
+
/* @__PURE__ */ jsx56("input", { type: "checkbox", className: "mr-2 rounded border-border", readOnly: true, checked: visibleCols.includes(c.key) }),
|
|
12149
|
+
/* @__PURE__ */ jsx56("span", { className: "truncate", children: c.title })
|
|
10786
12150
|
]
|
|
10787
12151
|
},
|
|
10788
12152
|
c.key
|
|
10789
12153
|
))
|
|
10790
12154
|
}
|
|
10791
12155
|
),
|
|
10792
|
-
enableHeaderAlignToggle && /* @__PURE__ */
|
|
12156
|
+
enableHeaderAlignToggle && /* @__PURE__ */ jsx56(
|
|
10793
12157
|
DropdownMenu_default,
|
|
10794
12158
|
{
|
|
10795
|
-
trigger: /* @__PURE__ */
|
|
10796
|
-
/* @__PURE__ */
|
|
12159
|
+
trigger: /* @__PURE__ */ jsxs50(Button_default, { variant: "ghost", size: "sm", className: "h-8 px-2", children: [
|
|
12160
|
+
/* @__PURE__ */ jsx56("svg", { className: "w-4 h-4 mr-1", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx56("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h10M4 18h16" }) }),
|
|
10797
12161
|
labels?.headerAlign || t("headerAlign")
|
|
10798
12162
|
] }),
|
|
10799
12163
|
items: [
|
|
@@ -10806,17 +12170,17 @@ function DataTable({
|
|
|
10806
12170
|
toolbar
|
|
10807
12171
|
] })
|
|
10808
12172
|
] }),
|
|
10809
|
-
/* @__PURE__ */
|
|
12173
|
+
/* @__PURE__ */ jsx56("div", { className: cn("relative rounded-md border border-border/50 overflow-hidden", loading2 && "opacity-60 pointer-events-none"), children: /* @__PURE__ */ jsxs50(
|
|
10810
12174
|
Table,
|
|
10811
12175
|
{
|
|
10812
12176
|
containerClassName: "border-0 md:border-0 rounded-none md:rounded-none shadow-none bg-transparent",
|
|
10813
12177
|
className: "[&_thead]:sticky [&_thead]:top-0 [&_thead]:z-5 [&_thead]:bg-background [&_thead]:backdrop-blur-sm",
|
|
10814
12178
|
children: [
|
|
10815
|
-
/* @__PURE__ */
|
|
10816
|
-
/* @__PURE__ */
|
|
10817
|
-
/* @__PURE__ */
|
|
10818
|
-
/* @__PURE__ */
|
|
10819
|
-
/* @__PURE__ */
|
|
12179
|
+
/* @__PURE__ */ jsx56(TableHeader, { children: renderHeader }),
|
|
12180
|
+
/* @__PURE__ */ jsx56(TableBody, { children: loading2 ? /* @__PURE__ */ jsx56(TableRow, { children: /* @__PURE__ */ jsx56(TableCell, { colSpan: visibleColumns.length, className: "text-center py-8", children: /* @__PURE__ */ jsxs50("div", { className: "flex items-center justify-center gap-2 text-muted-foreground", children: [
|
|
12181
|
+
/* @__PURE__ */ jsxs50("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
12182
|
+
/* @__PURE__ */ jsx56("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
12183
|
+
/* @__PURE__ */ jsx56(
|
|
10820
12184
|
"path",
|
|
10821
12185
|
{
|
|
10822
12186
|
className: "opacity-75",
|
|
@@ -10825,12 +12189,12 @@ function DataTable({
|
|
|
10825
12189
|
}
|
|
10826
12190
|
)
|
|
10827
12191
|
] }),
|
|
10828
|
-
/* @__PURE__ */
|
|
10829
|
-
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */
|
|
12192
|
+
/* @__PURE__ */ jsx56("span", { className: "text-sm", children: "Loading..." })
|
|
12193
|
+
] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ jsx56(TableRow, { children: /* @__PURE__ */ jsx56(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: "No data" }) }) : displayedData.map((row, idx) => {
|
|
10830
12194
|
const isLastRow = idx === displayedData.length - 1;
|
|
10831
|
-
return /* @__PURE__ */
|
|
12195
|
+
return /* @__PURE__ */ jsx56(TableRow, { className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/50"), children: visibleColumns.map((col, colIdx) => {
|
|
10832
12196
|
const value = col.dataIndex ? row[col.dataIndex] : void 0;
|
|
10833
|
-
return /* @__PURE__ */
|
|
12197
|
+
return /* @__PURE__ */ jsx56(
|
|
10834
12198
|
TableCell,
|
|
10835
12199
|
{
|
|
10836
12200
|
className: cn(
|
|
@@ -10850,7 +12214,7 @@ function DataTable({
|
|
|
10850
12214
|
]
|
|
10851
12215
|
}
|
|
10852
12216
|
) }),
|
|
10853
|
-
totalItems > 0 && /* @__PURE__ */
|
|
12217
|
+
totalItems > 0 && /* @__PURE__ */ jsx56("div", { className: "border-t bg-muted/30 p-4 rounded-b-md", children: /* @__PURE__ */ jsx56(
|
|
10854
12218
|
Pagination,
|
|
10855
12219
|
{
|
|
10856
12220
|
page: curPage,
|
|
@@ -10872,10 +12236,10 @@ function DataTable({
|
|
|
10872
12236
|
var DataTable_default = DataTable;
|
|
10873
12237
|
|
|
10874
12238
|
// ../../components/ui/Form.tsx
|
|
10875
|
-
import * as
|
|
12239
|
+
import * as React48 from "react";
|
|
10876
12240
|
import { Controller, FormProvider, useFormContext, useForm } from "react-hook-form";
|
|
10877
|
-
import { jsx as
|
|
10878
|
-
var FormConfigContext =
|
|
12241
|
+
import { jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
12242
|
+
var FormConfigContext = React48.createContext({ size: "md" });
|
|
10879
12243
|
var FormWrapper = ({
|
|
10880
12244
|
children,
|
|
10881
12245
|
onSubmit,
|
|
@@ -10888,24 +12252,24 @@ var FormWrapper = ({
|
|
|
10888
12252
|
const methods = useForm({
|
|
10889
12253
|
defaultValues: initialValues
|
|
10890
12254
|
});
|
|
10891
|
-
|
|
12255
|
+
React48.useEffect(() => {
|
|
10892
12256
|
if (initialValues) {
|
|
10893
12257
|
methods.reset(initialValues);
|
|
10894
12258
|
}
|
|
10895
12259
|
}, [JSON.stringify(initialValues)]);
|
|
10896
12260
|
const { validationSchema: _, ...formProps } = props;
|
|
10897
|
-
return /* @__PURE__ */
|
|
12261
|
+
return /* @__PURE__ */ jsx57(FormProvider, { ...methods, children: /* @__PURE__ */ jsx57(FormConfigContext.Provider, { value: { size }, children: /* @__PURE__ */ jsx57("form", { onSubmit: methods.handleSubmit(onSubmit), className, ...formProps, children }) }) });
|
|
10898
12262
|
};
|
|
10899
12263
|
var Form = FormWrapper;
|
|
10900
|
-
var FormFieldContext =
|
|
12264
|
+
var FormFieldContext = React48.createContext({});
|
|
10901
12265
|
var FormField = ({
|
|
10902
12266
|
...props
|
|
10903
12267
|
}) => {
|
|
10904
|
-
return /* @__PURE__ */
|
|
12268
|
+
return /* @__PURE__ */ jsx57(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx57(Controller, { ...props }) });
|
|
10905
12269
|
};
|
|
10906
12270
|
var useFormField = () => {
|
|
10907
|
-
const fieldContext =
|
|
10908
|
-
const itemContext =
|
|
12271
|
+
const fieldContext = React48.useContext(FormFieldContext);
|
|
12272
|
+
const itemContext = React48.useContext(FormItemContext);
|
|
10909
12273
|
const { getFieldState, formState } = useFormContext();
|
|
10910
12274
|
if (!fieldContext) {
|
|
10911
12275
|
try {
|
|
@@ -10926,27 +12290,27 @@ var useFormField = () => {
|
|
|
10926
12290
|
...fieldState
|
|
10927
12291
|
};
|
|
10928
12292
|
};
|
|
10929
|
-
var FormItemContext =
|
|
10930
|
-
var FormItem =
|
|
10931
|
-
const id =
|
|
10932
|
-
return /* @__PURE__ */
|
|
12293
|
+
var FormItemContext = React48.createContext({});
|
|
12294
|
+
var FormItem = React48.forwardRef(({ className, ...props }, ref) => {
|
|
12295
|
+
const id = React48.useId();
|
|
12296
|
+
return /* @__PURE__ */ jsx57(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx57("div", { ref, className: cn("space-y-2", className), ...props }) });
|
|
10933
12297
|
});
|
|
10934
12298
|
FormItem.displayName = "FormItem";
|
|
10935
|
-
var FormLabel =
|
|
12299
|
+
var FormLabel = React48.forwardRef(
|
|
10936
12300
|
({ className, children, required, ...props }, ref) => {
|
|
10937
12301
|
const { error, formItemId } = useFormField();
|
|
10938
|
-
const config =
|
|
12302
|
+
const config = React48.useContext(FormConfigContext);
|
|
10939
12303
|
const sizeClass = config.size === "sm" ? "text-xs" : config.size === "lg" ? "text-base" : "text-sm";
|
|
10940
|
-
return /* @__PURE__ */
|
|
12304
|
+
return /* @__PURE__ */ jsxs51(Label, { ref, className: cn(sizeClass, error && "text-destructive", className), htmlFor: formItemId, ...props, children: [
|
|
10941
12305
|
children,
|
|
10942
|
-
required && /* @__PURE__ */
|
|
12306
|
+
required && /* @__PURE__ */ jsx57("span", { className: "text-destructive ml-1", children: "*" })
|
|
10943
12307
|
] });
|
|
10944
12308
|
}
|
|
10945
12309
|
);
|
|
10946
12310
|
FormLabel.displayName = "FormLabel";
|
|
10947
|
-
var FormControl =
|
|
12311
|
+
var FormControl = React48.forwardRef(({ ...props }, ref) => {
|
|
10948
12312
|
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
|
|
10949
|
-
return /* @__PURE__ */
|
|
12313
|
+
return /* @__PURE__ */ jsx57(
|
|
10950
12314
|
"div",
|
|
10951
12315
|
{
|
|
10952
12316
|
ref,
|
|
@@ -10958,37 +12322,37 @@ var FormControl = React40.forwardRef(({ ...props }, ref) => {
|
|
|
10958
12322
|
);
|
|
10959
12323
|
});
|
|
10960
12324
|
FormControl.displayName = "FormControl";
|
|
10961
|
-
var FormDescription =
|
|
12325
|
+
var FormDescription = React48.forwardRef(({ className, ...props }, ref) => {
|
|
10962
12326
|
const { formDescriptionId } = useFormField();
|
|
10963
|
-
return /* @__PURE__ */
|
|
12327
|
+
return /* @__PURE__ */ jsx57("p", { ref, id: formDescriptionId, className: cn("text-sm text-muted-foreground", className), ...props });
|
|
10964
12328
|
});
|
|
10965
12329
|
FormDescription.displayName = "FormDescription";
|
|
10966
|
-
var FormMessage =
|
|
12330
|
+
var FormMessage = React48.forwardRef(({ className, children, ...props }, ref) => {
|
|
10967
12331
|
const { error, formMessageId } = useFormField();
|
|
10968
12332
|
const body = error ? String(error?.message) : children;
|
|
10969
12333
|
if (!body) {
|
|
10970
12334
|
return null;
|
|
10971
12335
|
}
|
|
10972
|
-
return /* @__PURE__ */
|
|
12336
|
+
return /* @__PURE__ */ jsx57("p", { ref, id: formMessageId, className: cn("text-sm font-medium text-destructive", className), ...props, children: body });
|
|
10973
12337
|
});
|
|
10974
12338
|
FormMessage.displayName = "FormMessage";
|
|
10975
|
-
var FormInput =
|
|
12339
|
+
var FormInput = React48.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ jsx57(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ jsx57(
|
|
10976
12340
|
FormField,
|
|
10977
12341
|
{
|
|
10978
12342
|
name,
|
|
10979
|
-
render: ({ field }) => /* @__PURE__ */
|
|
10980
|
-
/* @__PURE__ */
|
|
10981
|
-
/* @__PURE__ */
|
|
12343
|
+
render: ({ field }) => /* @__PURE__ */ jsxs51(FormItem, { children: [
|
|
12344
|
+
/* @__PURE__ */ jsx57(FormControl, { children: /* @__PURE__ */ jsx57(Input_default, { size: props.size ?? size, ...field, ...props }) }),
|
|
12345
|
+
/* @__PURE__ */ jsx57(FormMessage, {})
|
|
10982
12346
|
] })
|
|
10983
12347
|
}
|
|
10984
12348
|
) }));
|
|
10985
12349
|
FormInput.displayName = "FormInput";
|
|
10986
|
-
var FormCheckbox =
|
|
12350
|
+
var FormCheckbox = React48.forwardRef(({ name, ...props }, ref) => /* @__PURE__ */ jsx57(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ jsx57(
|
|
10987
12351
|
FormField,
|
|
10988
12352
|
{
|
|
10989
12353
|
name,
|
|
10990
|
-
render: ({ field }) => /* @__PURE__ */
|
|
10991
|
-
/* @__PURE__ */
|
|
12354
|
+
render: ({ field }) => /* @__PURE__ */ jsxs51(FormItem, { children: [
|
|
12355
|
+
/* @__PURE__ */ jsx57(FormControl, { children: /* @__PURE__ */ jsx57(
|
|
10992
12356
|
Checkbox,
|
|
10993
12357
|
{
|
|
10994
12358
|
ref,
|
|
@@ -11002,21 +12366,21 @@ var FormCheckbox = React40.forwardRef(({ name, ...props }, ref) => /* @__PURE__
|
|
|
11002
12366
|
...props
|
|
11003
12367
|
}
|
|
11004
12368
|
) }),
|
|
11005
|
-
/* @__PURE__ */
|
|
12369
|
+
/* @__PURE__ */ jsx57(FormMessage, {})
|
|
11006
12370
|
] })
|
|
11007
12371
|
}
|
|
11008
12372
|
) }));
|
|
11009
12373
|
FormCheckbox.displayName = "FormCheckbox";
|
|
11010
|
-
var FormActions =
|
|
12374
|
+
var FormActions = React48.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx57("div", { ref, className: cn("flex gap-2 justify-end", className), ...props }));
|
|
11011
12375
|
FormActions.displayName = "FormActions";
|
|
11012
|
-
var FormSubmitButton =
|
|
11013
|
-
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */
|
|
12376
|
+
var FormSubmitButton = React48.forwardRef(
|
|
12377
|
+
({ children, loading: loading2, ...props }, ref) => /* @__PURE__ */ jsx57(FormConfigContext.Consumer, { children: ({ size }) => /* @__PURE__ */ jsx57(Button_default, { ref, type: "submit", size: props.size ?? size, disabled: loading2, ...props, children }) })
|
|
11014
12378
|
);
|
|
11015
12379
|
FormSubmitButton.displayName = "FormSubmitButton";
|
|
11016
12380
|
|
|
11017
12381
|
// ../../components/ui/NotificationModal.tsx
|
|
11018
12382
|
import { ExternalLink } from "lucide-react";
|
|
11019
|
-
import { jsx as
|
|
12383
|
+
import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
11020
12384
|
function NotificationModal({ isOpen, onClose, notification, titleText, openLinkText, closeText }) {
|
|
11021
12385
|
const t = useTranslations("Common");
|
|
11022
12386
|
if (!notification) return null;
|
|
@@ -11037,20 +12401,20 @@ function NotificationModal({ isOpen, onClose, notification, titleText, openLinkT
|
|
|
11037
12401
|
onClose();
|
|
11038
12402
|
}
|
|
11039
12403
|
};
|
|
11040
|
-
return /* @__PURE__ */
|
|
11041
|
-
/* @__PURE__ */
|
|
11042
|
-
/* @__PURE__ */
|
|
11043
|
-
/* @__PURE__ */
|
|
12404
|
+
return /* @__PURE__ */ jsx58(Modal_default, { isOpen, onClose, title: titleText || t("notifications"), size: "md", children: /* @__PURE__ */ jsxs52("div", { className: "space-y-4", children: [
|
|
12405
|
+
/* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-2 pb-2 border-b border-border", children: [
|
|
12406
|
+
/* @__PURE__ */ jsx58("div", { className: cn("w-2 h-2 rounded-full", !notification.is_read ? "bg-primary" : "bg-border") }),
|
|
12407
|
+
/* @__PURE__ */ jsx58("span", { className: "text-xs text-muted-foreground", children: !notification.is_read ? t("newNotification") : t("readStatus") })
|
|
11044
12408
|
] }),
|
|
11045
|
-
notification.title && /* @__PURE__ */
|
|
11046
|
-
notification.body && /* @__PURE__ */
|
|
11047
|
-
/* @__PURE__ */
|
|
11048
|
-
/* @__PURE__ */
|
|
11049
|
-
hasLink && /* @__PURE__ */
|
|
11050
|
-
/* @__PURE__ */
|
|
12409
|
+
notification.title && /* @__PURE__ */ jsx58("h3", { className: "text-lg font-semibold text-foreground", children: notification.title }),
|
|
12410
|
+
notification.body && /* @__PURE__ */ jsx58("div", { className: "text-sm text-muted-foreground whitespace-pre-wrap leading-relaxed", children: notification.body }),
|
|
12411
|
+
/* @__PURE__ */ jsx58("div", { className: "text-xs text-muted-foreground border-t border-border pt-2", children: formatTime3(notification.created_at) }),
|
|
12412
|
+
/* @__PURE__ */ jsxs52("div", { className: "flex gap-2 justify-end pt-2", children: [
|
|
12413
|
+
hasLink && /* @__PURE__ */ jsxs52(Button_default, { variant: "primary", size: "sm", onClick: handleLinkClick, className: "gap-2", children: [
|
|
12414
|
+
/* @__PURE__ */ jsx58(ExternalLink, { className: "w-4 h-4" }),
|
|
11051
12415
|
openLinkText || t("openLink")
|
|
11052
12416
|
] }),
|
|
11053
|
-
/* @__PURE__ */
|
|
12417
|
+
/* @__PURE__ */ jsx58(Button_default, { variant: "ghost", size: "sm", onClick: onClose, children: closeText || t("close") })
|
|
11054
12418
|
] })
|
|
11055
12419
|
] }) });
|
|
11056
12420
|
}
|
|
@@ -11060,9 +12424,9 @@ var NotificationModal_default = NotificationModal;
|
|
|
11060
12424
|
import Link2 from "next/link";
|
|
11061
12425
|
import { usePathname } from "next/navigation";
|
|
11062
12426
|
import { Phone } from "lucide-react";
|
|
11063
|
-
import { jsx as
|
|
12427
|
+
import { jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
11064
12428
|
function MessengerIcon(props) {
|
|
11065
|
-
return /* @__PURE__ */
|
|
12429
|
+
return /* @__PURE__ */ jsx59("svg", { viewBox: "0 0 24 24", width: 24, height: 24, "aria-hidden": "true", ...props, children: /* @__PURE__ */ jsx59(
|
|
11066
12430
|
"path",
|
|
11067
12431
|
{
|
|
11068
12432
|
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",
|
|
@@ -11071,7 +12435,7 @@ function MessengerIcon(props) {
|
|
|
11071
12435
|
) });
|
|
11072
12436
|
}
|
|
11073
12437
|
function ZaloIcon(props) {
|
|
11074
|
-
return /* @__PURE__ */
|
|
12438
|
+
return /* @__PURE__ */ jsx59("svg", { viewBox: "0 0 48 48", width: 20, height: 20, "aria-hidden": "true", ...props, children: /* @__PURE__ */ jsx59(
|
|
11075
12439
|
"path",
|
|
11076
12440
|
{
|
|
11077
12441
|
fill: "white",
|
|
@@ -11080,7 +12444,7 @@ function ZaloIcon(props) {
|
|
|
11080
12444
|
) });
|
|
11081
12445
|
}
|
|
11082
12446
|
function InstagramIcon(props) {
|
|
11083
|
-
return /* @__PURE__ */
|
|
12447
|
+
return /* @__PURE__ */ jsx59("svg", { viewBox: "0 0 24 24", width: 20, height: 20, "aria-hidden": "true", fill: "white", ...props, children: /* @__PURE__ */ jsx59("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" }) });
|
|
11084
12448
|
}
|
|
11085
12449
|
function FloatingContacts({ className }) {
|
|
11086
12450
|
const pathname = usePathname();
|
|
@@ -11115,8 +12479,8 @@ function FloatingContacts({ className }) {
|
|
|
11115
12479
|
external: true
|
|
11116
12480
|
}
|
|
11117
12481
|
];
|
|
11118
|
-
return /* @__PURE__ */
|
|
11119
|
-
/* @__PURE__ */
|
|
12482
|
+
return /* @__PURE__ */ jsxs53("div", { className: cn("fixed bottom-6 right-4 z-100000", "flex flex-col items-end gap-3", className), "aria-label": "Quick contacts", children: [
|
|
12483
|
+
/* @__PURE__ */ jsx59(
|
|
11120
12484
|
Link2,
|
|
11121
12485
|
{
|
|
11122
12486
|
href: `tel:${hotline.replace(/\D/g, "")}`,
|
|
@@ -11127,10 +12491,10 @@ function FloatingContacts({ className }) {
|
|
|
11127
12491
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
11128
12492
|
"bg-[#22c55e]"
|
|
11129
12493
|
),
|
|
11130
|
-
children: /* @__PURE__ */
|
|
12494
|
+
children: /* @__PURE__ */ jsx59(Phone, { className: "w-6 h-6" })
|
|
11131
12495
|
}
|
|
11132
12496
|
),
|
|
11133
|
-
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */
|
|
12497
|
+
moreItems.map(({ key, href, label, bg, Icon, external }) => /* @__PURE__ */ jsx59(
|
|
11134
12498
|
Link2,
|
|
11135
12499
|
{
|
|
11136
12500
|
href,
|
|
@@ -11142,7 +12506,7 @@ function FloatingContacts({ className }) {
|
|
|
11142
12506
|
"hover:scale-105 active:scale-95 transition-transform",
|
|
11143
12507
|
bg
|
|
11144
12508
|
),
|
|
11145
|
-
children: /* @__PURE__ */
|
|
12509
|
+
children: /* @__PURE__ */ jsx59(Icon, { className: "w-6 h-6" })
|
|
11146
12510
|
},
|
|
11147
12511
|
key
|
|
11148
12512
|
))
|
|
@@ -11151,7 +12515,7 @@ function FloatingContacts({ className }) {
|
|
|
11151
12515
|
|
|
11152
12516
|
// ../../components/ui/AccessDenied.tsx
|
|
11153
12517
|
import { Ban, Lock, ShieldAlert } from "lucide-react";
|
|
11154
|
-
import { jsx as
|
|
12518
|
+
import { jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
11155
12519
|
var VARIANT_STYLES = {
|
|
11156
12520
|
destructive: { bg: "bg-destructive/5", border: "border-destructive/20", text: "text-destructive" },
|
|
11157
12521
|
warning: { bg: "bg-warning/5", border: "border-warning/20", text: "text-warning" },
|
|
@@ -11172,32 +12536,32 @@ function AccessDenied({
|
|
|
11172
12536
|
}) {
|
|
11173
12537
|
const styles = VARIANT_STYLES[variant];
|
|
11174
12538
|
const UsedIcon = Icon || DEFAULT_ICONS[variant];
|
|
11175
|
-
return /* @__PURE__ */
|
|
11176
|
-
/* @__PURE__ */
|
|
11177
|
-
/* @__PURE__ */
|
|
11178
|
-
/* @__PURE__ */
|
|
11179
|
-
/* @__PURE__ */
|
|
12539
|
+
return /* @__PURE__ */ jsx60(Card_default, { className: cn("p-8 text-center shadow-sm", styles.bg, styles.border, className), children: /* @__PURE__ */ jsxs54("div", { className: "flex flex-col items-center gap-4", children: [
|
|
12540
|
+
/* @__PURE__ */ jsx60("div", { className: cn("p-3 rounded-lg", styles.bg.replace("/5", "/10")), children: /* @__PURE__ */ jsx60(UsedIcon, { className: cn("w-8 h-8", styles.text) }) }),
|
|
12541
|
+
/* @__PURE__ */ jsxs54("div", { children: [
|
|
12542
|
+
/* @__PURE__ */ jsx60("h3", { className: cn("font-semibold mb-2", styles.text), children: title }),
|
|
12543
|
+
/* @__PURE__ */ jsx60("p", { className: cn(styles.text.replace("text-", "text-") + "/80", "text-sm"), children: description })
|
|
11180
12544
|
] }),
|
|
11181
|
-
children && /* @__PURE__ */
|
|
12545
|
+
children && /* @__PURE__ */ jsx60("div", { className: "mt-2 flex flex-wrap gap-2 justify-center", children })
|
|
11182
12546
|
] }) });
|
|
11183
12547
|
}
|
|
11184
12548
|
|
|
11185
12549
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
11186
12550
|
import { Moon, Sun, Monitor } from "lucide-react";
|
|
11187
|
-
import { useEffect as
|
|
11188
|
-
import { createPortal as
|
|
11189
|
-
import { Fragment as
|
|
12551
|
+
import { useEffect as useEffect21, useRef as useRef19, useState as useState39 } from "react";
|
|
12552
|
+
import { createPortal as createPortal11 } from "react-dom";
|
|
12553
|
+
import { Fragment as Fragment21, jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
11190
12554
|
function ThemeToggleHeadless({
|
|
11191
12555
|
theme,
|
|
11192
12556
|
onChange,
|
|
11193
12557
|
labels,
|
|
11194
12558
|
className
|
|
11195
12559
|
}) {
|
|
11196
|
-
const [isOpen, setIsOpen] =
|
|
11197
|
-
const [mounted, setMounted] =
|
|
11198
|
-
const triggerRef =
|
|
11199
|
-
const [dropdownPosition, setDropdownPosition] =
|
|
11200
|
-
|
|
12560
|
+
const [isOpen, setIsOpen] = useState39(false);
|
|
12561
|
+
const [mounted, setMounted] = useState39(false);
|
|
12562
|
+
const triggerRef = useRef19(null);
|
|
12563
|
+
const [dropdownPosition, setDropdownPosition] = useState39(null);
|
|
12564
|
+
useEffect21(() => setMounted(true), []);
|
|
11201
12565
|
const themes = [
|
|
11202
12566
|
{ value: "light", label: labels?.light ?? "Light", icon: Sun },
|
|
11203
12567
|
{ value: "dark", label: labels?.dark ?? "Dark", icon: Moon },
|
|
@@ -11215,8 +12579,8 @@ function ThemeToggleHeadless({
|
|
|
11215
12579
|
const top = rect.bottom + scrollTop + 8;
|
|
11216
12580
|
return { top, left, width };
|
|
11217
12581
|
};
|
|
11218
|
-
return /* @__PURE__ */
|
|
11219
|
-
/* @__PURE__ */
|
|
12582
|
+
return /* @__PURE__ */ jsxs55("div", { className: cn("relative", className), children: [
|
|
12583
|
+
/* @__PURE__ */ jsx61(
|
|
11220
12584
|
Button_default,
|
|
11221
12585
|
{
|
|
11222
12586
|
variant: "ghost",
|
|
@@ -11234,25 +12598,25 @@ function ThemeToggleHeadless({
|
|
|
11234
12598
|
"aria-haspopup": "menu",
|
|
11235
12599
|
"aria-expanded": isOpen,
|
|
11236
12600
|
"aria-label": labels?.heading ?? "Theme",
|
|
11237
|
-
children: /* @__PURE__ */
|
|
12601
|
+
children: /* @__PURE__ */ jsx61(CurrentIcon, { className: "h-5 w-5" })
|
|
11238
12602
|
}
|
|
11239
12603
|
),
|
|
11240
|
-
isOpen && /* @__PURE__ */
|
|
11241
|
-
typeof window !== "undefined" &&
|
|
11242
|
-
typeof window !== "undefined" && dropdownPosition &&
|
|
11243
|
-
/* @__PURE__ */
|
|
12604
|
+
isOpen && /* @__PURE__ */ jsxs55(Fragment21, { children: [
|
|
12605
|
+
typeof window !== "undefined" && createPortal11(/* @__PURE__ */ jsx61("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
12606
|
+
typeof window !== "undefined" && dropdownPosition && createPortal11(
|
|
12607
|
+
/* @__PURE__ */ jsx61(
|
|
11244
12608
|
"div",
|
|
11245
12609
|
{
|
|
11246
12610
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
11247
12611
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
11248
12612
|
onMouseDown: (e) => e.stopPropagation(),
|
|
11249
12613
|
role: "menu",
|
|
11250
|
-
children: /* @__PURE__ */
|
|
11251
|
-
/* @__PURE__ */
|
|
12614
|
+
children: /* @__PURE__ */ jsxs55("div", { className: "p-2", children: [
|
|
12615
|
+
/* @__PURE__ */ jsx61("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Theme" }),
|
|
11252
12616
|
themes.map((opt) => {
|
|
11253
12617
|
const Icon = opt.icon;
|
|
11254
12618
|
const active = theme === opt.value;
|
|
11255
|
-
return /* @__PURE__ */
|
|
12619
|
+
return /* @__PURE__ */ jsxs55(
|
|
11256
12620
|
Button_default,
|
|
11257
12621
|
{
|
|
11258
12622
|
variant: "ghost",
|
|
@@ -11268,9 +12632,9 @@ function ThemeToggleHeadless({
|
|
|
11268
12632
|
role: "menuitemradio",
|
|
11269
12633
|
"aria-checked": active,
|
|
11270
12634
|
children: [
|
|
11271
|
-
/* @__PURE__ */
|
|
11272
|
-
/* @__PURE__ */
|
|
11273
|
-
active && /* @__PURE__ */
|
|
12635
|
+
/* @__PURE__ */ jsx61(Icon, { className: "h-4 w-4" }),
|
|
12636
|
+
/* @__PURE__ */ jsx61("span", { className: "flex-1 text-left", children: opt.label }),
|
|
12637
|
+
active && /* @__PURE__ */ jsx61("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
11274
12638
|
]
|
|
11275
12639
|
},
|
|
11276
12640
|
opt.value
|
|
@@ -11286,10 +12650,10 @@ function ThemeToggleHeadless({
|
|
|
11286
12650
|
}
|
|
11287
12651
|
|
|
11288
12652
|
// ../../components/ui/LanguageSwitcherHeadless.tsx
|
|
11289
|
-
import { useRef as
|
|
11290
|
-
import { createPortal as
|
|
12653
|
+
import { useRef as useRef20, useState as useState40 } from "react";
|
|
12654
|
+
import { createPortal as createPortal12 } from "react-dom";
|
|
11291
12655
|
import { Globe } from "lucide-react";
|
|
11292
|
-
import { Fragment as
|
|
12656
|
+
import { Fragment as Fragment22, jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
11293
12657
|
function LanguageSwitcherHeadless({
|
|
11294
12658
|
locales,
|
|
11295
12659
|
currentLocale,
|
|
@@ -11297,9 +12661,9 @@ function LanguageSwitcherHeadless({
|
|
|
11297
12661
|
labels,
|
|
11298
12662
|
className
|
|
11299
12663
|
}) {
|
|
11300
|
-
const [isOpen, setIsOpen] =
|
|
11301
|
-
const [dropdownPosition, setDropdownPosition] =
|
|
11302
|
-
const triggerButtonRef =
|
|
12664
|
+
const [isOpen, setIsOpen] = useState40(false);
|
|
12665
|
+
const [dropdownPosition, setDropdownPosition] = useState40(null);
|
|
12666
|
+
const triggerButtonRef = useRef20(null);
|
|
11303
12667
|
const currentLanguage = locales.find((l) => l.code === currentLocale) || locales[0];
|
|
11304
12668
|
const calculatePosition = () => {
|
|
11305
12669
|
const rect = triggerButtonRef.current?.getBoundingClientRect();
|
|
@@ -11311,8 +12675,8 @@ function LanguageSwitcherHeadless({
|
|
|
11311
12675
|
const top = rect.bottom + scrollTop + 8;
|
|
11312
12676
|
return { top, left, width };
|
|
11313
12677
|
};
|
|
11314
|
-
return /* @__PURE__ */
|
|
11315
|
-
/* @__PURE__ */
|
|
12678
|
+
return /* @__PURE__ */ jsxs56("div", { className: cn("relative", className), children: [
|
|
12679
|
+
/* @__PURE__ */ jsx62(
|
|
11316
12680
|
Button_default,
|
|
11317
12681
|
{
|
|
11318
12682
|
variant: "ghost",
|
|
@@ -11331,22 +12695,22 @@ function LanguageSwitcherHeadless({
|
|
|
11331
12695
|
"aria-expanded": isOpen,
|
|
11332
12696
|
"aria-label": labels?.heading ?? "Language",
|
|
11333
12697
|
title: labels?.heading ?? "Language",
|
|
11334
|
-
children: /* @__PURE__ */
|
|
12698
|
+
children: /* @__PURE__ */ jsx62(Globe, { className: "h-5 w-5" })
|
|
11335
12699
|
}
|
|
11336
12700
|
),
|
|
11337
|
-
isOpen && /* @__PURE__ */
|
|
11338
|
-
typeof window !== "undefined" &&
|
|
11339
|
-
typeof window !== "undefined" && dropdownPosition &&
|
|
11340
|
-
/* @__PURE__ */
|
|
12701
|
+
isOpen && /* @__PURE__ */ jsxs56(Fragment22, { children: [
|
|
12702
|
+
typeof window !== "undefined" && createPortal12(/* @__PURE__ */ jsx62("div", { className: "fixed inset-0 z-9998", onClick: () => setIsOpen(false) }), document.body),
|
|
12703
|
+
typeof window !== "undefined" && dropdownPosition && createPortal12(
|
|
12704
|
+
/* @__PURE__ */ jsx62(
|
|
11341
12705
|
"div",
|
|
11342
12706
|
{
|
|
11343
12707
|
className: "z-9999 bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
11344
12708
|
style: { position: "absolute", top: dropdownPosition.top, left: dropdownPosition.left, width: dropdownPosition.width },
|
|
11345
12709
|
onMouseDown: (e) => e.stopPropagation(),
|
|
11346
12710
|
role: "menu",
|
|
11347
|
-
children: /* @__PURE__ */
|
|
11348
|
-
/* @__PURE__ */
|
|
11349
|
-
locales.map((language) => /* @__PURE__ */
|
|
12711
|
+
children: /* @__PURE__ */ jsxs56("div", { className: "p-2", children: [
|
|
12712
|
+
/* @__PURE__ */ jsx62("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground border-b border-border mb-2", children: labels?.heading ?? "Language" }),
|
|
12713
|
+
locales.map((language) => /* @__PURE__ */ jsxs56(
|
|
11350
12714
|
Button_default,
|
|
11351
12715
|
{
|
|
11352
12716
|
variant: "ghost",
|
|
@@ -11359,9 +12723,9 @@ function LanguageSwitcherHeadless({
|
|
|
11359
12723
|
role: "menuitemradio",
|
|
11360
12724
|
"aria-checked": currentLocale === language.code,
|
|
11361
12725
|
children: [
|
|
11362
|
-
language.flag && /* @__PURE__ */
|
|
11363
|
-
/* @__PURE__ */
|
|
11364
|
-
currentLocale === language.code && /* @__PURE__ */
|
|
12726
|
+
language.flag && /* @__PURE__ */ jsx62("span", { className: "text-lg", children: language.flag }),
|
|
12727
|
+
/* @__PURE__ */ jsx62("span", { className: "flex-1 text-left", children: language.name }),
|
|
12728
|
+
currentLocale === language.code && /* @__PURE__ */ jsx62("div", { className: "w-2 h-2 rounded-full bg-primary" })
|
|
11365
12729
|
]
|
|
11366
12730
|
},
|
|
11367
12731
|
language.code
|
|
@@ -11791,7 +13155,7 @@ var VARIANT_STYLES_ALERT = {
|
|
|
11791
13155
|
};
|
|
11792
13156
|
|
|
11793
13157
|
// src/contexts/TranslationContext.tsx
|
|
11794
|
-
import * as
|
|
13158
|
+
import * as React50 from "react";
|
|
11795
13159
|
|
|
11796
13160
|
// locales/en.json
|
|
11797
13161
|
var en_default = {
|
|
@@ -12046,16 +13410,16 @@ var ja_default = {
|
|
|
12046
13410
|
};
|
|
12047
13411
|
|
|
12048
13412
|
// src/contexts/TranslationContext.tsx
|
|
12049
|
-
import { jsx as
|
|
13413
|
+
import { jsx as jsx63 } from "react/jsx-runtime";
|
|
12050
13414
|
var defaultTranslations2 = {
|
|
12051
13415
|
en: en_default,
|
|
12052
13416
|
vi: vi_default,
|
|
12053
13417
|
ko: ko_default,
|
|
12054
13418
|
ja: ja_default
|
|
12055
13419
|
};
|
|
12056
|
-
var TranslationContext2 =
|
|
13420
|
+
var TranslationContext2 = React50.createContext(null);
|
|
12057
13421
|
var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
12058
|
-
const t =
|
|
13422
|
+
const t = React50.useCallback(
|
|
12059
13423
|
(namespace) => {
|
|
12060
13424
|
return (key) => {
|
|
12061
13425
|
const mergedTranslations = {
|
|
@@ -12080,10 +13444,10 @@ var TranslationProvider = ({ children, locale = "en", translations }) => {
|
|
|
12080
13444
|
},
|
|
12081
13445
|
[locale, translations]
|
|
12082
13446
|
);
|
|
12083
|
-
return /* @__PURE__ */
|
|
13447
|
+
return /* @__PURE__ */ jsx63(TranslationContext2.Provider, { value: { locale, t }, children });
|
|
12084
13448
|
};
|
|
12085
13449
|
var useUnderverseTranslations = (namespace) => {
|
|
12086
|
-
const context =
|
|
13450
|
+
const context = React50.useContext(TranslationContext2);
|
|
12087
13451
|
if (!context) {
|
|
12088
13452
|
return (key) => {
|
|
12089
13453
|
const parts = namespace.split(".");
|
|
@@ -12105,13 +13469,13 @@ var useUnderverseTranslations = (namespace) => {
|
|
|
12105
13469
|
return context.t(namespace);
|
|
12106
13470
|
};
|
|
12107
13471
|
var useUnderverseLocale = () => {
|
|
12108
|
-
const context =
|
|
13472
|
+
const context = React50.useContext(TranslationContext2);
|
|
12109
13473
|
return context?.locale || "en";
|
|
12110
13474
|
};
|
|
12111
13475
|
|
|
12112
13476
|
// src/hooks/useSmartTranslations.tsx
|
|
12113
|
-
import * as
|
|
12114
|
-
import { jsx as
|
|
13477
|
+
import * as React51 from "react";
|
|
13478
|
+
import { jsx as jsx64 } from "react/jsx-runtime";
|
|
12115
13479
|
var nextIntlHooks = null;
|
|
12116
13480
|
try {
|
|
12117
13481
|
const nextIntl = __require("next-intl");
|
|
@@ -12122,12 +13486,12 @@ try {
|
|
|
12122
13486
|
} catch {
|
|
12123
13487
|
nextIntlHooks = null;
|
|
12124
13488
|
}
|
|
12125
|
-
var ForceInternalContext =
|
|
13489
|
+
var ForceInternalContext = React51.createContext(false);
|
|
12126
13490
|
var ForceInternalTranslationsProvider = ({ children }) => {
|
|
12127
|
-
return /* @__PURE__ */
|
|
13491
|
+
return /* @__PURE__ */ jsx64(ForceInternalContext.Provider, { value: true, children });
|
|
12128
13492
|
};
|
|
12129
13493
|
function useSmartTranslations(namespace) {
|
|
12130
|
-
const forceInternal =
|
|
13494
|
+
const forceInternal = React51.useContext(ForceInternalContext);
|
|
12131
13495
|
const internalT = useUnderverseTranslations(namespace);
|
|
12132
13496
|
if (forceInternal || !nextIntlHooks?.useTranslations) {
|
|
12133
13497
|
return internalT;
|
|
@@ -12140,7 +13504,7 @@ function useSmartTranslations(namespace) {
|
|
|
12140
13504
|
}
|
|
12141
13505
|
}
|
|
12142
13506
|
function useSmartLocale() {
|
|
12143
|
-
const forceInternal =
|
|
13507
|
+
const forceInternal = React51.useContext(ForceInternalContext);
|
|
12144
13508
|
const internalLocale = useUnderverseLocale();
|
|
12145
13509
|
if (forceInternal || !nextIntlHooks?.useLocale) {
|
|
12146
13510
|
return internalLocale;
|
|
@@ -12161,9 +13525,11 @@ function getUnderverseMessages(locale = "en") {
|
|
|
12161
13525
|
export {
|
|
12162
13526
|
AccessDenied,
|
|
12163
13527
|
Alert_default as Alert,
|
|
13528
|
+
AreaChart,
|
|
12164
13529
|
Avatar_default as Avatar,
|
|
12165
13530
|
Badge_default as Badge,
|
|
12166
13531
|
Badge as BadgeBase,
|
|
13532
|
+
BarChart,
|
|
12167
13533
|
BatteryProgress,
|
|
12168
13534
|
BottomSheet,
|
|
12169
13535
|
Breadcrumb_default as Breadcrumb,
|
|
@@ -12201,6 +13567,7 @@ export {
|
|
|
12201
13567
|
FormLabel,
|
|
12202
13568
|
FormMessage,
|
|
12203
13569
|
FormSubmitButton,
|
|
13570
|
+
GaugeChart,
|
|
12204
13571
|
GlobalLoading,
|
|
12205
13572
|
GradientBadge,
|
|
12206
13573
|
Grid_default as Grid,
|
|
@@ -12212,6 +13579,7 @@ export {
|
|
|
12212
13579
|
Label,
|
|
12213
13580
|
LanguageSwitcherHeadless as LanguageSwitcher,
|
|
12214
13581
|
LanguageSwitcherHeadless,
|
|
13582
|
+
LineChart,
|
|
12215
13583
|
List_default as List,
|
|
12216
13584
|
ListItem,
|
|
12217
13585
|
LoadingBar,
|
|
@@ -12228,10 +13596,12 @@ export {
|
|
|
12228
13596
|
PageLoading,
|
|
12229
13597
|
Pagination,
|
|
12230
13598
|
PasswordInput,
|
|
13599
|
+
PieChart,
|
|
12231
13600
|
PillTabs,
|
|
12232
13601
|
Popover,
|
|
12233
13602
|
Progress,
|
|
12234
13603
|
PulseBadge,
|
|
13604
|
+
RadarChart,
|
|
12235
13605
|
RadioGroup,
|
|
12236
13606
|
RadioGroupItem,
|
|
12237
13607
|
SIZE_STYLES_BTN,
|
|
@@ -12256,6 +13626,7 @@ export {
|
|
|
12256
13626
|
SlideOver,
|
|
12257
13627
|
Slider,
|
|
12258
13628
|
SmartImage,
|
|
13629
|
+
Sparkline,
|
|
12259
13630
|
StatusBadge,
|
|
12260
13631
|
StepProgress,
|
|
12261
13632
|
Switch_default as Switch,
|