Files
mainwebsite/src/components/ui/rating.tsx
SrIzan10 c9c6215f6a astro v2 website (#11)
* initial commit

* bento

* spotify and about me

* lol

* rose pine

* eff

* fix: small centering issue

* feat: latest posts view

* chore: temp filler

* feat: weather

* feat: discord status

* feat: remove old posts and add myself and some projects

* chore: generalize a bit

* chore: testing post and cloudflare ssr

* fix: prerender some more stuff

* feat: branding

* fix: cloudflare deployments

* feat: add lastfm profile

* feat: star rating

* feat: add discogs

* chore: add nocheck

* docs: barebones readme

* docs: try it out

* feat: writeup

* feat: some component stuff
2026-03-13 23:04:37 +01:00

110 lines
2.4 KiB
TypeScript

// @ts-nocheck
import React from "react"
import { Star } from "lucide-react"
import { cn } from "@/lib/utils"
const ratingVariants = {
default: {
star: "text-primary",
emptyStar: "text-muted-foreground",
},
destructive: {
star: "text-red-500",
emptyStar: "text-red-200",
},
yellow: {
star: "text-yellow-500",
emptyStar: "text-yellow-200",
},
}
interface RatingsProps extends React.HTMLAttributes<HTMLDivElement> {
rating: number
totalStars?: number
size?: number
fill?: boolean
Icon?: React.ReactElement
variant?: keyof typeof ratingVariants
}
const Ratings = ({ ...props }: RatingsProps) => {
const {
rating,
totalStars = 5,
size = 20,
fill = true,
Icon = <Star />,
variant = "default",
} = props
const fullStars = Math.floor(rating)
const partialStar =
rating % 1 > 0 ? (
<PartialStar
fillPercentage={rating % 1}
size={size}
className={cn(ratingVariants[variant].star)}
Icon={Icon}
/>
) : null
return (
<div className={cn("flex items-center gap-2")} {...props}>
{[...Array(fullStars)].map((_, i) =>
React.cloneElement(Icon, {
key: i,
size,
className: cn(
fill ? "fill-current" : "fill-transparent",
ratingVariants[variant].star
),
})
)}
{partialStar}
{[...Array(totalStars - fullStars - (partialStar ? 1 : 0))].map((_, i) =>
React.cloneElement(Icon, {
key: i + fullStars + 1,
size,
className: cn(ratingVariants[variant].emptyStar),
})
)}
</div>
)
}
interface PartialStarProps {
fillPercentage: number
size: number
className?: string
Icon: React.ReactElement
}
const PartialStar = ({ ...props }: PartialStarProps) => {
const { fillPercentage, size, className, Icon } = props
return (
<div style={{ position: "relative", display: "inline-block" }}>
{React.cloneElement(Icon, {
size,
className: cn("fill-transparent", className),
})}
<div
style={{
position: "absolute",
top: 0,
overflow: "hidden",
width: `${fillPercentage * 100}%`,
}}
>
{React.cloneElement(Icon, {
size,
className: cn("fill-current", className),
})}
</div>
</div>
)
}
export { Ratings }