SortSection.vue 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <script setup lang="ts">
  2. import SortSvg from '~/assets/icons/sort.svg'
  3. import SortUpSvg from '~/assets/icons/sort-up.svg'
  4. import SortDownSvg from '~/assets/icons/sort-down.svg'
  5. type SortOption = {
  6. label: string
  7. value: string
  8. }
  9. type SortDirection = 'none' | 'asc' | 'desc'
  10. const sortOptions: SortOption[] = [
  11. { label: '评分', value: 'rating' },
  12. { label: '价格', value: 'price' },
  13. ]
  14. const activeSort = ref<SortOption['value']>(sortOptions[0]?.value ?? '')
  15. const sortDirections = ref<Record<string, SortDirection>>({
  16. rating: 'none',
  17. price: 'none',
  18. })
  19. // Handle sort click
  20. const handleSort = (sortValue: string) => {
  21. const currentDirection = sortDirections.value[sortValue]
  22. // Cycle through: none -> desc -> asc -> none -> ...
  23. if (currentDirection === 'none') {
  24. sortDirections.value[sortValue] = 'desc'
  25. }
  26. else if (currentDirection === 'desc') {
  27. sortDirections.value[sortValue] = 'asc'
  28. }
  29. else {
  30. sortDirections.value[sortValue] = 'none'
  31. }
  32. activeSort.value = sortValue
  33. }
  34. // Get sort icon component based on direction
  35. const getSortIcon = (sortValue: string) => {
  36. const direction = sortDirections.value[sortValue]
  37. if (direction === 'asc')
  38. return SortUpSvg
  39. if (direction === 'desc')
  40. return SortDownSvg
  41. return SortSvg
  42. }
  43. </script>
  44. <template>
  45. <section class="flex flex-wrap items-center justify-between bg-bg-primary z-50">
  46. <div class="flex gap-4 text-xs font-normal text-text-secondary">
  47. <button
  48. v-for="sortOption in sortOptions"
  49. :key="sortOption.value"
  50. class="flex items-center gap-1 py-1"
  51. :class="sortDirections[sortOption.value] !== 'none' ? 'text-text-primary' : ''"
  52. @click="handleSort(sortOption.value)"
  53. >
  54. {{ sortOption.label }}
  55. <component :is="getSortIcon(sortOption.value)" />
  56. </button>
  57. </div>
  58. <van-button
  59. round
  60. size="small"
  61. class="find-btn flex items-center justify-center"
  62. plain
  63. type="primary"
  64. >
  65. <span class="text-xs font-semibold text-text-secondary">Find your partner</span>
  66. <van-icon
  67. class="ml-1 text-text-secondary"
  68. name="arrow"
  69. size="14"
  70. />
  71. </van-button>
  72. </section>
  73. </template>
  74. <style lang="scss" scoped>
  75. .find-btn {
  76. @include size(152px, 40px);
  77. border-radius: 20px;
  78. border: 1px solid #FFF;
  79. background: linear-gradient(90deg, rgba(183, 238, 255, 0.60) 0.01%, rgba(221, 255, 183, 0.60) 26.99%, rgba(255, 255, 255, 0.60) 75.07%);
  80. }
  81. </style>