036973ea32
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
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
import { Star } from "lucide-react";
|
|
|
|
interface RatingStarsProps {
|
|
value: number;
|
|
max?: number;
|
|
size?: "sm" | "md" | "lg";
|
|
interactive?: boolean;
|
|
onChange?: (value: number) => void;
|
|
}
|
|
|
|
export function RatingStars({ value, max = 5, size = "md", interactive = false, onChange }: RatingStarsProps) {
|
|
const sizeClasses = {
|
|
sm: "w-3 h-3",
|
|
md: "w-5 h-5",
|
|
lg: "w-7 h-7"
|
|
};
|
|
|
|
return (
|
|
<div className="flex items-center gap-0.5" data-testid="rating-stars">
|
|
{Array.from({ length: max }).map((_, i) => {
|
|
const starValue = i + 1;
|
|
const isFilled = value >= starValue;
|
|
|
|
return (
|
|
<button
|
|
key={i}
|
|
type="button"
|
|
disabled={!interactive}
|
|
onClick={() => interactive && onChange?.(starValue)}
|
|
className={`${interactive ? "cursor-pointer hover:scale-110 transition-transform" : "cursor-default"} bg-transparent border-0 p-0`}
|
|
data-testid={`star-${starValue}`}
|
|
>
|
|
<Star
|
|
className={`${sizeClasses[size]} ${isFilled ? "fill-primary text-primary" : "text-muted-foreground/30"} transition-colors`}
|
|
/>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|