37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
import { Library, GraduationCap, Star, Repeat } from "lucide-react"
|
|
import type { KnowledgeItem } from "@/lib/types"
|
|
|
|
export function StatsBar({ items }: { items: KnowledgeItem[] }) {
|
|
const total = items.length
|
|
const mastered = items.filter((i) => i.mastery === "mastered").length
|
|
const favorites = items.filter((i) => i.is_favorite).length
|
|
const now = Date.now()
|
|
const due = items.filter((i) => i.next_review_at && new Date(i.next_review_at).getTime() <= now).length
|
|
const masteredPct = total ? Math.round((mastered / total) * 100) : 0
|
|
|
|
const stats = [
|
|
{ label: "知识点总数", value: total, icon: Library, hint: "全部收录" },
|
|
{ label: "已掌握", value: mastered, icon: GraduationCap, hint: `${masteredPct}% 掌握率` },
|
|
{ label: "已收藏", value: favorites, icon: Star, hint: "重点关注" },
|
|
{ label: "待复习", value: due, icon: Repeat, hint: "今日到期" },
|
|
]
|
|
|
|
return (
|
|
<div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
|
|
{stats.map((s) => (
|
|
<div
|
|
key={s.label}
|
|
className="rounded-xl border border-border bg-card/60 p-4 backdrop-blur-sm"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs text-muted-foreground">{s.label}</span>
|
|
<s.icon className="size-4 text-primary" />
|
|
</div>
|
|
<p className="mt-2 font-mono text-2xl font-semibold tracking-tight">{s.value}</p>
|
|
<p className="mt-1 text-xs text-muted-foreground">{s.hint}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|