Files
apps.apple.com/shared/components/src/components/Rating/Rating.svelte
2025-11-04 05:03:50 +08:00

142 lines
4.0 KiB
Svelte

<script lang="ts">
import type { RatingCountsList } from './types';
import { calculatePercentages } from './utils';
import FilledStarIcon from '@amp/web-app-components/assets/icons/star-filled.svg';
/**
* @name Rating
*
* @description
* This implements the standard rating lockup showing aggregate ratings
*
* Design:
* https://pd-hi.apple.com/viewvc/Common/Modules/macOS/Podcasts/Lockups/Review%20Lockup.png?revision=57299
*
* Aria Discussions:
* https://quip-apple.com/yvZaAbJMnAK0#JeB9CAOHPMd
*
* POTW difference:
* No write a review on the web
*/
export let averageRating: number | string;
export let ratingCount: number;
export let ratingCountText: string;
export let ratingCountsList: RatingCountsList;
export let totalText: string;
$: ratingPercentList = calculatePercentages(ratingCountsList, ratingCount);
</script>
<div class="amp-rating" data-testid="rating-component">
<div class="stats" aria-label={`${averageRating} ${totalText}`}>
<div class="stats__main" data-testid="amp-rating__average-rating">
{averageRating}
</div>
<div class="stats__total" data-testid="amp-rating__total-text">
{totalText}
</div>
</div>
<div class="numbers">
<div class="numbers__star-graph">
{#each ratingPercentList as value, i}
<div
class={`numbers__star-graph__row row-${i}`}
aria-label={`${5 - i} star, ${value}%`}
>
<!-- TODO: rdar://79873131 (Localize Aria Label in Rating Shared Component) -->
<div class="numbers__star-graph__row__stars">
<!-- In order to display the 5 stars to 1 stars we use the 5 - index as 0 index means 1 star and so on -->
{#each { length: 5 - i } as _}
<div class="star"><FilledStarIcon /></div>
{/each}
</div>
<div class="numbers__star-graph__row__bar">
<div
class="numbers__star-graph__row__bar__foreground"
style={`width: ${value}%`}
data-testid={`star-row-${5 - i}`}
/>
</div>
</div>
{/each}
</div>
<div class="numbers__count" data-testid="amp-rating__rating-count-text">
{ratingCountText}
</div>
</div>
</div>
<style lang="scss">
.amp-rating {
display: flex;
}
.stats {
margin-right: 10px;
flex: 0 80px;
}
.stats__main {
font-size: 50px;
font-weight: bold;
display: flex;
justify-content: center;
}
.stats__total {
display: flex;
justify-content: center;
color: var(--systemSecondary-text);
font: var(--body-emphasized);
}
.numbers {
width: 100%;
}
.numbers__count {
display: flex;
align-items: flex-end;
justify-content: flex-end;
color: var(--systemSecondary-text);
}
.numbers__star-graph {
margin-top: 12px;
line-height: 9px;
}
.numbers__star-graph__row {
display: flex;
width: 100%;
}
.numbers__star-graph__row__stars {
display: flex;
min-width: 45px;
font-size: 8px;
justify-content: flex-end;
margin-right: 6px;
& :global(.star) {
fill: var(--systemSecondary);
width: 8px;
height: 8px;
}
}
.numbers__star-graph__row__bar {
height: 2px;
width: 100%;
background: var(--systemQuaternary);
margin-top: 3px;
}
.numbers__star-graph__row__bar__foreground {
height: 2px;
background: var(--ratingBarColor, --systemSecondary);
max-width: 100%;
}
</style>