Files
components/rating.tsx
1'use client'
2
3import * as React from 'react'
4import { PencilLine, Star, StarIcon } from 'lucide-react'
5
6import { cn } from '@/lib/utils'
7import { Button } from '@/components/ui/button'
8import {
9    Card,
10    CardContent,
11    CardDescription,
12    CardFooter,
13    CardHeader,
14    CardTitle,
15} from '@/components/ui/card'
16import { Rating } from '@/components/ui/rating'
17import { Separator } from '@/components/ui/separator'
18
19export function Rating01() {
20    const totalRatings = 17400
21    const totalReviews = 567
22    const average = 3.9
23    const distribution: Record<string, number> = {
24        '5': 56,
25        '4': 25,
26        '3': 7,
27        '2': 8,
28        '1': 4,
29    }
30
31    const maxBar = Math.max(...Object.values(distribution))
32
33    return (
34        <Card className="max-w-sm rounded-2xl border border-gray-200 bg-white shadow-sm">
35            <CardHeader className="">
36                <div className="hidden h-9 w-9 items-center justify-center rounded-full border border-gray-300 md:flex">
37                    <Star className="h-4 w-4 text-gray-500" />
38                </div>
39                <div className="flex flex-col space-y-2">
40                    <CardTitle>Rate Our Product</CardTitle>
41                    <CardDescription>
42                        Provide us with feedback for the product.
43                    </CardDescription>
44                </div>
45            </CardHeader>
46            <CardContent className="px-4 py-3">
47                <div className="flex items-center gap-4 space-y-2">
48                    <div className="text-4xl font-semibold text-black">
49                        {average}
50                    </div>
51                    <div className="flex flex-col space-y-2">
52                        <Rating value={average} readOnly allowHalf size={18} />
53                        <p className="text-sm text-gray-600">
54                            {average} ยท {totalRatings.toLocaleString()} Ratings{' '}
55                            <a href="#" className="text-blue-600 underline">
56                                {totalReviews} reviews
57                            </a>
58                        </p>
59                    </div>
60                </div>
61                <Separator className="my-3" />
62                <div className="mt-4 space-y-2">
63                    {[5, 4, 3, 2, 1].map((star) => (
64                        <div key={star} className="flex items-center gap-2">
65                            <div className="relative h-2 flex-1 overflow-hidden rounded-full bg-gray-100">
66                                <div
67                                    className={cn(
68                                        'bg-yellow absolute top-0 left-0 h-2 rounded-full transition-all',
69                                    )}
70                                    style={{
71                                        width: `${(distribution[star] / maxBar) * 100}%`,
72                                    }}
73                                />
74                            </div>
75                            <div className="flex w-10 items-center justify-end gap-1 text-sm text-gray-600">
76                                {star}.0
77                                <StarIcon className="fill-yellow text-yellow h-3.5 w-3.5" />
78                            </div>
79                        </div>
80                    ))}
81                </div>
82            </CardContent>
83
84            <CardFooter>
85                <Button
86                    variant="outline"
87                    className="w-full justify-center gap-2 text-gray-800"
88                >
89                    <PencilLine className="h-4 w-4" />
90                    Write a Review
91                </Button>
92            </CardFooter>
93        </Card>
94    )
95}
96
Rating card.
rating-01
Files
components/rating.tsx
1'use client'
2
3import * as React from 'react'
4import Image from 'next/image'
5import { Flag } from 'lucide-react'
6
7import { Card } from '@/components/ui/card'
8import { Rating } from '@/components/ui/rating'
9
10export function Rating02() {
11    const ratingValue = 3.5
12
13    return (
14        <Card className="flex flex-row items-center justify-between gap-10 rounded-xl border border-gray-200 bg-white px-4 py-3 shadow-sm">
15            <div className="flex items-center gap-3">
16                <div className="h-10 w-10 overflow-hidden rounded-full bg-gray-100">
17                    <Image
18                        src="/images/profile1.png"
19                        alt="James Brown"
20                        width={40}
21                        height={40}
22                        className="object-cover"
23                    />
24                </div>
25
26                <div className="flex flex-col">
27                    <div className="flex items-center gap-1 sm:gap-0">
28                        <span className="text-sm font-semibold text-gray-900">
29                            Rafael Costa
30                        </span>
31                        <span className="text-xs text-gray-500">
32                            @rafaelcosta
33                        </span>
34                    </div>
35
36                    <div className="mt-1 flex items-center gap-1">
37                        <Rating
38                            value={ratingValue}
39                            readOnly
40                            allowHalf
41                            size={16}
42                        />
43                        <span className="text-xs text-gray-600">
44                            ({ratingValue})
45                        </span>
46                    </div>
47                </div>
48            </div>
49            <div>
50                <Flag className="hover:text-gray h-4 w-4 cursor-pointer text-black" />
51            </div>
52        </Card>
53    )
54}
55
Rating card.
rating-02
Files
components/rating.tsx
1'use client'
2
3import * as React from 'react'
4import { Info, Star } from 'lucide-react'
5import { toast } from 'sonner'
6
7import { Button } from '@/components/ui/button'
8import {
9    Card,
10    CardContent,
11    CardDescription,
12    CardFooter,
13    CardHeader,
14    CardTitle,
15} from '@/components/ui/card'
16import { Checkbox } from '@/components/ui/checkbox'
17import { Input } from '@/components/ui/input'
18import { Label } from '@/components/ui/label'
19import { Rating } from '@/components/ui/rating'
20import { Textarea } from '@/components/ui/textarea'
21
22export function RatingFeedbackCard() {
23    const [rating, setRating] = React.useState(3)
24    const [review, setReview] = React.useState('')
25    const [anonymous, setAnonymous] = React.useState(false)
26
27    const onSubmit = () => {
28        toast.success(`Review submitted ${rating} star`)
29    }
30
31    return (
32        <Card className="max-w-sm rounded-2xl border border-gray-200 bg-white shadow-sm">
33            <CardHeader className="">
34                <div className="border-gray hidden h-9 w-9 items-center justify-center rounded-full border md:flex">
35                    <Star className="text-gray h-4 w-4" />
36                </div>
37                <div className="flex flex-col space-y-2">
38                    <CardTitle>Rate Our Product</CardTitle>
39                    <CardDescription>
40                        Provide us with feedback for the product.
41                    </CardDescription>
42                </div>
43            </CardHeader>
44            <CardContent className="space-y-2">
45                <div className="space-y-2">
46                    <div className="flex items-center gap-1">
47                        <span className="text-sm font-medium text-black">
48                            Your Rating
49                        </span>
50                        <Info className="text-gray h-3.5 w-3.5" />
51                    </div>
52                    <Rating
53                        value={rating}
54                        onChange={setRating}
55                        allowHalf={false}
56                        size={28}
57                    />
58                </div>
59
60                <div className="space-y-2">
61                    <Label className="mb-1 block text-sm font-medium text-black">
62                        Product Name *
63                    </Label>
64                    <Input
65                        type="text"
66                        placeholder="MacBook Air M1"
67                        className="rounded-lg border-gray-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-100"
68                    />
69                </div>
70
71                <div className="space-y-2">
72                    <Label className="block text-sm font-medium text-black">
73                        Product Review{' '}
74                        <span className="text-gray">(Optional)</span>
75                    </Label>
76                    <Textarea
77                        value={review}
78                        onChange={(e) => setReview(e.target.value)}
79                        placeholder="Jot down your thoughts..."
80                        maxLength={200}
81                        className="focus:border-border rounded-lg border-gray-200 focus:ring-2 focus:ring-blue-100"
82                    />
83                    <div className="text-right text-xs text-gray-400">
84                        {review.length}/200
85                    </div>
86                </div>
87
88                <div className="flex items-center gap-2">
89                    <Checkbox
90                        checked={anonymous}
91                        onCheckedChange={(checked) =>
92                            setAnonymous(checked as boolean)
93                        }
94                        id="anonymous"
95                    />
96                    <Label
97                        htmlFor="anonymous"
98                        className="text-sm text-gray-700"
99                    >
100                        Remain anonymous
101                    </Label>
102                </div>
103            </CardContent>
104            <CardFooter className="gap-2">
105                <Button
106                    variant="outline"
107                    className="border-gray w-1/2 rounded-lg text-gray-700 hover:bg-gray-100"
108                >
109                    Cancel
110                </Button>
111                <Button className="w-1/2 rounded-lg" onClick={onSubmit}>
112                    Submit
113                </Button>
114            </CardFooter>
115        </Card>
116    )
117}
118
Rating card.
rating-03