Skip to content

Commit cdaf9ed

Browse files
committed
✨ Add Rating components for Svelte & React
1 parent ce803dd commit cdaf9ed

File tree

3 files changed

+145
-6
lines changed

3 files changed

+145
-6
lines changed

src/components/Rating/Rating.svelte

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<script lang="ts">
2+
import type { RatingProps } from './rating'
3+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.svelte'
4+
5+
import './rating.scss'
6+
7+
export let score: RatingProps['score']
8+
export let total: RatingProps['total'] = 5
9+
export let showText: RatingProps['showText'] = false
10+
export let text: RatingProps['text'] = '{0} out of {1}'
11+
export let showEmpty: RatingProps['showEmpty'] = true
12+
export let outline: RatingProps['outline'] = true
13+
export let reviewCount: RatingProps['reviewCount'] = 0
14+
export let reviewText: RatingProps['reviewText'] = '{0} reviews'
15+
export let reviewLink: RatingProps['reviewLink'] = ''
16+
export let reviewTarget: RatingProps['reviewTarget'] = ''
17+
export let color: RatingProps['color'] = ''
18+
export let emptyColor: RatingProps['emptyColor'] = ''
19+
export let size: RatingProps['size'] = 0
20+
export let className: RatingProps['className'] = ''
21+
22+
const classes = [
23+
'w-rating',
24+
outline && 'outline',
25+
className
26+
].filter(Boolean).join(' ')
27+
28+
const styles = [
29+
color && `--w-rating-color: ${color};`,
30+
size && `--w-rating-size: ${size}px;`,
31+
emptyColor && `--w-rating-empty-color: ${emptyColor};`
32+
].filter(Boolean).join(' ')
33+
34+
const translatedText = text!
35+
.replace('{0}', `${score}`)
36+
.replace('{1}', `${total}`)
37+
38+
const translatedReviewText = reviewText?.replace('{0}', `${reviewCount}`)
39+
</script>
40+
41+
42+
<span class={classes} style={styles || null}>
43+
<span class="score">{Array(score).fill('').join('')}</span>
44+
{#if showEmpty}
45+
<span
46+
class="empty"
47+
class:ten-star={total === 10}
48+
>
49+
{Array((total || 5) - score).fill('').join('')}
50+
</span>
51+
{/if}
52+
53+
{#if showText}
54+
<span class="text" class:m={reviewCount}>
55+
{translatedText}
56+
</span>
57+
{/if}
58+
59+
{#if reviewCount}
60+
{''}
61+
<ConditionalWrapper
62+
condition={!!reviewLink}
63+
element="a"
64+
href={reviewLink}
65+
target={reviewTarget}
66+
>
67+
<span class="text">{translatedReviewText}</span>
68+
</ConditionalWrapper>
69+
{/if}
70+
</span>

src/components/Rating/Rating.tsx

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,67 @@
11
import React from 'react'
22
import type { RatingProps } from './rating'
3+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.tsx'
4+
import './rating.scss'
35

4-
const Rating = ({}: RatingProps) => <div>rating</div>
6+
const Rating = ({
7+
score,
8+
total = 5,
9+
showText,
10+
text = '{0} out of {1}',
11+
showEmpty = true,
12+
outline = true,
13+
reviewCount,
14+
reviewText = '{0} reviews',
15+
reviewLink,
16+
reviewTarget,
17+
color,
18+
emptyColor,
19+
size,
20+
className
21+
}: RatingProps) => {
22+
const classes = [
23+
'w-rating',
24+
outline && 'outline',
25+
className
26+
].filter(Boolean).join(' ')
27+
28+
const styles = {
29+
...(color && { '--w-rating-color': color }),
30+
...(size && { '--w-rating-size': `${size}px` }),
31+
...(emptyColor && { '--w-rating-empty-color': emptyColor })
32+
} as React.CSSProperties
33+
34+
const translatedText = text
35+
.replace('{0}', `${score}`)
36+
.replace('{1}', `${total}`)
37+
38+
const translatedReviewText = reviewText.replace('{0}', `${reviewCount}`)
39+
40+
return (
41+
<span className={classes} style={styles}>
42+
<span className="score">{Array(score).fill('★').join('')}</span>
43+
{showEmpty && (
44+
<span className={total === 10 ? 'empty ten-star' : 'empty'}>
45+
{Array(total - score).fill('★').join('')}
46+
</span>
47+
)}
48+
{showText && (
49+
<span className={reviewCount ? 'text m' : 'text'}>
50+
{translatedText}
51+
</span>
52+
)}
53+
{reviewCount && '•'}
54+
{reviewCount && (
55+
<ConditionalWrapper condition={!!reviewLink} wrapper={children => (
56+
<a href={reviewLink} target={reviewTarget}>
57+
{children}
58+
</a>
59+
)}>
60+
<span className="text">{translatedReviewText}</span>
61+
</ConditionalWrapper>
62+
)}
63+
</span>
64+
)
65+
}
566

667
export default Rating

src/pages/rating.astro

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,17 @@ const sections = [
2525
<Layout>
2626
<h1>Rating</h1>
2727
<div class="grid md-2 lg-3">
28-
<AstroRating score={5} />
29-
<SvelteRating score={4} color="#ee5253" />
30-
<ReactRating score={3} color="#48dbfb" />
28+
<ComponentWrapper type="Astro">
29+
<AstroRating score={5} />
30+
</ComponentWrapper>
31+
32+
<ComponentWrapper type="Svelte">
33+
<SvelteRating score={4} color="#ee5253" />
34+
</ComponentWrapper>
35+
36+
<ComponentWrapper type="React">
37+
<ReactRating score={3} color="#48dbfb" />
38+
</ComponentWrapper>
3139
</div>
3240

3341
{sections.map(section => (
@@ -82,7 +90,7 @@ const sections = [
8290
<section.component score={3} showText={true} />
8391
</ComponentWrapper>
8492

85-
<ComponentWrapper title="Rating with translated text">
93+
<ComponentWrapper title="Rating with custom text">
8694
<section.component
8795
score={3}
8896
showText={true}
@@ -97,7 +105,7 @@ const sections = [
97105
/>
98106
</ComponentWrapper>
99107

100-
<ComponentWrapper title="Rating with translated review text">
108+
<ComponentWrapper title="Rating with custom review text">
101109
<section.component
102110
score={3}
103111
reviewCount={123}

0 commit comments

Comments
 (0)