66 lines
1.5 KiB
TypeScript
66 lines
1.5 KiB
TypeScript
'use client';
|
|
|
|
import { Star } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface StarRatingProps {
|
|
rating: number;
|
|
count?: number;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
showCount?: boolean;
|
|
interactive?: boolean;
|
|
onRate?: (rating: number) => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function StarRating({
|
|
rating,
|
|
count = 0,
|
|
size = 'md',
|
|
showCount = false,
|
|
interactive = false,
|
|
onRate,
|
|
className
|
|
}: StarRatingProps) {
|
|
const sizeClasses = {
|
|
sm: 'h-3 w-3',
|
|
md: 'h-4 w-4',
|
|
lg: 'h-5 w-5'
|
|
};
|
|
|
|
const handleRate = (newRating: number) => {
|
|
if (interactive && onRate) {
|
|
onRate(newRating);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={cn("flex items-center gap-1", className)}>
|
|
{[1, 2, 3, 4, 5].map((star) => (
|
|
<button
|
|
key={star}
|
|
type="button"
|
|
disabled={!interactive}
|
|
onClick={() => handleRate(star)}
|
|
className={cn(
|
|
"transition-colors",
|
|
interactive ? "cursor-pointer hover:text-yellow-400" : "cursor-default",
|
|
star <= Math.round(rating) ? "text-yellow-400" : "text-gray-300"
|
|
)}
|
|
>
|
|
<Star
|
|
className={cn(
|
|
sizeClasses[size],
|
|
star <= Math.round(rating) ? "fill-yellow-400" : "fill-transparent"
|
|
)}
|
|
/>
|
|
</button>
|
|
))}
|
|
{showCount && count > 0 && (
|
|
<span className="text-xs text-muted-foreground ml-1">
|
|
({count})
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
} |