58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
"use client";
|
||
|
||
import { useMemo, useState } from "react";
|
||
import { AppGrid, CategoryTabs } from "@/components/sections";
|
||
import { AppResource } from "@/lib/types";
|
||
|
||
export function AppsExplorer({ apps }: { apps: AppResource[] }) {
|
||
const [query, setQuery] = useState("");
|
||
const [category, setCategory] = useState("all");
|
||
const [sort, setSort] = useState("latest");
|
||
const [count, setCount] = useState(6);
|
||
|
||
const filtered = useMemo(() => {
|
||
let list = [...apps].filter((a) =>
|
||
[a.name, a.subtitle, ...a.tags].join(" ").toLowerCase().includes(query.toLowerCase())
|
||
);
|
||
if (category !== "all") list = list.filter((a) => a.category === category);
|
||
list.sort((a, b) => {
|
||
if (sort === "hot") return b.downloads - a.downloads;
|
||
if (sort === "update") return b.updatedAt.localeCompare(a.updatedAt);
|
||
return b.uploadedAt.localeCompare(a.uploadedAt);
|
||
});
|
||
return list;
|
||
}, [apps, query, category, sort]);
|
||
|
||
return (
|
||
<section className="space-y-4">
|
||
<div className="card-glass space-y-3">
|
||
<input
|
||
className="w-full rounded-xl border border-white/15 bg-slate-900/50 px-3 py-2 text-sm outline-none"
|
||
placeholder="搜索资源、标签或名称"
|
||
value={query}
|
||
onChange={(e) => setQuery(e.target.value)}
|
||
/>
|
||
<CategoryTabs active={category} onChange={setCategory} />
|
||
<div className="flex items-center gap-2 text-sm">
|
||
<span>排序:</span>
|
||
{[
|
||
{ id: "latest", label: "最新" },
|
||
{ id: "hot", label: "最热" },
|
||
{ id: "update", label: "更新日期" },
|
||
].map((s) => (
|
||
<button key={s.id} className={`pill ${sort === s.id ? "pill-active" : ""}`} onClick={() => setSort(s.id)}>
|
||
{s.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<AppGrid apps={filtered.slice(0, count)} />
|
||
{count < filtered.length && (
|
||
<button onClick={() => setCount((c) => c + 6)} className="mx-auto block rounded-xl border border-white/20 px-4 py-2 text-sm">
|
||
加载更多
|
||
</button>
|
||
)}
|
||
</section>
|
||
);
|
||
}
|