Components
A sophisticated, interactive dashboard for comparing AI models:
Loading preview...
import { useState } from "react";
import { cn } from "@/lib/utils";
import { CheckCircle, AlertCircle, Zap, Activity, BarChart3 } from "lucide-react";
export const Component = () => {
const [activeTab, setActiveTab] = useState("performance");
const [selectedModel, setSelectedModel] = useState("gpt-4");
const models = [
{ id: "gpt-4", name: "GPT-4", color: "#10B981" },
{ id: "claude-3", name: "Claude 3", color: "#8B5CF6" },
{ id: "llama-3", name: "Llama 3", color: "#EC4899" },
{ id: "mistral", name: "Mistral", color: "#3B82F6" }
];
const performanceData = {
"gpt-4": [89, 92, 91, 96],
"claude-3": [82, 88, 94, 97],
"llama-3": [76, 81, 87, 91],
"mistral": [79, 84, 89, 92]
};
const quarters = ["Q1", "Q2", "Q3", "Q4"];
const accuracyData = {
categories: ["Translation", "Coding", "Creative", "Reasoning"],
"gpt-4": [95, 92, 88, 94],
"claude-3": [93, 89, 91, 96],
"llama-3": [88, 84, 82, 87],
"mistral": [90, 85, 79, 88]
};
const modelDetails = {
"gpt-4": {
strengths: ["Complex reasoning", "Code generation", "Multilingual"],
limitations: ["Training cutoff", "Hallucinations", "Context length"],
speed: 92,
accuracy: 94
},
"claude-3": {
strengths: ["Long context", "Creative writing", "Safety guardrails"],
limitations: ["Technical reasoning", "Coding", "Math problems"],
speed: 88,
accuracy: 95
},
"llama-3": {
strengths: ["Open source", "Local deployment", "Customizable"],
limitations: ["Less refined", "Resource intensive", "Smaller knowledge base"],
speed: 86,
accuracy: 88
},
"mistral": {
strengths: ["Efficiency", "Low resource usage", "Specialization options"],
limitations: ["Less general knowledge", "Narrower capabilities", "Less training data"],
speed: 90,
accuracy: 86
}
};
// Custom chart components
const CustomBarChart = ({ data, labels, max = 100, height = 250 }) => {
const barWidth = `${100 / data.length - 2}%`;
return (
<div className="w-full" style={{ height: `${height}px` }}>
<div className="flex h-full">
{data.map((value, index) => (
<div key={index} className="flex flex-col items-center justify-end flex-1 gap-2">
<div className="w-full flex justify-center items-end h-[85%]">
<div
className="rounded-t-md transition-all duration-300 ease-out"
style={{
height: `${(value / max) * 100}%`,
width: barWidth,
backgroundColor: models[index % models.length].color,
opacity: models[index % models.length].id === selectedModel ? 1 : 0.6
}}
></div>
</div>
<span className="text-xs text-center truncate w-full">{labels[index]}</span>
</div>
))}
</div>
</div>
);
};
const CustomLineChart = ({ data, labels, max = 100, height = 250 }) => {
const selectedModelData = data[selectedModel];
const maxValue = Object.values(data).flat().reduce((a, b) => Math.max(a, b), 0);
return (
<div className="w-full relative" style={{ height: `${height}px` }}>
{/* Background grid */}
<div className="absolute inset-0 border-l border-t border-border grid grid-rows-4 grid-cols-4">
{Array(16).fill(0).map((_, i) => (
<div key={i} className="border-r border-b border-border/30"></div>
))}
</div>
{/* Y-axis labels */}
<div className="absolute left-0 inset-y-0 w-10 flex flex-col justify-between text-xs text-muted-foreground">
{[maxValue, Math.floor(maxValue * 0.66), Math.floor(maxValue * 0.33), 0].map((value, i) => (
<div key={i} className="relative -ml-8">
{value}
</div>
))}
</div>
{/* X-axis labels */}
<div className="absolute bottom-0 inset-x-0 h-6 flex justify-between text-xs text-muted-foreground">
{labels.map((label, i) => (
<div key={i} className="relative" style={{ left: `${(i / (labels.length - 1)) * 100}%` }}>
{label}
</div>
))}
</div>
{/* Lines */}
<div className="absolute inset-x-0 top-0 bottom-6 px-10">
{Object.entries(data).map(([modelId, values]) => {
const points = values.map((value, i) =>
`${(i / (values.length - 1)) * 100}% ${100 - (value / maxValue) * 100}%`
).join(', ');
const modelInfo = models.find(m => m.id === modelId);
if (!modelInfo) return null;
return (
<svg
key={modelId}
className="absolute inset-0 w-full h-full overflow-visible"
preserveAspectRatio="none"
>
<polyline
points={points}
fill="none"
stroke={modelInfo.color}
strokeWidth={modelId === selectedModel ? 3 : 1.5}
strokeLinecap="round"
strokeLinejoin="round"
vectorEffect="non-scaling-stroke"
/>
{modelId === selectedModel && values.map((value, i) => (
<circle
key={i}
cx={`${(i / (values.length - 1)) * 100}%`}
cy={`${100 - (value / maxValue) * 100}%`}
r="4"
fill={modelInfo.color}
strokeWidth="2"
stroke="white"
/>
))}
</svg>
);
})}
</div>
</div>
);
};
return (
<div className="w-full max-w-6xl mx-auto bg-card rounded-xl shadow-lg overflow-hidden">
<div className="p-6 border-b border-border">
<h1 className="text-3xl font-bold text-card-foreground">AI Model Comparison Dashboard</h1>
<p className="text-muted-foreground mt-2">Interactive analytics for leading language models</p>
</div>
<div className="flex flex-col md:flex-row">
{/* Sidebar */}
<div className="md:w-64 bg-accent p-4 flex flex-col gap-2">
{models.map(model => (
<button
key={model.id}
className={cn(
"p-3 rounded-lg text-left transition-all flex items-center gap-2",
selectedModel === model.id
? "bg-primary text-primary-foreground"
: "hover:bg-primary/10 text-foreground"
)}
onClick={() => setSelectedModel(model.id)}
>
<div
className="w-3 h-3 rounded-full"
style={{ backgroundColor: model.color }}
/>
<span>{model.name}</span>
</button>
))}
<div className="mt-8 pt-4 border-t border-border">
<h3 className="font-semibold mb-2">View Data</h3>
<div className="flex flex-col gap-1">
{[
{ id: "performance", label: "Performance", icon: <Activity size={16} /> },
{ id: "features", label: "Features", icon: <CheckCircle size={16} /> }
].map(tab => (
<button
key={tab.id}
className={cn(
"p-2 rounded-lg text-left transition-all flex items-center gap-2 text-sm",
activeTab === tab.id
? "bg-accent-foreground/10 text-accent-foreground"
: "hover:bg-accent-foreground/5 text-accent-foreground/80"
)}
onClick={() => setActiveTab(tab.id)}
>
{tab.icon}
<span>{tab.label}</span>
</button>
))}
</div>
</div>
</div>
{/* Main content */}
<div className="flex-1 p-6">
{activeTab === "performance" && (
<div>
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-semibold">Performance Metrics</h2>
<div className="flex gap-2">
<button className="px-3 py-1 text-sm bg-secondary rounded-md">Quarterly</button>
<button className="px-3 py-1 text-sm hover:bg-secondary rounded-md">Monthly</button>
</div>
</div>
<div className="mb-8 mt-6">
<h3 className="text-lg font-medium mb-4">Quarterly Performance Trend</h3>
<CustomLineChart
data={performanceData}
labels={quarters}
max={100}
height={240}
/>
</div>
<div className="mt-12">
<h3 className="text-lg font-medium mb-4">Task Category Performance</h3>
<div className="flex gap-2 mb-4">
{models.map(model => (
<div key={model.id} className="flex items-center gap-1">
<div
className="w-3 h-3 rounded-full"
style={{
backgroundColor: model.color,
opacity: model.id === selectedModel ? 1 : 0.6
}}
/>
<span className="text-xs text-muted-foreground">{model.name}</span>
</div>
))}
</div>
<CustomBarChart
data={[
accuracyData["gpt-4"][0],
accuracyData["claude-3"][0],
accuracyData["llama-3"][0],
accuracyData["mistral"][0],
]}
labels={models.map(m => m.name)}
max={100}
height={200}
/>
<div className="flex justify-between items-center mt-2">
<div className="text-sm font-medium">Category: <span className="text-accent-foreground">Translation</span></div>
<div className="flex gap-1">
{accuracyData.categories.map((cat, i) => (
<button
key={i}
className={cn(
"px-2 py-1 text-xs rounded",
i === 0 ? "bg-primary text-primary-foreground" : "hover:bg-secondary"
)}
>
{cat}
</button>
))}
</div>
</div>
</div>
</div>
)}
{activeTab === "features" && (
<div>
<h2 className="text-xl font-semibold mb-6">Model Features</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-card border border-border rounded-lg p-4">
<h3 className="text-lg font-medium flex items-center gap-2 mb-3">
<CheckCircle size={20} className="text-emerald-500" />
Strengths
</h3>
<ul className="space-y-2">
{modelDetails[selectedModel as keyof typeof modelDetails].strengths.map((strength, i) => (
<li key={i} className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-emerald-500" />
<span>{strength}</span>
</li>
))}
</ul>
</div>
<div className="bg-card border border-border rounded-lg p-4">
<h3 className="text-lg font-medium flex items-center gap-2 mb-3">
<AlertCircle size={20} className="text-amber-500" />
Limitations
</h3>
<ul className="space-y-2">
{modelDetails[selectedModel as keyof typeof modelDetails].limitations.map((limitation, i) => (
<li key={i} className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-amber-500" />
<span>{limitation}</span>
</li>
))}
</ul>
</div>
</div>
<div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-card border border-border rounded-lg p-4">
<h3 className="text-lg font-medium flex items-center gap-2 mb-3">
<Zap size={20} className="text-blue-500" />
Processing Speed
</h3>
<div className="mt-4">
<div className="flex justify-between mb-1">
<span className="text-sm text-muted-foreground">Score</span>
<span className="font-medium">{modelDetails[selectedModel as keyof typeof modelDetails].speed}/100</span>
</div>
<div className="w-full bg-muted rounded-full h-2.5">
<div
className="bg-blue-500 h-2.5 rounded-full"
style={{ width: `${modelDetails[selectedModel as keyof typeof modelDetails].speed}%` }}
></div>
</div>
</div>
</div>
<div className="bg-card border border-border rounded-lg p-4">
<h3 className="text-lg font-medium flex items-center gap-2 mb-3">
<Activity size={20} className="text-purple-500" />
Accuracy Rating
</h3>
<div className="mt-4">
<div className="flex justify-between mb-1">
<span className="text-sm text-muted-foreground">Score</span>
<span className="font-medium">{modelDetails[selectedModel as keyof typeof modelDetails].accuracy}/100</span>
</div>
<div className="w-full bg-muted rounded-full h-2.5">
<div
className="bg-purple-500 h-2.5 rounded-full"
style={{ width: `${modelDetails[selectedModel as keyof typeof modelDetails].accuracy}%` }}
></div>
</div>
</div>
</div>
</div>
<div className="mt-6 p-4 bg-card border border-border rounded-lg">
<h3 className="text-lg font-medium flex items-center gap-2 mb-3">
<BarChart3 size={20} className="text-teal-500" />
Model Comparison
</h3>
<div className="grid grid-cols-2 gap-4 mt-4">
{models.map(model => (
<div
key={model.id}
className={cn(
"p-3 rounded-lg border transition-all",
model.id === selectedModel
? "border-primary bg-primary/5"
: "border-border hover:bg-secondary/20"
)}
onClick={() => setSelectedModel(model.id)}
>
<div className="flex items-center gap-2">
<div
className="w-3 h-3 rounded-full"
style={{ backgroundColor: model.color }}
/>
<span className="font-medium">{model.name}</span>
</div>
<div className="flex justify-between mt-2 text-sm">
<span className="text-muted-foreground">Speed:</span>
<span>{modelDetails[model.id as keyof typeof modelDetails].speed}/100</span>
</div>
<div className="flex justify-between mt-1 text-sm">
<span className="text-muted-foreground">Accuracy:</span>
<span>{modelDetails[model.id as keyof typeof modelDetails].accuracy}/100</span>
</div>
</div>
))}
</div>
</div>
</div>
)}
</div>
</div>
</div>
);
};