Add API endpoints and frontend components for tool management and analytics
Implement CRUD operations for tools and ratings, introduce analytics endpoints, and develop frontend components for displaying tools, ratings, and analytics data. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: feaa4ce1-5aed-4cc0-bcea-47855b615b48 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/rx9K7bW Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { ToolWithStats } from "@workspace/api-client-react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Star, MessageSquare } from "lucide-react";
|
||||
import { Link } from "wouter";
|
||||
|
||||
export function ToolCard({ tool }: { tool: ToolWithStats }) {
|
||||
return (
|
||||
<Card className="hover-elevate transition-all flex flex-col h-full cursor-pointer hover:border-primary/50">
|
||||
<Link href={`/tools/${tool.id}`} className="flex flex-col h-full p-0 m-0">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<CardTitle className="text-lg line-clamp-1">{tool.name}</CardTitle>
|
||||
<Badge variant="outline" className="shrink-0">{tool.category}</Badge>
|
||||
</div>
|
||||
<CardDescription className="line-clamp-2 min-h-[2.5rem]">
|
||||
{tool.description}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 pb-4">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{tool.tags?.slice(0, 3).map((tag) => (
|
||||
<Badge key={tag} variant="secondary" className="text-xs px-1.5 py-0">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
{(tool.tags?.length || 0) > 3 && (
|
||||
<Badge variant="secondary" className="text-xs px-1.5 py-0 text-muted-foreground">
|
||||
+{(tool.tags?.length || 0) - 3}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="pt-0 flex justify-between items-center text-sm text-muted-foreground border-t p-4 mt-auto">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-1">
|
||||
<Star className="w-4 h-4 fill-primary text-primary" />
|
||||
<span className="font-medium text-foreground">
|
||||
{tool.avgCombined ? tool.avgCombined.toFixed(1) : "N/A"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<MessageSquare className="w-4 h-4" />
|
||||
<span>{tool.ratingCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Link>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user