Files
dht/web/src/components/SearchResultCard.vue
T

30 lines
1.7 KiB
Vue

<script setup lang="ts">
import { ChevronRight, Files, Flame, HardDrive, Radio, Repeat2 } from '@lucide/vue'
import { availabilityLabel, formatBytes, heatLabel, relativeDate } from '@/lib/format'
import type { SearchHit } from '@/types/api'
defineProps<{ hit: SearchHit }>()
defineEmits<{ select: [hit: SearchHit] }>()
</script>
<template>
<button class="group w-full rounded-xl border bg-card p-5 text-left shadow-xs transition hover:-translate-y-0.5 hover:border-foreground/20 hover:shadow-md" type="button" @click="$emit('select', hit)">
<div class="flex items-start gap-4">
<div class="min-w-0 flex-1">
<h2 class="truncate text-base font-semibold tracking-tight">{{ hit.name }}</h2>
<p class="mt-1.5 truncate font-mono text-[11px] text-muted-foreground">{{ hit.info_hash }}</p>
</div>
<ChevronRight class="mt-1 size-4 shrink-0 text-muted-foreground transition group-hover:translate-x-0.5 group-hover:text-foreground" />
</div>
<div class="mt-4 flex flex-wrap gap-x-5 gap-y-2 text-xs text-muted-foreground">
<span class="result-meta"><HardDrive />{{ formatBytes(hit.total_size) }}</span>
<span class="result-meta"><Files />{{ hit.file_count.toLocaleString() }} 个文件</span>
<span class="result-meta"><Repeat2 />{{ hit.variant_count }} 个版本</span>
<span class="result-meta"><Flame />{{ heatLabel[hit.heat.level] }} {{ hit.heat.score }}</span>
<span class="result-meta" :class="hit.availability.status === 'active' && 'text-emerald-600'"><Radio />{{ availabilityLabel[hit.availability.status] }}</span>
<span class="ml-auto">最近发现 {{ relativeDate(hit.last_seen) }}</span>
</div>
</button>
</template>