mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 01:35:39 -04:00
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>
53 lines
1.4 KiB
TypeScript
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>
|
|
);
|
|
}
|