chart.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. "use client";
  2. import { type ComponentRenderProps } from "@json-render/react";
  3. import { useData } from "@json-render/react";
  4. import { getByPath } from "@json-render/core";
  5. export function Chart({ element }: ComponentRenderProps) {
  6. const { title, dataPath } = element.props as {
  7. title?: string | null;
  8. dataPath: string;
  9. };
  10. const { data } = useData();
  11. const chartData = getByPath(data, dataPath) as
  12. | Array<{ label: string; value: number }>
  13. | undefined;
  14. if (!chartData || !Array.isArray(chartData)) {
  15. return <div style={{ padding: 20, color: "var(--muted)" }}>No data</div>;
  16. }
  17. const maxValue = Math.max(...chartData.map((d) => d.value));
  18. return (
  19. <div>
  20. {title && (
  21. <h4 style={{ margin: "0 0 16px", fontSize: 14, fontWeight: 600 }}>
  22. {title}
  23. </h4>
  24. )}
  25. <div
  26. style={{ display: "flex", gap: 8, alignItems: "flex-end", height: 120 }}
  27. >
  28. {chartData.map((d, i) => (
  29. <div
  30. key={i}
  31. style={{
  32. flex: 1,
  33. display: "flex",
  34. flexDirection: "column",
  35. alignItems: "center",
  36. gap: 4,
  37. }}
  38. >
  39. <div
  40. style={{
  41. width: "100%",
  42. height: `${(d.value / maxValue) * 100}%`,
  43. background: "var(--foreground)",
  44. borderRadius: "4px 4px 0 0",
  45. minHeight: 4,
  46. }}
  47. />
  48. <span style={{ fontSize: 12, color: "var(--muted)" }}>
  49. {d.label}
  50. </span>
  51. </div>
  52. ))}
  53. </div>
  54. </div>
  55. );
  56. }