SortMenu.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <template>
  2. <div class="sort-menu">
  3. <button
  4. class="sort-btn"
  5. :class="{ 'active': modelValue !== 'time-asc' }"
  6. @click.stop="open = !open"
  7. :title="lang.ssSpkSortTimeAsc"
  8. >
  9. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
  10. stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  11. <path d="M3 6h18M3 12h12M3 18h6" />
  12. </svg>
  13. </button>
  14. <template v-if="open">
  15. <div class="sort-overlay" @click="open = false" />
  16. <div class="sort-dropdown">
  17. <button v-for="opt in options" :key="opt.key"
  18. class="sort-option"
  19. :class="{ 'active': modelValue === opt.key }"
  20. @click="onSelect(opt.key)">
  21. {{ opt.label }}
  22. </button>
  23. </div>
  24. </template>
  25. </div>
  26. </template>
  27. <script lang="ts" setup>
  28. import { ref, computed } from 'vue'
  29. import { lang } from '@/main'
  30. export type SortKey = 'time-asc' | 'time-desc' | 'name-asc'
  31. const props = defineProps<{ modelValue: SortKey }>()
  32. const emit = defineEmits<{ 'update:modelValue': [val: SortKey] }>()
  33. const open = ref(false)
  34. const options = computed(() => [
  35. { key: 'time-asc' as SortKey, label: (lang as any).ssSpkSortTimeAsc },
  36. { key: 'time-desc' as SortKey, label: (lang as any).ssSpkSortTimeDesc },
  37. { key: 'name-asc' as SortKey, label: (lang as any).ssSpkSortNameAsc },
  38. ])
  39. function onSelect(key: SortKey) {
  40. emit('update:modelValue', key)
  41. open.value = false
  42. }
  43. </script>
  44. <style lang="scss" scoped>
  45. .sort-menu { position: relative; }
  46. .sort-btn {
  47. width: 28px; height: 28px;
  48. display: flex; align-items: center; justify-content: center;
  49. border-radius: 6px;
  50. background: transparent;
  51. border: none;
  52. color: #9ca3af;
  53. cursor: pointer;
  54. transition: background .15s ease;
  55. &:hover { background: #f3f4f6; }
  56. &.active {
  57. color: #ca8a04;
  58. background: #fef3c7;
  59. }
  60. }
  61. .sort-overlay {
  62. position: fixed; inset: 0;
  63. z-index: 30;
  64. }
  65. .sort-dropdown {
  66. position: absolute;
  67. right: 0; top: 32px;
  68. z-index: 40;
  69. background: #fff;
  70. border: 1px solid #e5e7eb;
  71. border-radius: 8px;
  72. box-shadow: 0 4px 12px rgba(0,0,0,.08);
  73. padding: 4px 0;
  74. min-width: 128px;
  75. }
  76. .sort-option {
  77. width: 100%;
  78. text-align: left;
  79. padding: 6px 12px;
  80. font-size: 12px;
  81. background: transparent;
  82. border: none;
  83. color: #4b5563;
  84. cursor: pointer;
  85. &:hover { background: #f9fafb; }
  86. &.active { color: #ca8a04; background: #fef3c7; font-weight: 500; }
  87. }
  88. </style>