parent
c5b063b980
commit
987c7bc8ec
3 changed files with 103 additions and 2 deletions
@ -0,0 +1,100 @@ |
||||
import { useState } from 'react'; |
||||
|
||||
type RatingProps = { |
||||
ratings?: number; |
||||
starSize?: number; |
||||
readOnly?: boolean; |
||||
}; |
||||
|
||||
export function Rating(props: RatingProps) { |
||||
const { ratings = 0, starSize, readOnly = false } = props; |
||||
|
||||
const [stars, setStars] = useState(Number(ratings.toFixed(2))); |
||||
const starCount = Math.floor(stars); |
||||
const decimalWidthPercentage = Math.min((stars - starCount) * 100, 100); |
||||
|
||||
return ( |
||||
<div className="mt-4 flex"> |
||||
{[1, 2, 3, 4, 5].map((counter) => { |
||||
const isActive = counter <= starCount; |
||||
const hasDecimal = starCount + 1 === counter; |
||||
|
||||
return ( |
||||
<RatingStar |
||||
key={`start-${counter}`} |
||||
starSize={starSize} |
||||
widthPercentage={ |
||||
isActive ? 100 : hasDecimal ? decimalWidthPercentage : 0 |
||||
} |
||||
onClick={() => { |
||||
setStars(counter); |
||||
}} |
||||
readOnly={readOnly} |
||||
/> |
||||
); |
||||
})} |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
type RatingStarProps = { |
||||
starSize?: number; |
||||
onClick: () => void; |
||||
widthPercentage?: number; |
||||
readOnly: boolean; |
||||
}; |
||||
|
||||
function RatingStar(props: RatingStarProps) { |
||||
const { onClick, widthPercentage = 100, starSize = 20, readOnly } = props; |
||||
|
||||
return ( |
||||
<button |
||||
onClick={onClick} |
||||
className="relative block cursor-pointer text-gray-300 disabled:cursor-default" |
||||
style={{ |
||||
width: `${starSize}px`, |
||||
height: `${starSize}px`, |
||||
}} |
||||
disabled={readOnly} |
||||
> |
||||
<span className="absolute inset-0"> |
||||
<svg |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
viewBox="0 0 24 24" |
||||
stroke="currentColor" |
||||
strokeWidth="2" |
||||
strokeLinecap="round" |
||||
strokeLinejoin="round" |
||||
className="fill-none" |
||||
style={{ |
||||
width: `${starSize}px`, |
||||
height: `${starSize}px`, |
||||
}} |
||||
> |
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" /> |
||||
</svg> |
||||
<span |
||||
className="absolute inset-0 overflow-hidden" |
||||
style={{ |
||||
width: `${widthPercentage}%`, |
||||
}} |
||||
> |
||||
<svg |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
viewBox="0 0 24 24" |
||||
strokeWidth="2" |
||||
strokeLinecap="round" |
||||
strokeLinejoin="round" |
||||
className="fill-yellow-400 stroke-yellow-400" |
||||
style={{ |
||||
width: `${starSize}px`, |
||||
height: `${starSize}px`, |
||||
}} |
||||
> |
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" /> |
||||
</svg> |
||||
</span> |
||||
</span> |
||||
</button> |
||||
); |
||||
} |
Loading…
Reference in new issue