PlaymateCards.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <script setup lang="ts">
  2. import LocateSvg from '~/assets/icons/locate.svg'
  3. type PlaymateCard = {
  4. id: number
  5. name: string
  6. age: number
  7. gender: 0 | 1 | 2 // 0=未知,1=男,2=女
  8. location: string
  9. latency: string
  10. rate: number
  11. rating: number
  12. bio: string
  13. avatar: string
  14. gallery: string[]
  15. }
  16. const assets = {
  17. avatar: 'https://www.figma.com/api/mcp/asset/90a1b39b-5843-4d4a-b3cf-87bc6d1041a5',
  18. galleryOne: 'https://www.figma.com/api/mcp/asset/57bca0f4-24ad-4c4f-8aeb-57bc2db6dbe2',
  19. galleryTwo: 'https://www.figma.com/api/mcp/asset/90a34be7-3f84-4b53-abfb-e52f9b328407',
  20. galleryThree: 'https://www.figma.com/api/mcp/asset/28911d37-523b-4b61-930b-84625ec26511',
  21. } as const
  22. const playmateCards: PlaymateCard[] = [
  23. {
  24. id: 1,
  25. name: 'Super Beautiful',
  26. age: 20,
  27. gender: 2,
  28. location: 'Jakarta',
  29. latency: '15"',
  30. rate: 1000,
  31. rating: 4,
  32. bio: 'Hello brother, multiple seasons of S, online technology, online awareness in ...',
  33. avatar: assets.avatar,
  34. gallery: [assets.galleryOne, assets.galleryTwo, assets.galleryThree],
  35. },
  36. {
  37. id: 2,
  38. name: 'Super Beautiful',
  39. age: 20,
  40. gender: 2,
  41. location: 'Timur',
  42. latency: '15"',
  43. rate: 1000,
  44. rating: 4,
  45. bio: 'Always ready for ranked matches, can guide team strategy and communication.',
  46. avatar: assets.avatar,
  47. gallery: [assets.galleryOne, assets.galleryTwo, assets.galleryThree],
  48. },
  49. {
  50. id: 3,
  51. name: 'Super Beautiful',
  52. age: 20,
  53. gender: 1,
  54. location: 'Timur',
  55. latency: '15"',
  56. rate: 1000,
  57. rating: 4,
  58. bio: 'Specialized in Mobile Legends jungle role, offering duo coaching service.',
  59. avatar: assets.avatar,
  60. gallery: [assets.galleryOne, assets.galleryTwo, assets.galleryThree],
  61. },
  62. ]
  63. const formatRate = (rate: number) => new Intl.NumberFormat().format(rate)
  64. </script>
  65. <template>
  66. <section class="flex flex-col gap-4 pb-10">
  67. <article
  68. v-for="card in playmateCards"
  69. :key="card.id"
  70. class="playmate-card p-3 overflow-hidden"
  71. >
  72. <div class="flex gap-3">
  73. <div class="flex w-[76px] flex-col items-center">
  74. <div class="avatar-box relative flex flex-col items-center">
  75. <img
  76. :src="card.avatar"
  77. :alt="card.name"
  78. class="avatar"
  79. loading="lazy"
  80. >
  81. <div class="avatar-audio absolute bottom-0" />
  82. </div>
  83. <div class="flex items-center gap-1">
  84. <div class="diamond-icon" />
  85. <p class="text-xs">
  86. <span class="font-title">{{ formatRate(card.rate) }}</span>
  87. <span class="text-[#8e8e8e]">/h</span>
  88. </p>
  89. </div>
  90. </div>
  91. <div class="flex-1">
  92. <div class="flex items-start justify-between gap-3">
  93. <div class="flex items-center gap-2">
  94. <h2 class="text-sm font-semibold">
  95. {{ card.name }}
  96. </h2>
  97. <CommonGender
  98. :gender="card.gender"
  99. :age="card.age"
  100. />
  101. </div>
  102. <div class="flex items-center gap-1 text-xs text-text-secondary">
  103. <LocateSvg />
  104. <span>{{ card.location }}</span>
  105. </div>
  106. </div>
  107. <div class="mt-1">
  108. <CommonStarRating
  109. :model-value="card.rating"
  110. mode="display"
  111. :size="10"
  112. />
  113. </div>
  114. <div class="summary mt-2 flex items-center">
  115. <div class="summary-triangle z-0" />
  116. <div class="summary-bg z-0" />
  117. <div class="summary-content z-10">
  118. <p class="text-xs text-text-description">
  119. {{ card.bio }}
  120. </p>
  121. </div>
  122. </div>
  123. <div class="mt-2 flex gap-2">
  124. <div
  125. v-for="(image, index) in card.gallery"
  126. :key="`${card.id}-gallery-${index}`"
  127. class="h-[72px] w-[72px] overflow-hidden rounded-xl"
  128. >
  129. <img
  130. :src="image"
  131. :alt="`${card.name} gallery ${index + 1}`"
  132. class="size-full object-cover"
  133. loading="lazy"
  134. >
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. </article>
  140. </section>
  141. </template>
  142. <style lang="scss" scoped>
  143. .playmate-card {
  144. @include size(100%, auto);
  145. flex-shrink: 0;
  146. border-radius: 49px 12px 12px 12px;
  147. background: #FFF;
  148. .diamond-icon {
  149. @include size(10px, 10px);
  150. @include bg('~/assets/images/common/diamond.png');
  151. }
  152. }
  153. .avatar-box {
  154. .avatar {
  155. @include size(76px, 76px);
  156. border-radius: 50%;
  157. }
  158. .avatar-audio {
  159. @include size(64px, 22px);
  160. @include bg('~/assets/images/common/audio.png');
  161. }
  162. }
  163. .summary {
  164. @include size(100%, 38px);
  165. position: relative;
  166. .summary-triangle {
  167. position: absolute;
  168. width: 0;
  169. height: 0;
  170. border-style: solid;
  171. border-width: 0 4px 4px 4px;
  172. border-color: transparent transparent rgba(217, 255, 248, 0.70) transparent;
  173. left: 12px;
  174. top: -4px;
  175. }
  176. .summary-bg {
  177. position: absolute;
  178. width: 100%;
  179. height: 100%;
  180. border-radius: 12px;
  181. background: linear-gradient(90deg, rgba(217, 255, 248, 0.70) 0%, rgba(249, 255, 242, 0.70) 99.53%);
  182. }
  183. .summary-content {
  184. position: relative;
  185. padding: 0 12px;
  186. }
  187. }
  188. </style>