refactor(links): extract sort menu and fix sort logic

- Extracts dropdown sort menu into separate DashboardLinksSort component
- Fixes incorrect sort order for newest/oldest links
- Adds internationalization support for sort options
- Updates QR code download button size for consistency
- Adds helpful tooltip about sort limitation for loaded links

The sort logic was reversed where newest/oldest were concerned, this fixes
that while making the sorting feature more maintainable through component
extraction.
This commit is contained in:
ccbikai 2025-03-16 11:52:29 +08:00
parent 71c726ab9b
commit 5118201911
5 changed files with 75 additions and 40 deletions

View file

@ -1,27 +1,22 @@
<script setup>
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '#components'
import { useInfiniteScroll } from '@vueuse/core'
import { ArrowUpDown, Loader } from 'lucide-vue-next'
import { Loader } from 'lucide-vue-next'
const links = ref([])
const limit = 24
let cursor = ''
let listComplete = false
let listError = false
const sortBy = ref('newest')
const sortBy = ref('az')
const displayedLinks = computed(() => {
const sorted = [...links.value]
switch (sortBy.value) {
case 'newest':
return sorted.sort((a, b) => b.createdAt - a.createdAt)
case 'oldest':
return sorted.sort((a, b) => a.createdAt - b.createdAt)
case 'oldest':
return sorted.sort((a, b) => b.createdAt - a.createdAt)
case 'az':
return sorted.sort((a, b) => a.slug.localeCompare(b.slug))
case 'za':
@ -83,33 +78,7 @@ function updateLinkList(link, type) {
<DashboardNav class="flex-1">
<div class="flex items-center gap-2">
<DashboardLinksEditor @update:link="updateLinkList" />
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="outline" size="sm">
<ArrowUpDown class="mr-2 h-4 w-4" />
Sort by: {{
sortBy === 'newest' ? 'Newest First'
: sortBy === 'oldest' ? 'Oldest First'
: sortBy === 'az' ? 'Slug A-Z'
: 'Slug Z-A'
}}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem @click="sortBy = 'newest'">
Newest First
</DropdownMenuItem>
<DropdownMenuItem @click="sortBy = 'oldest'">
Oldest First
</DropdownMenuItem>
<DropdownMenuItem @click="sortBy = 'az'">
A to Z
</DropdownMenuItem>
<DropdownMenuItem @click="sortBy = 'za'">
Z to A
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<DashboardLinksSort v-model:sort-by="sortBy" />
</div>
</DashboardNav>
<LazyDashboardLinksSearch />

View file

@ -118,7 +118,11 @@ onMounted(() => {
>
</div>
</div>
<Button variant="outline" @click="downloadQRCode">
<Button
variant="outline"
size="sm"
@click="downloadQRCode"
>
<Download class="w-4 h-4 mr-2" />
{{ $t('links.download_qr_code') }}
</Button>

View file

@ -0,0 +1,48 @@
<script setup>
import { ArrowUpDown } from 'lucide-vue-next'
defineProps({
sortBy: {
type: String,
default: 'az',
},
})
const emit = defineEmits(['update:sortBy'])
</script>
<template>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="outline">
<TooltipProvider>
<Tooltip>
<TooltipTrigger class="flex items-center">
<ArrowUpDown class="h-4 w-4 sm:mr-2" />
<span class="hidden sm:inline">
{{ $t('links.sort.newest') }}
</span>
</TooltipTrigger>
<TooltipContent>
<p>{{ $t('links.sort.tip') }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem @click="emit('update:sortBy', 'newest')">
{{ $t('links.sort.newest') }}
</DropdownMenuItem>
<DropdownMenuItem @click="emit('update:sortBy', 'oldest')">
{{ $t('links.sort.oldest') }}
</DropdownMenuItem>
<DropdownMenuItem @click="emit('update:sortBy', 'az')">
{{ $t('links.sort.az') }}
</DropdownMenuItem>
<DropdownMenuItem @click="emit('update:sortBy', 'za')">
{{ $t('links.sort.za') }}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</template>

View file

@ -157,6 +157,13 @@
"expires_at": "Expires At",
"no_more": "No more links",
"load_failed": "Loading links failed,",
"download_qr_code": "Download QR Code"
"download_qr_code": "Download QR Code",
"sort": {
"newest": "Newest First",
"oldest": "Oldest First",
"az": "Slug A-Z",
"za": "Slug Z-A",
"tip": "Experience: Only for loaded links"
}
}
}

View file

@ -157,6 +157,13 @@
"expires_at": "过期时间",
"no_more": "没有更多链接",
"load_failed": "加载链接失败,",
"download_qr_code": "下载二维码"
"download_qr_code": "下载二维码",
"sort": {
"newest": "最新",
"oldest": "最旧",
"az": "字母(A-Z)",
"za": "字母(Z-A)",
"tip": "体验功能: 仅对已经加载的链接有效"
}
}
}