|
|
@@ -0,0 +1,99 @@
|
|
|
+<template>
|
|
|
+ <div class="sort-menu">
|
|
|
+ <button
|
|
|
+ class="sort-btn"
|
|
|
+ :class="{ 'active': modelValue !== 'time-asc' }"
|
|
|
+ @click.stop="open = !open"
|
|
|
+ :title="lang.ssSpkSortTimeAsc"
|
|
|
+ >
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
|
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M3 6h18M3 12h12M3 18h6" />
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ <template v-if="open">
|
|
|
+ <div class="sort-overlay" @click="open = false" />
|
|
|
+ <div class="sort-dropdown">
|
|
|
+ <button v-for="opt in options" :key="opt.key"
|
|
|
+ class="sort-option"
|
|
|
+ :class="{ 'active': modelValue === opt.key }"
|
|
|
+ @click="onSelect(opt.key)">
|
|
|
+ {{ opt.label }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ref, computed } from 'vue'
|
|
|
+import { lang } from '@/main'
|
|
|
+
|
|
|
+export type SortKey = 'time-asc' | 'time-desc' | 'name-asc'
|
|
|
+
|
|
|
+const props = defineProps<{ modelValue: SortKey }>()
|
|
|
+const emit = defineEmits<{ 'update:modelValue': [val: SortKey] }>()
|
|
|
+
|
|
|
+const open = ref(false)
|
|
|
+
|
|
|
+const options = computed(() => [
|
|
|
+ { key: 'time-asc' as SortKey, label: (lang as any).ssSpkSortTimeAsc },
|
|
|
+ { key: 'time-desc' as SortKey, label: (lang as any).ssSpkSortTimeDesc },
|
|
|
+ { key: 'name-asc' as SortKey, label: (lang as any).ssSpkSortNameAsc },
|
|
|
+])
|
|
|
+
|
|
|
+function onSelect(key: SortKey) {
|
|
|
+ emit('update:modelValue', key)
|
|
|
+ open.value = false
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.sort-menu { position: relative; }
|
|
|
+
|
|
|
+.sort-btn {
|
|
|
+ width: 28px; height: 28px;
|
|
|
+ display: flex; align-items: center; justify-content: center;
|
|
|
+ border-radius: 6px;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ color: #9ca3af;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background .15s ease;
|
|
|
+ &:hover { background: #f3f4f6; }
|
|
|
+ &.active {
|
|
|
+ color: #ca8a04;
|
|
|
+ background: #fef3c7;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.sort-overlay {
|
|
|
+ position: fixed; inset: 0;
|
|
|
+ z-index: 30;
|
|
|
+}
|
|
|
+
|
|
|
+.sort-dropdown {
|
|
|
+ position: absolute;
|
|
|
+ right: 0; top: 32px;
|
|
|
+ z-index: 40;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 4px 12px rgba(0,0,0,.08);
|
|
|
+ padding: 4px 0;
|
|
|
+ min-width: 128px;
|
|
|
+}
|
|
|
+
|
|
|
+.sort-option {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ padding: 6px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ color: #4b5563;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover { background: #f9fafb; }
|
|
|
+ &.active { color: #ca8a04; background: #fef3c7; font-weight: 500; }
|
|
|
+}
|
|
|
+</style>
|