feat: 实现搜索结果的分类计数功能

添加搜索关键词时显示匹配结果数量的功能,同时优化了应用卡片和网格的UI样式
This commit is contained in:
2026-03-29 14:21:48 +08:00
parent d144d0d398
commit 5b2d96cf0a
3 changed files with 40 additions and 15 deletions

View File

@@ -303,6 +303,30 @@ const filteredApps = computed(() => {
}); });
const categoryCounts = computed(() => { const categoryCounts = computed(() => {
// 如果有搜索关键词,显示搜索结果数量
if (searchQuery.value.trim()) {
const q = searchQuery.value.toLowerCase().trim();
const counts: Record<string, number> = { all: 0 };
apps.value.forEach((app) => {
// 检查应用是否匹配搜索条件
const matches =
(app.name || "").toLowerCase().includes(q) ||
(app.pkgname || "").toLowerCase().includes(q) ||
(app.tags || "").toLowerCase().includes(q) ||
(app.more || "").toLowerCase().includes(q);
if (matches) {
counts.all++;
if (!counts[app.category]) counts[app.category] = 0;
counts[app.category]++;
}
});
return counts;
}
// 无搜索时显示总数量
const counts: Record<string, number> = { all: apps.value.length }; const counts: Record<string, number> = { all: apps.value.length };
apps.value.forEach((app) => { apps.value.forEach((app) => {
if (!counts[app.category]) counts[app.category] = 0; if (!counts[app.category]) counts[app.category] = 0;

View File

@@ -1,19 +1,17 @@
<template> <template>
<div <div
@click="openDetail" @click="openDetail"
class="group flex h-full cursor-pointer gap-4 rounded-2xl border border-slate-200/70 bg-white/90 p-4 shadow-sm transition hover:-translate-y-1 hover:border-brand/50 hover:shadow-lg dark:border-slate-800/60 dark:bg-slate-900/60" class="group flex cursor-pointer gap-3 rounded-xl border border-slate-200/70 bg-white/90 p-4 shadow-sm transition hover:-translate-y-0.5 hover:border-brand/50 hover:shadow-md dark:border-slate-800/60 dark:bg-slate-900/60"
> >
<div <div
class="flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl bg-gradient-to-b from-slate-100 to-slate-200 shadow-inner dark:from-slate-800 dark:to-slate-700" class="flex h-14 w-14 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-gradient-to-b from-slate-100 to-slate-200 shadow-inner dark:from-slate-800 dark:to-slate-700"
> >
<img <img
ref="iconImg" ref="iconImg"
:src="loadedIcon" :src="loadedIcon"
alt="icon" alt="icon"
:class="[ class="h-full w-full object-cover transition-opacity duration-300"
'h-full w-full object-cover transition-opacity duration-300', :class="isLoaded ? 'opacity-100' : 'opacity-0'"
isLoaded ? 'opacity-100' : 'opacity-0',
]"
/> />
</div> </div>
<div class="flex flex-1 flex-col gap-1 overflow-hidden"> <div class="flex flex-1 flex-col gap-1 overflow-hidden">
@@ -25,7 +23,7 @@
</div> </div>
<span <span
:class="[ :class="[
'rounded-md px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider shadow-sm', 'shrink-0 rounded-md px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider shadow-sm',
app.isMerged app.isMerged
? 'bg-purple-100 text-purple-600 dark:bg-purple-900/30 dark:text-purple-400' ? 'bg-purple-100 text-purple-600 dark:bg-purple-900/30 dark:text-purple-400'
: app.origin === 'spark' : app.origin === 'spark'
@@ -42,11 +40,11 @@
}} }}
</span> </span>
</div> </div>
<div class="text-sm text-slate-500 dark:text-slate-400"> <div class="text-sm text-slate-500 dark:text-slate-400 leading-tight">
{{ app.pkgname || "" }} · {{ app.version || "" }} {{ app.pkgname || "" }} · {{ app.version || "" }}
</div> </div>
<div class="text-sm text-slate-500 dark:text-slate-400"> <div class="truncate text-xs text-slate-500 dark:text-slate-400 leading-tight">
{{ description }} {{ description || '\u00A0' }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="!loading" v-if="!loading"
class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4"
> >
<AppCard <AppCard
v-for="(app, index) in apps" v-for="(app, index) in apps"
@@ -12,23 +12,26 @@
</div> </div>
<div <div
v-else v-else
class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4"
> >
<div <div
v-for="n in 8" v-for="n in 8"
:key="n" :key="n"
class="flex gap-4 rounded-2xl border border-slate-200/60 bg-white/80 p-4 shadow-sm dark:border-slate-800/60 dark:bg-slate-900/50" class="flex gap-3 rounded-xl border border-slate-200/60 bg-white/80 p-4 shadow-sm dark:border-slate-800/60 dark:bg-slate-900/50"
> >
<div <div
class="h-16 w-16 animate-pulse rounded-2xl bg-slate-200 dark:bg-slate-800" class="h-14 w-14 shrink-0 animate-pulse rounded-xl bg-slate-200 dark:bg-slate-800"
></div> ></div>
<div class="flex flex-1 flex-col justify-center gap-2"> <div class="flex flex-1 flex-col gap-1.5">
<div <div
class="h-4 w-2/3 animate-pulse rounded-full bg-slate-200 dark:bg-slate-800" class="h-4 w-2/3 animate-pulse rounded-full bg-slate-200 dark:bg-slate-800"
></div> ></div>
<div <div
class="h-3 w-1/2 animate-pulse rounded-full bg-slate-200/80 dark:bg-slate-800/80" class="h-3 w-1/2 animate-pulse rounded-full bg-slate-200/80 dark:bg-slate-800/80"
></div> ></div>
<div
class="h-3 w-3/4 animate-pulse rounded-full bg-slate-200/60 dark:bg-slate-800/60"
></div>
</div> </div>
</div> </div>
</div> </div>