Skip to content

Commit d9a8138

Browse files
committed
✨ Add rating components
1 parent 95d4b42 commit d9a8138

File tree

10 files changed

+262
-1
lines changed

10 files changed

+262
-1
lines changed

src/components/Card/Card.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const Title = titleTag
3030

3131
<Component {...props} {...rest}>
3232
{title && (
33-
<Title class="card-title">{title}</Title>
33+
<Title class:list="card-title">{title}</Title>
3434
)}
3535
<div class="card-body" class:list={[compact && 'compact']}>
3636
{compact && !secondary ? (

src/components/Card/card.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export type CardProps = {
22
element?: string
33
title?: string
4+
titleTag?: string
45
compact?: boolean
56
className?: string
67
secondary?: boolean

src/components/Rating/Rating.astro

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

src/components/Rating/Rating.svelte

Whitespace-only changes.

src/components/Rating/Rating.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react'
2+
import type { RatingProps } from './rating'
3+
4+
const Rating = ({}: RatingProps) => <div>rating</div>
5+
6+
export default Rating

src/components/Rating/rating.scss

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@import '../../scss/config.scss';
2+
3+
.w-rating {
4+
display: inline-flex;
5+
align-items: center;
6+
color: var(--w-rating-color);
7+
font-size: var(--w-rating-size);
8+
9+
&.outline .empty {
10+
transform: scale(.88);
11+
color: black;
12+
text-shadow: -1px 0 var(--w-rating-color), 0 1px var(--w-rating-color), 1px 0 var(--w-rating-color), 0 -1px var(--w-rating-color);
13+
letter-spacing: 2px;
14+
}
15+
16+
.empty {
17+
color: var(--w-rating-empty-color);
18+
19+
&.ten-star {
20+
margin-left: -3px;
21+
}
22+
}
23+
24+
a {
25+
text-decoration: underline;
26+
}
27+
28+
.text {
29+
font-size: 16px;
30+
color: #BBB;
31+
margin-left: 5px;
32+
33+
&.m {
34+
margin-right: 5px;
35+
}
36+
}
37+
}

src/components/Rating/rating.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export type RatingProps = {
2+
score: number
3+
total?: number
4+
showText?: boolean
5+
text?: string
6+
showEmpty?: boolean
7+
outline?: boolean
8+
reviewCount?: number
9+
reviewText?: string
10+
reviewLink?: string
11+
reviewTarget?: string
12+
color?: string
13+
emptyColor?: string
14+
size?: number
15+
className?: string
16+
}

src/pages/index.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Avatar from '@components/Avatar/Avatar.astro'
88
import Badge from '@components/Badge/Badge.astro'
99
import Button from '@components/Button/Button.astro'
1010
import Icon from '@components/Icon/Icon.astro'
11+
import Rating from '@components/Rating/Rating.astro'
1112
---
1213

1314
<Layout>
@@ -97,6 +98,9 @@ import Icon from '@components/Icon/Icon.astro'
9798
color="#f2c262"
9899
/>
99100
</CardWrapper>
101+
<CardWrapper title="Rating" href="/rating">
102+
<Rating score={4} />
103+
</CardWrapper>
100104
</div>
101105
</Layout>
102106

src/pages/rating.astro

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
import Layout from '@static/Layout.astro'
3+
import ComponentWrapper from '@static/ComponentWrapper.astro'
4+
5+
import AstroRating from '@components/Rating/Rating.astro'
6+
import SvelteRating from '@components/Rating/Rating.svelte'
7+
import ReactRating from '@components/Rating/Rating.tsx'
8+
9+
const sections = [
10+
{
11+
title: 'Astro ratings',
12+
component: AstroRating
13+
},
14+
{
15+
title: 'Svelte ratings',
16+
component: SvelteRating
17+
},
18+
{
19+
title: 'React ratings',
20+
component: ReactRating
21+
}
22+
]
23+
---
24+
25+
<Layout>
26+
<h1>Rating</h1>
27+
<div class="grid md-2 lg-3">
28+
<AstroRating score={5} />
29+
<SvelteRating score={4} color="#ee5253" />
30+
<ReactRating score={3} color="#48dbfb" />
31+
</div>
32+
33+
{sections.map(section => (
34+
<h1>{section.title}</h1>
35+
<div class="grid md-2 lg-3">
36+
<ComponentWrapper title="Default 5-star rating">
37+
<section.component score={5} />
38+
</ComponentWrapper>
39+
40+
<ComponentWrapper title="3-star rating">
41+
<section.component score={3} />
42+
</ComponentWrapper>
43+
44+
<ComponentWrapper title="5-star rating out of 10">
45+
<section.component score={5} total={10} />
46+
</ComponentWrapper>
47+
48+
<ComponentWrapper title="Rating without outline">
49+
<section.component score={3} outline={false} />
50+
</ComponentWrapper>
51+
52+
<ComponentWrapper title="Rating without empty stars">
53+
<section.component score={3} showEmpty={false} />
54+
</ComponentWrapper>
55+
56+
<ComponentWrapper title="Rating with size">
57+
<section.component score={4} size={24} />
58+
</ComponentWrapper>
59+
60+
<ComponentWrapper title="Rating with color">
61+
<section.component
62+
score={3}
63+
outline={false}
64+
color="#f7aa61"
65+
/>
66+
</ComponentWrapper>
67+
68+
<ComponentWrapper title="Rating with empty color">
69+
<section.component
70+
score={3}
71+
outline={false}
72+
color="#f7aa61"
73+
emptyColor='#555'
74+
/>
75+
</ComponentWrapper>
76+
77+
<ComponentWrapper title="Rating with color and outline">
78+
<section.component score={3} color="#f7aa61" />
79+
</ComponentWrapper>
80+
81+
<ComponentWrapper title="Rating with default text">
82+
<section.component score={3} showText={true} />
83+
</ComponentWrapper>
84+
85+
<ComponentWrapper title="Rating with translated text">
86+
<section.component
87+
score={3}
88+
showText={true}
89+
text="{0} from {1}"
90+
/>
91+
</ComponentWrapper>
92+
93+
<ComponentWrapper title="Rating with review text">
94+
<section.component
95+
score={3}
96+
reviewCount={123}
97+
/>
98+
</ComponentWrapper>
99+
100+
<ComponentWrapper title="Rating with translated review text">
101+
<section.component
102+
score={3}
103+
reviewCount={123}
104+
reviewText="{0} ratings"
105+
/>
106+
</ComponentWrapper>
107+
108+
<ComponentWrapper title="Review text with link">
109+
<section.component
110+
score={3}
111+
reviewCount={123}
112+
reviewText="{0} ratings"
113+
reviewLink="/avatar"
114+
/>
115+
</ComponentWrapper>
116+
117+
<ComponentWrapper title="Rating with all text">
118+
<section.component
119+
score={3}
120+
showText={true}
121+
reviewCount={123}
122+
reviewLink="/avatar"
123+
reviewTarget="_blank"
124+
/>
125+
</ComponentWrapper>
126+
</div>
127+
))}
128+
</Layout>

src/scss/setup.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ $config: (
88

99
:root {
1010
--w-avatar-border: #000;
11+
--w-rating-color: #FFF;
12+
--w-rating-empty-color: #BBB;
13+
--w-rating-size: 18px;
1114
}
1215

1316
@function config($key) {

0 commit comments

Comments
 (0)