mirror of
https://github.com/SrIzan10/mainwebsite.git
synced 2026-06-06 00:56:58 +00:00
* 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
110 lines
2.4 KiB
TypeScript
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 }
|