summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/charts/ChartRenderer.tsx
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2025-12-23 14:43:23 +0000
committersoryu <soryu@soryu.co>2025-12-23 14:47:18 +0000
commit555061b179b8ec034cb70f9a2dd6c823ced0f637 (patch)
tree0545b4395dab6d957884d8d36bf15b8da529dc1f /makima/frontend/src/components/charts/ChartRenderer.tsx
parenta32dc56d2e5447ef8988cb98b8686476cc94e70c (diff)
downloadsoryu-555061b179b8ec034cb70f9a2dd6c823ced0f637.tar.gz
soryu-555061b179b8ec034cb70f9a2dd6c823ced0f637.zip
Add file body and initial tool call system
Diffstat (limited to 'makima/frontend/src/components/charts/ChartRenderer.tsx')
-rw-r--r--makima/frontend/src/components/charts/ChartRenderer.tsx181
1 files changed, 181 insertions, 0 deletions
diff --git a/makima/frontend/src/components/charts/ChartRenderer.tsx b/makima/frontend/src/components/charts/ChartRenderer.tsx
new file mode 100644
index 0000000..276b170
--- /dev/null
+++ b/makima/frontend/src/components/charts/ChartRenderer.tsx
@@ -0,0 +1,181 @@
+import { useMemo } from "react";
+import {
+ LineChart,
+ Line,
+ BarChart,
+ Bar,
+ PieChart,
+ Pie,
+ AreaChart,
+ Area,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ Legend,
+ ResponsiveContainer,
+ Cell,
+} from "recharts";
+import type { ChartType } from "../../lib/api";
+
+interface ChartRendererProps {
+ chartType: ChartType;
+ data: Record<string, unknown>[];
+ title?: string;
+ config?: Record<string, unknown>;
+}
+
+// Default color palette
+const COLORS = [
+ "#9bc3ff",
+ "#ff9b9b",
+ "#9bffb3",
+ "#ffeb9b",
+ "#d49bff",
+ "#9bfff0",
+ "#ff9beb",
+ "#b3ff9b",
+];
+
+export function ChartRenderer({
+ chartType,
+ data,
+ title,
+ config,
+}: ChartRendererProps) {
+ // Extract data keys (excluding 'name' which is used for labels)
+ const dataKeys = useMemo(() => {
+ if (data.length === 0) return [];
+ const keys = Object.keys(data[0]).filter((key) => key !== "name");
+ return keys;
+ }, [data]);
+
+ // Get colors from config or use defaults
+ const colors = (config?.colors as string[]) || COLORS;
+
+ const renderChart = () => {
+ switch (chartType) {
+ case "line":
+ return (
+ <LineChart data={data}>
+ <CartesianGrid strokeDasharray="3 3" stroke="#333" />
+ <XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
+ <YAxis stroke="#9bc3ff" fontSize={12} />
+ <Tooltip
+ contentStyle={{
+ backgroundColor: "#111",
+ border: "1px solid #9bc3ff",
+ borderRadius: "0",
+ }}
+ />
+ <Legend />
+ {dataKeys.map((key, i) => (
+ <Line
+ key={key}
+ type="monotone"
+ dataKey={key}
+ stroke={colors[i % colors.length]}
+ strokeWidth={2}
+ dot={{ fill: colors[i % colors.length] }}
+ />
+ ))}
+ </LineChart>
+ );
+
+ case "bar":
+ return (
+ <BarChart data={data}>
+ <CartesianGrid strokeDasharray="3 3" stroke="#333" />
+ <XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
+ <YAxis stroke="#9bc3ff" fontSize={12} />
+ <Tooltip
+ contentStyle={{
+ backgroundColor: "#111",
+ border: "1px solid #9bc3ff",
+ borderRadius: "0",
+ }}
+ />
+ <Legend />
+ {dataKeys.map((key, i) => (
+ <Bar key={key} dataKey={key} fill={colors[i % colors.length]} />
+ ))}
+ </BarChart>
+ );
+
+ case "area":
+ return (
+ <AreaChart data={data}>
+ <CartesianGrid strokeDasharray="3 3" stroke="#333" />
+ <XAxis dataKey="name" stroke="#9bc3ff" fontSize={12} />
+ <YAxis stroke="#9bc3ff" fontSize={12} />
+ <Tooltip
+ contentStyle={{
+ backgroundColor: "#111",
+ border: "1px solid #9bc3ff",
+ borderRadius: "0",
+ }}
+ />
+ <Legend />
+ {dataKeys.map((key, i) => (
+ <Area
+ key={key}
+ type="monotone"
+ dataKey={key}
+ stroke={colors[i % colors.length]}
+ fill={colors[i % colors.length]}
+ fillOpacity={0.3}
+ />
+ ))}
+ </AreaChart>
+ );
+
+ case "pie":
+ // For pie charts, use the first data key as value
+ const valueKey = dataKeys[0] || "value";
+ return (
+ <PieChart>
+ <Pie
+ data={data}
+ dataKey={valueKey}
+ nameKey="name"
+ cx="50%"
+ cy="50%"
+ outerRadius={80}
+ label={({ name, percent }) =>
+ `${name}: ${((percent ?? 0) * 100).toFixed(0)}%`
+ }
+ labelLine={{ stroke: "#9bc3ff" }}
+ >
+ {data.map((_, i) => (
+ <Cell key={i} fill={colors[i % colors.length]} />
+ ))}
+ </Pie>
+ <Tooltip
+ contentStyle={{
+ backgroundColor: "#111",
+ border: "1px solid #9bc3ff",
+ borderRadius: "0",
+ }}
+ />
+ <Legend />
+ </PieChart>
+ );
+
+ default:
+ return <div className="text-red-400">Unknown chart type: {chartType}</div>;
+ }
+ };
+
+ return (
+ <div className="w-full">
+ {title && (
+ <h4 className="text-[#9bc3ff] font-mono text-sm mb-2">{title}</h4>
+ )}
+ <div className="h-64 w-full">
+ <ResponsiveContainer width="100%" height="100%">
+ {renderChart()}
+ </ResponsiveContainer>
+ </div>
+ </div>
+ );
+}