From 9cb7703f6472d713d3f0a0879413a83d7e0a35c5 Mon Sep 17 00:00:00 2001
From: Joey Wong <33094058+slowsynapse@users.noreply.github.com>
Date: Thu, 30 Jan 2025 05:01:01 +0700
Subject: [PATCH] agent catalog front-end
---
agent-catalog/.gitignore | 27 +
agent-catalog/app/agent/[id]/page.tsx | 12 +
agent-catalog/app/globals.css | 94 +++
agent-catalog/app/layout.tsx | 32 +
agent-catalog/app/page.tsx | 21 +
agent-catalog/components.json | 21 +
agent-catalog/components/agent-card.tsx | 114 +++
.../components/agent-description.tsx | 13 +
agent-catalog/components/agent-details.tsx | 53 ++
agent-catalog/components/agent-grid.tsx | 96 +++
agent-catalog/components/agent-tags.tsx | 18 +
agent-catalog/components/agent-tiers.tsx | 122 +++
agent-catalog/components/header.tsx | 46 ++
agent-catalog/components/integrations.tsx | 36 +
agent-catalog/components/price-chart.tsx | 121 +++
.../components/social-media-buttons.tsx | 38 +
agent-catalog/components/theme-provider.tsx | 11 +
agent-catalog/components/token-data.tsx | 21 +
agent-catalog/components/ui/accordion.tsx | 58 ++
agent-catalog/components/ui/alert-dialog.tsx | 141 ++++
agent-catalog/components/ui/alert.tsx | 59 ++
agent-catalog/components/ui/aspect-ratio.tsx | 7 +
agent-catalog/components/ui/avatar.tsx | 50 ++
agent-catalog/components/ui/badge.tsx | 36 +
agent-catalog/components/ui/breadcrumb.tsx | 115 +++
agent-catalog/components/ui/button.tsx | 56 ++
agent-catalog/components/ui/calendar.tsx | 66 ++
agent-catalog/components/ui/card.tsx | 79 ++
agent-catalog/components/ui/carousel.tsx | 262 ++++++
agent-catalog/components/ui/chart.tsx | 365 +++++++++
agent-catalog/components/ui/checkbox.tsx | 30 +
agent-catalog/components/ui/collapsible.tsx | 11 +
agent-catalog/components/ui/command.tsx | 153 ++++
agent-catalog/components/ui/context-menu.tsx | 200 +++++
agent-catalog/components/ui/dialog.tsx | 122 +++
agent-catalog/components/ui/drawer.tsx | 118 +++
agent-catalog/components/ui/dropdown-menu.tsx | 200 +++++
agent-catalog/components/ui/form.tsx | 178 ++++
agent-catalog/components/ui/hover-card.tsx | 29 +
agent-catalog/components/ui/input-otp.tsx | 71 ++
agent-catalog/components/ui/input.tsx | 22 +
agent-catalog/components/ui/label.tsx | 26 +
agent-catalog/components/ui/menubar.tsx | 236 ++++++
.../components/ui/navigation-menu.tsx | 128 +++
agent-catalog/components/ui/pagination.tsx | 117 +++
agent-catalog/components/ui/popover.tsx | 31 +
agent-catalog/components/ui/progress.tsx | 28 +
agent-catalog/components/ui/radio-group.tsx | 44 +
agent-catalog/components/ui/resizable.tsx | 45 ++
agent-catalog/components/ui/scroll-area.tsx | 48 ++
agent-catalog/components/ui/select.tsx | 160 ++++
agent-catalog/components/ui/separator.tsx | 31 +
agent-catalog/components/ui/sheet.tsx | 140 ++++
agent-catalog/components/ui/sidebar.tsx | 763 ++++++++++++++++++
agent-catalog/components/ui/skeleton.tsx | 15 +
agent-catalog/components/ui/slider.tsx | 28 +
agent-catalog/components/ui/sonner.tsx | 31 +
agent-catalog/components/ui/switch.tsx | 29 +
agent-catalog/components/ui/table.tsx | 117 +++
agent-catalog/components/ui/tabs.tsx | 55 ++
agent-catalog/components/ui/textarea.tsx | 22 +
agent-catalog/components/ui/toast.tsx | 129 +++
agent-catalog/components/ui/toaster.tsx | 35 +
agent-catalog/components/ui/toggle-group.tsx | 61 ++
agent-catalog/components/ui/toggle.tsx | 45 ++
agent-catalog/components/ui/tooltip.tsx | 30 +
agent-catalog/components/ui/use-mobile.tsx | 19 +
agent-catalog/components/ui/use-toast.ts | 194 +++++
agent-catalog/components/vrm-demo.tsx | 8 +
agent-catalog/hooks/use-mobile.tsx | 19 +
agent-catalog/hooks/use-toast.ts | 194 +++++
agent-catalog/lib/mock-agents.ts | 77 ++
agent-catalog/lib/utils.ts | 6 +
agent-catalog/next.config.mjs | 48 ++
agent-catalog/package.json | 74 ++
agent-catalog/postcss.config.mjs | 8 +
agent-catalog/public/placeholder-logo.png | Bin 0 -> 958 bytes
agent-catalog/public/placeholder-logo.svg | 1 +
agent-catalog/public/placeholder-user.jpg | Bin 0 -> 2615 bytes
agent-catalog/public/placeholder.jpg | Bin 0 -> 1596 bytes
agent-catalog/public/placeholder.svg | 1 +
agent-catalog/styles/globals.css | 94 +++
agent-catalog/tailwind.config.js | 51 ++
agent-catalog/tailwind.config.ts | 96 +++
agent-catalog/tsconfig.json | 27 +
agent-catalog/types/agent.ts | 17 +
86 files changed, 6652 insertions(+)
create mode 100644 agent-catalog/.gitignore
create mode 100644 agent-catalog/app/agent/[id]/page.tsx
create mode 100644 agent-catalog/app/globals.css
create mode 100644 agent-catalog/app/layout.tsx
create mode 100644 agent-catalog/app/page.tsx
create mode 100644 agent-catalog/components.json
create mode 100644 agent-catalog/components/agent-card.tsx
create mode 100644 agent-catalog/components/agent-description.tsx
create mode 100644 agent-catalog/components/agent-details.tsx
create mode 100644 agent-catalog/components/agent-grid.tsx
create mode 100644 agent-catalog/components/agent-tags.tsx
create mode 100644 agent-catalog/components/agent-tiers.tsx
create mode 100644 agent-catalog/components/header.tsx
create mode 100644 agent-catalog/components/integrations.tsx
create mode 100644 agent-catalog/components/price-chart.tsx
create mode 100644 agent-catalog/components/social-media-buttons.tsx
create mode 100644 agent-catalog/components/theme-provider.tsx
create mode 100644 agent-catalog/components/token-data.tsx
create mode 100644 agent-catalog/components/ui/accordion.tsx
create mode 100644 agent-catalog/components/ui/alert-dialog.tsx
create mode 100644 agent-catalog/components/ui/alert.tsx
create mode 100644 agent-catalog/components/ui/aspect-ratio.tsx
create mode 100644 agent-catalog/components/ui/avatar.tsx
create mode 100644 agent-catalog/components/ui/badge.tsx
create mode 100644 agent-catalog/components/ui/breadcrumb.tsx
create mode 100644 agent-catalog/components/ui/button.tsx
create mode 100644 agent-catalog/components/ui/calendar.tsx
create mode 100644 agent-catalog/components/ui/card.tsx
create mode 100644 agent-catalog/components/ui/carousel.tsx
create mode 100644 agent-catalog/components/ui/chart.tsx
create mode 100644 agent-catalog/components/ui/checkbox.tsx
create mode 100644 agent-catalog/components/ui/collapsible.tsx
create mode 100644 agent-catalog/components/ui/command.tsx
create mode 100644 agent-catalog/components/ui/context-menu.tsx
create mode 100644 agent-catalog/components/ui/dialog.tsx
create mode 100644 agent-catalog/components/ui/drawer.tsx
create mode 100644 agent-catalog/components/ui/dropdown-menu.tsx
create mode 100644 agent-catalog/components/ui/form.tsx
create mode 100644 agent-catalog/components/ui/hover-card.tsx
create mode 100644 agent-catalog/components/ui/input-otp.tsx
create mode 100644 agent-catalog/components/ui/input.tsx
create mode 100644 agent-catalog/components/ui/label.tsx
create mode 100644 agent-catalog/components/ui/menubar.tsx
create mode 100644 agent-catalog/components/ui/navigation-menu.tsx
create mode 100644 agent-catalog/components/ui/pagination.tsx
create mode 100644 agent-catalog/components/ui/popover.tsx
create mode 100644 agent-catalog/components/ui/progress.tsx
create mode 100644 agent-catalog/components/ui/radio-group.tsx
create mode 100644 agent-catalog/components/ui/resizable.tsx
create mode 100644 agent-catalog/components/ui/scroll-area.tsx
create mode 100644 agent-catalog/components/ui/select.tsx
create mode 100644 agent-catalog/components/ui/separator.tsx
create mode 100644 agent-catalog/components/ui/sheet.tsx
create mode 100644 agent-catalog/components/ui/sidebar.tsx
create mode 100644 agent-catalog/components/ui/skeleton.tsx
create mode 100644 agent-catalog/components/ui/slider.tsx
create mode 100644 agent-catalog/components/ui/sonner.tsx
create mode 100644 agent-catalog/components/ui/switch.tsx
create mode 100644 agent-catalog/components/ui/table.tsx
create mode 100644 agent-catalog/components/ui/tabs.tsx
create mode 100644 agent-catalog/components/ui/textarea.tsx
create mode 100644 agent-catalog/components/ui/toast.tsx
create mode 100644 agent-catalog/components/ui/toaster.tsx
create mode 100644 agent-catalog/components/ui/toggle-group.tsx
create mode 100644 agent-catalog/components/ui/toggle.tsx
create mode 100644 agent-catalog/components/ui/tooltip.tsx
create mode 100644 agent-catalog/components/ui/use-mobile.tsx
create mode 100644 agent-catalog/components/ui/use-toast.ts
create mode 100644 agent-catalog/components/vrm-demo.tsx
create mode 100644 agent-catalog/hooks/use-mobile.tsx
create mode 100644 agent-catalog/hooks/use-toast.ts
create mode 100644 agent-catalog/lib/mock-agents.ts
create mode 100644 agent-catalog/lib/utils.ts
create mode 100644 agent-catalog/next.config.mjs
create mode 100644 agent-catalog/package.json
create mode 100644 agent-catalog/postcss.config.mjs
create mode 100644 agent-catalog/public/placeholder-logo.png
create mode 100644 agent-catalog/public/placeholder-logo.svg
create mode 100644 agent-catalog/public/placeholder-user.jpg
create mode 100644 agent-catalog/public/placeholder.jpg
create mode 100644 agent-catalog/public/placeholder.svg
create mode 100644 agent-catalog/styles/globals.css
create mode 100644 agent-catalog/tailwind.config.js
create mode 100644 agent-catalog/tailwind.config.ts
create mode 100644 agent-catalog/tsconfig.json
create mode 100644 agent-catalog/types/agent.ts
diff --git a/agent-catalog/.gitignore b/agent-catalog/.gitignore
new file mode 100644
index 0000000..f650315
--- /dev/null
+++ b/agent-catalog/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files
+.env*
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
\ No newline at end of file
diff --git a/agent-catalog/app/agent/[id]/page.tsx b/agent-catalog/app/agent/[id]/page.tsx
new file mode 100644
index 0000000..2249e25
--- /dev/null
+++ b/agent-catalog/app/agent/[id]/page.tsx
@@ -0,0 +1,12 @@
+import { AgentDetails } from "@/components/agent-details"
+import { mockAgents } from "@/lib/mock-agents"
+
+export default function AgentPage({ params }: { params: { id: string } }) {
+ const agent = mockAgents.find((a) => a.id === params.id) || mockAgents[0]
+ return (
+
+ )
+}
+
diff --git a/agent-catalog/app/globals.css b/agent-catalog/app/globals.css
new file mode 100644
index 0000000..ac68442
--- /dev/null
+++ b/agent-catalog/app/globals.css
@@ -0,0 +1,94 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+body {
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+@layer utilities {
+ .text-balance {
+ text-wrap: balance;
+ }
+}
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 0 0% 3.9%;
+ --card: 0 0% 100%;
+ --card-foreground: 0 0% 3.9%;
+ --popover: 0 0% 100%;
+ --popover-foreground: 0 0% 3.9%;
+ --primary: 0 0% 9%;
+ --primary-foreground: 0 0% 98%;
+ --secondary: 0 0% 96.1%;
+ --secondary-foreground: 0 0% 9%;
+ --muted: 0 0% 96.1%;
+ --muted-foreground: 0 0% 45.1%;
+ --accent: 0 0% 96.1%;
+ --accent-foreground: 0 0% 9%;
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 0 0% 89.8%;
+ --input: 0 0% 89.8%;
+ --ring: 0 0% 3.9%;
+ --chart-1: 12 76% 61%;
+ --chart-2: 173 58% 39%;
+ --chart-3: 197 37% 24%;
+ --chart-4: 43 74% 66%;
+ --chart-5: 27 87% 67%;
+ --radius: 0.5rem;
+ --sidebar-background: 0 0% 98%;
+ --sidebar-foreground: 240 5.3% 26.1%;
+ --sidebar-primary: 240 5.9% 10%;
+ --sidebar-primary-foreground: 0 0% 98%;
+ --sidebar-accent: 240 4.8% 95.9%;
+ --sidebar-accent-foreground: 240 5.9% 10%;
+ --sidebar-border: 220 13% 91%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
+ }
+ .dark {
+ --background: 0 0% 3.9%;
+ --foreground: 0 0% 98%;
+ --card: 0 0% 3.9%;
+ --card-foreground: 0 0% 98%;
+ --popover: 0 0% 3.9%;
+ --popover-foreground: 0 0% 98%;
+ --primary: 0 0% 98%;
+ --primary-foreground: 0 0% 9%;
+ --secondary: 0 0% 14.9%;
+ --secondary-foreground: 0 0% 98%;
+ --muted: 0 0% 14.9%;
+ --muted-foreground: 0 0% 63.9%;
+ --accent: 0 0% 14.9%;
+ --accent-foreground: 0 0% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 0% 98%;
+ --border: 0 0% 14.9%;
+ --input: 0 0% 14.9%;
+ --ring: 0 0% 83.1%;
+ --chart-1: 220 70% 50%;
+ --chart-2: 160 60% 45%;
+ --chart-3: 30 80% 55%;
+ --chart-4: 280 65% 60%;
+ --chart-5: 340 75% 55%;
+ --sidebar-background: 240 5.9% 10%;
+ --sidebar-foreground: 240 4.8% 95.9%;
+ --sidebar-primary: 224.3 76.3% 48%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 240 3.7% 15.9%;
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
+ --sidebar-border: 240 3.7% 15.9%;
+ --sidebar-ring: 217.2 91.2% 59.8%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/agent-catalog/app/layout.tsx b/agent-catalog/app/layout.tsx
new file mode 100644
index 0000000..90e1240
--- /dev/null
+++ b/agent-catalog/app/layout.tsx
@@ -0,0 +1,32 @@
+import { Orbitron, Noto_Sans_JP, Roboto_Mono } from "next/font/google"
+
+const orbitron = Orbitron({
+ subsets: ["latin"],
+ variable: "--font-orbitron",
+})
+
+const noto = Noto_Sans_JP({
+ subsets: ["latin"],
+ variable: "--font-noto-sans-jp",
+})
+
+const robotoMono = Roboto_Mono({
+ subsets: ["latin"],
+ variable: "--font-roboto-mono",
+})
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
+ {children}
+
+ )
+}
+
+
+
+import './globals.css'
\ No newline at end of file
diff --git a/agent-catalog/app/page.tsx b/agent-catalog/app/page.tsx
new file mode 100644
index 0000000..23ecaf0
--- /dev/null
+++ b/agent-catalog/app/page.tsx
@@ -0,0 +1,21 @@
+"use client"
+
+import { AgentGrid } from "@/components/agent-grid"
+import { Header } from "@/components/header"
+import { mockAgents } from "@/lib/mock-agents"
+import { motion, useScroll, useTransform } from "framer-motion"
+
+export default function Home() {
+ const { scrollY } = useScroll()
+ const backgroundColor = useTransform(scrollY, [0, 300], ["rgb(26, 26, 46)", "rgb(255, 255, 255)"])
+
+ return (
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components.json b/agent-catalog/components.json
new file mode 100644
index 0000000..d9ef0ae
--- /dev/null
+++ b/agent-catalog/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "default",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "tailwind.config.ts",
+ "css": "app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
\ No newline at end of file
diff --git a/agent-catalog/components/agent-card.tsx b/agent-catalog/components/agent-card.tsx
new file mode 100644
index 0000000..b553154
--- /dev/null
+++ b/agent-catalog/components/agent-card.tsx
@@ -0,0 +1,114 @@
+"use client"
+
+import type { Agent } from "@/types/agent"
+import { Card, CardContent, CardHeader } from "@/components/ui/card"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { MessageSquare, Info } from "lucide-react"
+import Image from "next/image"
+import { motion } from "framer-motion"
+import Link from "next/link"
+import { useState, useEffect, useRef } from "react"
+
+interface AgentCardProps {
+ agent: Agent
+ index: number
+}
+
+export function AgentCard({ agent, index }: AgentCardProps) {
+ const [isExpanded, setIsExpanded] = useState(false)
+ const descriptionRef = useRef(null)
+ const [needsExpand, setNeedsExpand] = useState(false)
+
+ useEffect(() => {
+ if (descriptionRef.current) {
+ const isOverflowing = descriptionRef.current.scrollHeight > descriptionRef.current.clientHeight
+ setNeedsExpand(isOverflowing)
+ }
+ }, [descriptionRef])
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
{agent.name}
+
+ {agent.price} AIUS
+
+ {agent.status}
+
+
+
+
+
Token: {agent.token}
+
+ Tier: {agent.tier.name} (Level {agent.tier.level})
+
+
+
+
+ {agent.description}
+
+ {needsExpand && !isExpanded && (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/agent-description.tsx b/agent-catalog/components/agent-description.tsx
new file mode 100644
index 0000000..1dd675b
--- /dev/null
+++ b/agent-catalog/components/agent-description.tsx
@@ -0,0 +1,13 @@
+interface AgentDescriptionProps {
+ description: string
+}
+
+export function AgentDescription({ description }: AgentDescriptionProps) {
+ return (
+
+
About
+
{description}
+
+ )
+}
+
diff --git a/agent-catalog/components/agent-details.tsx b/agent-catalog/components/agent-details.tsx
new file mode 100644
index 0000000..8951560
--- /dev/null
+++ b/agent-catalog/components/agent-details.tsx
@@ -0,0 +1,53 @@
+"use client"
+
+import type { Agent } from "@/types/agent"
+import { VRMDemo } from "./vrm-demo"
+import { PriceChart } from "./price-chart"
+import { TokenData } from "./token-data"
+import { AgentDescription } from "./agent-description"
+import { SocialMediaButtons } from "./social-media-buttons"
+import { AgentTags } from "./agent-tags"
+import { AgentTiers } from "./agent-tiers"
+import { Button } from "./ui/button"
+import { MessageSquare, ArrowRightLeft } from "lucide-react"
+import { Integrations } from "./integrations"
+
+interface AgentDetailsProps {
+ agent: Agent
+}
+
+export function AgentDetails({ agent }: AgentDetailsProps) {
+ return (
+
+
+
{agent.name}
+
+ {agent.token} | {agent.tier.name} (Level {agent.tier.level})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/agent-grid.tsx b/agent-catalog/components/agent-grid.tsx
new file mode 100644
index 0000000..98b2fec
--- /dev/null
+++ b/agent-catalog/components/agent-grid.tsx
@@ -0,0 +1,96 @@
+"use client"
+
+import type { Agent } from "@/types/agent"
+import { AgentCard } from "./agent-card"
+import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
+import { Brain, Code, Microscope, Users, Shield, TrendingUp, Bitcoin, Briefcase } from "lucide-react"
+import { motion } from "framer-motion"
+
+interface AgentGridProps {
+ agents: Agent[]
+}
+
+const categories = [
+ { name: "All Agents", icon: Brain },
+ { name: "Programmer", icon: Code },
+ { name: "Researcher", icon: Microscope },
+ { name: "Friend", icon: Users },
+ { name: "Security", icon: Shield },
+ { name: "Degen Trader", icon: TrendingUp },
+ { name: "Crypto", icon: Bitcoin },
+ { name: "Personal Assistant", icon: Briefcase },
+]
+
+export function AgentGrid({ agents }: AgentGridProps) {
+ return (
+
+
+ {/* Search and Filters */}
+
+
+
+
+
+
+
+
+
+
+ {/* Categories */}
+
+ {categories.map((category, index) => {
+ const Icon = category.icon
+ return (
+
+
+
+ )
+ })}
+
+
+ {/* Featured Agents Section */}
+
+
Featured Agents
+
+ {agents.map((agent, index) => (
+
+ ))}
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/agent-tags.tsx b/agent-catalog/components/agent-tags.tsx
new file mode 100644
index 0000000..1fd5eca
--- /dev/null
+++ b/agent-catalog/components/agent-tags.tsx
@@ -0,0 +1,18 @@
+import { Badge } from "./ui/badge"
+
+interface AgentTagsProps {
+ tags: string[]
+}
+
+export function AgentTags({ tags }: AgentTagsProps) {
+ return (
+
+ {tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+ )
+}
+
diff --git a/agent-catalog/components/agent-tiers.tsx b/agent-catalog/components/agent-tiers.tsx
new file mode 100644
index 0000000..2bffd9e
--- /dev/null
+++ b/agent-catalog/components/agent-tiers.tsx
@@ -0,0 +1,122 @@
+import { Progress } from "./ui/progress"
+
+const tiers = [
+ { name: "Newborn", requiredAIUS: 100 },
+ { name: "Baby", requiredAIUS: 500 },
+ { name: "Child", requiredAIUS: 1000 },
+ { name: "Teen", requiredAIUS: 5000 },
+ { name: "Adult", requiredAIUS: 10000 },
+]
+
+interface AgentTiersProps {
+ currentTier: {
+ name: "Newborn" | "Baby" | "Child" | "Teen" | "Adult"
+ level: number
+ stakedAIUS: number
+ }
+}
+
+export function AgentTiers({ currentTier }: AgentTiersProps) {
+ const currentTierIndex = tiers.findIndex((tier) => tier.name === currentTier.name)
+ const nextTier = tiers[currentTierIndex + 1]
+ const progress = nextTier
+ ? ((currentTier.stakedAIUS - tiers[currentTierIndex].requiredAIUS) /
+ (nextTier.requiredAIUS - tiers[currentTierIndex].requiredAIUS)) *
+ 100
+ : 100
+
+ return (
+
+
Agent Level
+
+
+
+
+
+ {currentTier.name}
+ Level {currentTier.level}
+
+
+
+ {currentTier.stakedAIUS} AIUS
+ {nextTier && {nextTier.requiredAIUS} AIUS}
+
+
+
+
+
+ )
+}
+
+function TierIcon({ name, className }: { name: string; className?: string }) {
+ switch (name) {
+ case "Newborn":
+ return (
+
+ )
+ case "Baby":
+ return (
+
+ )
+ case "Child":
+ return (
+
+ )
+ case "Teen":
+ return (
+
+ )
+ case "Adult":
+ return (
+
+ )
+ default:
+ return null
+ }
+}
+
diff --git a/agent-catalog/components/header.tsx b/agent-catalog/components/header.tsx
new file mode 100644
index 0000000..7837037
--- /dev/null
+++ b/agent-catalog/components/header.tsx
@@ -0,0 +1,46 @@
+"use client"
+
+import { motion, useScroll, useTransform } from "framer-motion"
+import { useRef } from "react"
+
+export function Header() {
+ const ref = useRef(null)
+ const { scrollY } = useScroll()
+
+ const textY = useTransform(scrollY, [0, 300], [0, 100])
+ const opacity = useTransform(scrollY, [0, 300], [1, 0])
+ const scale = useTransform(scrollY, [0, 300], [1, 0.9])
+
+ return (
+
+
+
+
+
+
+ Amica Agent Catalog
+
+ アミカエージェント
+
+
+
+
+ Discover and deploy advanced AI agents for your specific needs
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/integrations.tsx b/agent-catalog/components/integrations.tsx
new file mode 100644
index 0000000..92d8617
--- /dev/null
+++ b/agent-catalog/components/integrations.tsx
@@ -0,0 +1,36 @@
+import { Check, X } from "lucide-react"
+
+const integrations = [
+ { name: "Amica Brain", active: true },
+ { name: "Virtuals", active: false },
+ { name: "EACC Marketplace", active: true },
+ { name: "UOS", active: false },
+]
+
+export function Integrations() {
+ return (
+
+
Integrations
+
+ {integrations.map((integration) => (
+
+
+ {integration.name}
+ {integration.active ? (
+
+ ) : (
+
+ )}
+
+
+ ))}
+
+
+ )
+}
+
diff --git a/agent-catalog/components/price-chart.tsx b/agent-catalog/components/price-chart.tsx
new file mode 100644
index 0000000..a39dc94
--- /dev/null
+++ b/agent-catalog/components/price-chart.tsx
@@ -0,0 +1,121 @@
+"use client"
+
+import { useState } from "react"
+import { Line } from "react-chartjs-2"
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+ TimeScale,
+} from "chart.js"
+import "chartjs-adapter-date-fns"
+import { Button } from "./ui/button"
+
+ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, TimeScale)
+
+const options = {
+ responsive: true,
+ interaction: {
+ mode: "index" as const,
+ intersect: false,
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ title: {
+ display: false,
+ },
+ },
+ scales: {
+ x: {
+ type: "time" as const,
+ time: {
+ unit: "day" as const,
+ },
+ grid: {
+ display: false,
+ },
+ },
+ y: {
+ position: "right" as const,
+ grid: {
+ color: "rgba(107, 114, 128, 0.1)",
+ },
+ ticks: {
+ callback: (value: any) => `$${value.toLocaleString()}`,
+ },
+ },
+ },
+}
+
+function generateMockData(days: number) {
+ const data = []
+ const startDate = new Date()
+ startDate.setDate(startDate.getDate() - days)
+
+ for (let i = 0; i < days; i++) {
+ const date = new Date(startDate)
+ date.setDate(date.getDate() + i)
+ data.push({
+ x: date.toISOString(),
+ y: Math.random() * 1000 + 5000, // Random price between $5000 and $6000
+ })
+ }
+
+ return data
+}
+
+const timeFrames = [
+ { label: "1D", days: 1 },
+ { label: "1W", days: 7 },
+ { label: "1M", days: 30 },
+ { label: "3M", days: 90 },
+ { label: "1Y", days: 365 },
+]
+
+export function PriceChart() {
+ const [selectedTimeFrame, setSelectedTimeFrame] = useState(timeFrames[2]) // Default to 1M
+
+ const data = {
+ datasets: [
+ {
+ label: "Price",
+ data: generateMockData(selectedTimeFrame.days),
+ borderColor: "rgb(59, 130, 246)",
+ backgroundColor: "rgba(59, 130, 246, 0.5)",
+ borderWidth: 2,
+ pointRadius: 0,
+ tension: 0.1,
+ },
+ ],
+ }
+
+ return (
+
+
+
$5,234.56
+
+ {timeFrames.map((tf) => (
+
+ ))}
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/social-media-buttons.tsx b/agent-catalog/components/social-media-buttons.tsx
new file mode 100644
index 0000000..6ee5b67
--- /dev/null
+++ b/agent-catalog/components/social-media-buttons.tsx
@@ -0,0 +1,38 @@
+import { Button } from "./ui/button"
+import { Twitter, Facebook, Linkedin, Github } from "lucide-react"
+
+export function SocialMediaButtons() {
+ return (
+
+
+
+
+
+
+ )
+}
+
diff --git a/agent-catalog/components/theme-provider.tsx b/agent-catalog/components/theme-provider.tsx
new file mode 100644
index 0000000..55c2f6e
--- /dev/null
+++ b/agent-catalog/components/theme-provider.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import * as React from 'react'
+import {
+ ThemeProvider as NextThemesProvider,
+ type ThemeProviderProps,
+} from 'next-themes'
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children}
+}
diff --git a/agent-catalog/components/token-data.tsx b/agent-catalog/components/token-data.tsx
new file mode 100644
index 0000000..e662336
--- /dev/null
+++ b/agent-catalog/components/token-data.tsx
@@ -0,0 +1,21 @@
+export function TokenData() {
+ const data = [
+ { label: "Market Cap", value: "$1.2B" },
+ { label: "24h Change", value: "+5.67%" },
+ { label: "TVL", value: "$500M" },
+ { label: "Holders", value: "10,000" },
+ { label: "24h Volume", value: "$50M" },
+ ]
+
+ return (
+
+ {data.map((item) => (
+
+
{item.label}
+
{item.value}
+
+ ))}
+
+ )
+}
+
diff --git a/agent-catalog/components/ui/accordion.tsx b/agent-catalog/components/ui/accordion.tsx
new file mode 100644
index 0000000..24c788c
--- /dev/null
+++ b/agent-catalog/components/ui/accordion.tsx
@@ -0,0 +1,58 @@
+"use client"
+
+import * as React from "react"
+import * as AccordionPrimitive from "@radix-ui/react-accordion"
+import { ChevronDown } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Accordion = AccordionPrimitive.Root
+
+const AccordionItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AccordionItem.displayName = "AccordionItem"
+
+const AccordionTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ svg]:rotate-180",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+))
+AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
+
+const AccordionContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ {children}
+
+))
+
+AccordionContent.displayName = AccordionPrimitive.Content.displayName
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/agent-catalog/components/ui/alert-dialog.tsx b/agent-catalog/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..25e7b47
--- /dev/null
+++ b/agent-catalog/components/ui/alert-dialog.tsx
@@ -0,0 +1,141 @@
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/agent-catalog/components/ui/alert.tsx b/agent-catalog/components/ui/alert.tsx
new file mode 100644
index 0000000..41fa7e0
--- /dev/null
+++ b/agent-catalog/components/ui/alert.tsx
@@ -0,0 +1,59 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const alertVariants = cva(
+ "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
+ {
+ variants: {
+ variant: {
+ default: "bg-background text-foreground",
+ destructive:
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Alert = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & VariantProps
+>(({ className, variant, ...props }, ref) => (
+
+))
+Alert.displayName = "Alert"
+
+const AlertTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+AlertTitle.displayName = "AlertTitle"
+
+const AlertDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+AlertDescription.displayName = "AlertDescription"
+
+export { Alert, AlertTitle, AlertDescription }
diff --git a/agent-catalog/components/ui/aspect-ratio.tsx b/agent-catalog/components/ui/aspect-ratio.tsx
new file mode 100644
index 0000000..d6a5226
--- /dev/null
+++ b/agent-catalog/components/ui/aspect-ratio.tsx
@@ -0,0 +1,7 @@
+"use client"
+
+import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
+
+const AspectRatio = AspectRatioPrimitive.Root
+
+export { AspectRatio }
diff --git a/agent-catalog/components/ui/avatar.tsx b/agent-catalog/components/ui/avatar.tsx
new file mode 100644
index 0000000..51e507b
--- /dev/null
+++ b/agent-catalog/components/ui/avatar.tsx
@@ -0,0 +1,50 @@
+"use client"
+
+import * as React from "react"
+import * as AvatarPrimitive from "@radix-ui/react-avatar"
+
+import { cn } from "@/lib/utils"
+
+const Avatar = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+Avatar.displayName = AvatarPrimitive.Root.displayName
+
+const AvatarImage = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AvatarImage.displayName = AvatarPrimitive.Image.displayName
+
+const AvatarFallback = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+
+export { Avatar, AvatarImage, AvatarFallback }
diff --git a/agent-catalog/components/ui/badge.tsx b/agent-catalog/components/ui/badge.tsx
new file mode 100644
index 0000000..f000e3e
--- /dev/null
+++ b/agent-catalog/components/ui/badge.tsx
@@ -0,0 +1,36 @@
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive:
+ "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
+ outline: "text-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/agent-catalog/components/ui/breadcrumb.tsx b/agent-catalog/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..60e6c96
--- /dev/null
+++ b/agent-catalog/components/ui/breadcrumb.tsx
@@ -0,0 +1,115 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { ChevronRight, MoreHorizontal } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Breadcrumb = React.forwardRef<
+ HTMLElement,
+ React.ComponentPropsWithoutRef<"nav"> & {
+ separator?: React.ReactNode
+ }
+>(({ ...props }, ref) => )
+Breadcrumb.displayName = "Breadcrumb"
+
+const BreadcrumbList = React.forwardRef<
+ HTMLOListElement,
+ React.ComponentPropsWithoutRef<"ol">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbList.displayName = "BreadcrumbList"
+
+const BreadcrumbItem = React.forwardRef<
+ HTMLLIElement,
+ React.ComponentPropsWithoutRef<"li">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbItem.displayName = "BreadcrumbItem"
+
+const BreadcrumbLink = React.forwardRef<
+ HTMLAnchorElement,
+ React.ComponentPropsWithoutRef<"a"> & {
+ asChild?: boolean
+ }
+>(({ asChild, className, ...props }, ref) => {
+ const Comp = asChild ? Slot : "a"
+
+ return (
+
+ )
+})
+BreadcrumbLink.displayName = "BreadcrumbLink"
+
+const BreadcrumbPage = React.forwardRef<
+ HTMLSpanElement,
+ React.ComponentPropsWithoutRef<"span">
+>(({ className, ...props }, ref) => (
+
+))
+BreadcrumbPage.displayName = "BreadcrumbPage"
+
+const BreadcrumbSeparator = ({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<"li">) => (
+ svg]:w-3.5 [&>svg]:h-3.5", className)}
+ {...props}
+ >
+ {children ?? }
+
+)
+BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
+
+const BreadcrumbEllipsis = ({
+ className,
+ ...props
+}: React.ComponentProps<"span">) => (
+
+
+ More
+
+)
+BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/agent-catalog/components/ui/button.tsx b/agent-catalog/components/ui/button.tsx
new file mode 100644
index 0000000..36496a2
--- /dev/null
+++ b/agent-catalog/components/ui/button.tsx
@@ -0,0 +1,56 @@
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ {
+ variants: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button"
+ return (
+
+ )
+ }
+)
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
diff --git a/agent-catalog/components/ui/calendar.tsx b/agent-catalog/components/ui/calendar.tsx
new file mode 100644
index 0000000..61d2b45
--- /dev/null
+++ b/agent-catalog/components/ui/calendar.tsx
@@ -0,0 +1,66 @@
+"use client"
+
+import * as React from "react"
+import { ChevronLeft, ChevronRight } from "lucide-react"
+import { DayPicker } from "react-day-picker"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+export type CalendarProps = React.ComponentProps
+
+function Calendar({
+ className,
+ classNames,
+ showOutsideDays = true,
+ ...props
+}: CalendarProps) {
+ return (
+ ,
+ IconRight: ({ ...props }) => ,
+ }}
+ {...props}
+ />
+ )
+}
+Calendar.displayName = "Calendar"
+
+export { Calendar }
diff --git a/agent-catalog/components/ui/card.tsx b/agent-catalog/components/ui/card.tsx
new file mode 100644
index 0000000..f62edea
--- /dev/null
+++ b/agent-catalog/components/ui/card.tsx
@@ -0,0 +1,79 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardTitle.displayName = "CardTitle"
+
+const CardDescription = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardDescription.displayName = "CardDescription"
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardContent.displayName = "CardContent"
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/agent-catalog/components/ui/carousel.tsx b/agent-catalog/components/ui/carousel.tsx
new file mode 100644
index 0000000..ec505d0
--- /dev/null
+++ b/agent-catalog/components/ui/carousel.tsx
@@ -0,0 +1,262 @@
+"use client"
+
+import * as React from "react"
+import useEmblaCarousel, {
+ type UseEmblaCarouselType,
+} from "embla-carousel-react"
+import { ArrowLeft, ArrowRight } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+
+type CarouselApi = UseEmblaCarouselType[1]
+type UseCarouselParameters = Parameters
+type CarouselOptions = UseCarouselParameters[0]
+type CarouselPlugin = UseCarouselParameters[1]
+
+type CarouselProps = {
+ opts?: CarouselOptions
+ plugins?: CarouselPlugin
+ orientation?: "horizontal" | "vertical"
+ setApi?: (api: CarouselApi) => void
+}
+
+type CarouselContextProps = {
+ carouselRef: ReturnType[0]
+ api: ReturnType[1]
+ scrollPrev: () => void
+ scrollNext: () => void
+ canScrollPrev: boolean
+ canScrollNext: boolean
+} & CarouselProps
+
+const CarouselContext = React.createContext(null)
+
+function useCarousel() {
+ const context = React.useContext(CarouselContext)
+
+ if (!context) {
+ throw new Error("useCarousel must be used within a ")
+ }
+
+ return context
+}
+
+const Carousel = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & CarouselProps
+>(
+ (
+ {
+ orientation = "horizontal",
+ opts,
+ setApi,
+ plugins,
+ className,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const [carouselRef, api] = useEmblaCarousel(
+ {
+ ...opts,
+ axis: orientation === "horizontal" ? "x" : "y",
+ },
+ plugins
+ )
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
+
+ const onSelect = React.useCallback((api: CarouselApi) => {
+ if (!api) {
+ return
+ }
+
+ setCanScrollPrev(api.canScrollPrev())
+ setCanScrollNext(api.canScrollNext())
+ }, [])
+
+ const scrollPrev = React.useCallback(() => {
+ api?.scrollPrev()
+ }, [api])
+
+ const scrollNext = React.useCallback(() => {
+ api?.scrollNext()
+ }, [api])
+
+ const handleKeyDown = React.useCallback(
+ (event: React.KeyboardEvent) => {
+ if (event.key === "ArrowLeft") {
+ event.preventDefault()
+ scrollPrev()
+ } else if (event.key === "ArrowRight") {
+ event.preventDefault()
+ scrollNext()
+ }
+ },
+ [scrollPrev, scrollNext]
+ )
+
+ React.useEffect(() => {
+ if (!api || !setApi) {
+ return
+ }
+
+ setApi(api)
+ }, [api, setApi])
+
+ React.useEffect(() => {
+ if (!api) {
+ return
+ }
+
+ onSelect(api)
+ api.on("reInit", onSelect)
+ api.on("select", onSelect)
+
+ return () => {
+ api?.off("select", onSelect)
+ }
+ }, [api, onSelect])
+
+ return (
+
+
+ {children}
+
+
+ )
+ }
+)
+Carousel.displayName = "Carousel"
+
+const CarouselContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { carouselRef, orientation } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselContent.displayName = "CarouselContent"
+
+const CarouselItem = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => {
+ const { orientation } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselItem.displayName = "CarouselItem"
+
+const CarouselPrevious = React.forwardRef<
+ HTMLButtonElement,
+ React.ComponentProps
+>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselPrevious.displayName = "CarouselPrevious"
+
+const CarouselNext = React.forwardRef<
+ HTMLButtonElement,
+ React.ComponentProps
+>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
+ const { orientation, scrollNext, canScrollNext } = useCarousel()
+
+ return (
+
+ )
+})
+CarouselNext.displayName = "CarouselNext"
+
+export {
+ type CarouselApi,
+ Carousel,
+ CarouselContent,
+ CarouselItem,
+ CarouselPrevious,
+ CarouselNext,
+}
diff --git a/agent-catalog/components/ui/chart.tsx b/agent-catalog/components/ui/chart.tsx
new file mode 100644
index 0000000..8620baa
--- /dev/null
+++ b/agent-catalog/components/ui/chart.tsx
@@ -0,0 +1,365 @@
+"use client"
+
+import * as React from "react"
+import * as RechartsPrimitive from "recharts"
+
+import { cn } from "@/lib/utils"
+
+// Format: { THEME_NAME: CSS_SELECTOR }
+const THEMES = { light: "", dark: ".dark" } as const
+
+export type ChartConfig = {
+ [k in string]: {
+ label?: React.ReactNode
+ icon?: React.ComponentType
+ } & (
+ | { color?: string; theme?: never }
+ | { color?: never; theme: Record }
+ )
+}
+
+type ChartContextProps = {
+ config: ChartConfig
+}
+
+const ChartContext = React.createContext(null)
+
+function useChart() {
+ const context = React.useContext(ChartContext)
+
+ if (!context) {
+ throw new Error("useChart must be used within a ")
+ }
+
+ return context
+}
+
+const ChartContainer = React.forwardRef<
+ HTMLDivElement,
+ React.ComponentProps<"div"> & {
+ config: ChartConfig
+ children: React.ComponentProps<
+ typeof RechartsPrimitive.ResponsiveContainer
+ >["children"]
+ }
+>(({ id, className, children, config, ...props }, ref) => {
+ const uniqueId = React.useId()
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
+
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+})
+ChartContainer.displayName = "Chart"
+
+const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
+ const colorConfig = Object.entries(config).filter(
+ ([_, config]) => config.theme || config.color
+ )
+
+ if (!colorConfig.length) {
+ return null
+ }
+
+ return (
+