Files
sofa/components/star-rating.tsx
T
jakeandClaude Opus 4.6 b6aaad243f UX overhaul: motion animations, command palette, warm cinema theme
Add premium "Late Night Screening Room" experience with warm indigo/amber
palette, framer-motion spring animations, Cmd+K command palette with TMDB
search, keyboard shortcuts (G H, G S, ?, W, M, 1-5), sonner toasts with
optimistic updates, skeleton loading states, stats dashboard, search
autocomplete with filter tabs, cinematic backdrop with film grain, season
progress bars, and staggered card reveal animations throughout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:30:35 -05:00

53 lines
1.4 KiB
TypeScript

"use client";
import { IconStar, IconStarFilled } from "@tabler/icons-react";
import { motion } from "motion/react";
import { useState } from "react";
interface StarRatingProps {
value: number;
onChange: (value: number) => void;
}
export function StarRating({ value, onChange }: StarRatingProps) {
const [hover, setHover] = useState(0);
return (
<div
className="flex items-center gap-0.5"
role="radiogroup"
aria-label="Rating"
onMouseLeave={() => setHover(0)}
>
{[1, 2, 3, 4, 5].map((star) => {
const filled = star <= (hover || value);
return (
<motion.button
key={star}
type="button"
onClick={() => onChange(star === value ? 0 : star)}
onMouseEnter={() => setHover(star)}
className="p-0.5"
whileHover={{ scale: 1.15 }}
whileTap={{ scale: 0.9 }}
animate={
filled && star === value ? { scale: [1, 1.25, 1] } : { scale: 1 }
}
transition={{
type: "spring" as const,
stiffness: 400,
damping: 15,
}}
>
{filled ? (
<IconStarFilled size={18} className="text-primary" />
) : (
<IconStar size={18} className="text-muted-foreground/30" />
)}
</motion.button>
);
})}
</div>
);
}