/ shared / components / src / components / Rating / Rating.svelte
Rating.svelte
  1  <script lang="ts">
  2      import type { RatingCountsList } from './types';
  3      import { calculatePercentages } from './utils';
  4      import FilledStarIcon from '@amp/web-app-components/assets/icons/star-filled.svg';
  5  
  6      /**
  7       * @name Rating
  8       *
  9       * @description
 10       * This implements the standard rating lockup showing aggregate ratings
 11       *
 12       * Design:
 13       * https://pd-hi.apple.com/viewvc/Common/Modules/macOS/Podcasts/Lockups/Review%20Lockup.png?revision=57299
 14       *
 15       * Aria Discussions:
 16       * https://quip-apple.com/yvZaAbJMnAK0#JeB9CAOHPMd
 17       *
 18       * POTW difference:
 19       * No write a review on the web
 20       */
 21  
 22      export let averageRating: number | string;
 23      export let ratingCount: number;
 24      export let ratingCountText: string;
 25      export let ratingCountsList: RatingCountsList;
 26      export let totalText: string;
 27  
 28      $: ratingPercentList = calculatePercentages(ratingCountsList, ratingCount);
 29  </script>
 30  
 31  <div class="amp-rating" data-testid="rating-component">
 32      <div class="stats" aria-label={`${averageRating} ${totalText}`}>
 33          <div class="stats__main" data-testid="amp-rating__average-rating">
 34              {averageRating}
 35          </div>
 36          <div class="stats__total" data-testid="amp-rating__total-text">
 37              {totalText}
 38          </div>
 39      </div>
 40      <div class="numbers">
 41          <div class="numbers__star-graph">
 42              {#each ratingPercentList as value, i}
 43                  <div
 44                      class={`numbers__star-graph__row row-${i}`}
 45                      aria-label={`${5 - i} star, ${value}%`}
 46                  >
 47                      <!-- TODO: rdar://79873131 (Localize Aria Label in Rating Shared Component) -->
 48                      <div class="numbers__star-graph__row__stars">
 49                          <!-- In order to display the 5 stars to 1 stars we use the 5 - index as 0 index means 1 star and so on -->
 50                          {#each { length: 5 - i } as _}
 51                              <div class="star"><FilledStarIcon /></div>
 52                          {/each}
 53                      </div>
 54                      <div class="numbers__star-graph__row__bar">
 55                          <div
 56                              class="numbers__star-graph__row__bar__foreground"
 57                              style={`width: ${value}%`}
 58                              data-testid={`star-row-${5 - i}`}
 59                          />
 60                      </div>
 61                  </div>
 62              {/each}
 63          </div>
 64          <div class="numbers__count" data-testid="amp-rating__rating-count-text">
 65              {ratingCountText}
 66          </div>
 67      </div>
 68  </div>
 69  
 70  <style lang="scss">
 71      .amp-rating {
 72          display: flex;
 73      }
 74  
 75      .stats {
 76          margin-right: 10px;
 77          flex: 0 80px;
 78      }
 79  
 80      .stats__main {
 81          font-size: 50px;
 82          font-weight: bold;
 83          display: flex;
 84          justify-content: center;
 85      }
 86  
 87      .stats__total {
 88          display: flex;
 89          justify-content: center;
 90          color: var(--systemSecondary-text);
 91          font: var(--body-emphasized);
 92      }
 93  
 94      .numbers {
 95          width: 100%;
 96      }
 97  
 98      .numbers__count {
 99          display: flex;
100          align-items: flex-end;
101          justify-content: flex-end;
102          color: var(--systemSecondary-text);
103      }
104  
105      .numbers__star-graph {
106          margin-top: 12px;
107          line-height: 9px;
108      }
109  
110      .numbers__star-graph__row {
111          display: flex;
112          width: 100%;
113      }
114  
115      .numbers__star-graph__row__stars {
116          display: flex;
117          min-width: 45px;
118          font-size: 8px;
119          justify-content: flex-end;
120          margin-right: 6px;
121  
122          & :global(.star) {
123              fill: var(--systemSecondary);
124              width: 8px;
125              height: 8px;
126          }
127      }
128  
129      .numbers__star-graph__row__bar {
130          height: 2px;
131          width: 100%;
132          background: var(--systemQuaternary);
133          margin-top: 3px;
134      }
135  
136      .numbers__star-graph__row__bar__foreground {
137          height: 2px;
138          background: var(--ratingBarColor, --systemSecondary);
139          max-width: 100%;
140      }
141  </style>