Files
SnapAndAnaly/frontend/src/components/Card.tsx
T
congsh 5c028d7952 Initial commit: snapAna 截图智能整理工具
包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 15:45:50 +08:00

71 lines
2.4 KiB
TypeScript

import { Star } from "lucide-react";
import type { ScreenshotBrief } from "@/types";
import { StatusBadge } from "./StatusBadge";
interface Props {
shot: ScreenshotBrief;
onOpen: (id: number) => void;
onToggleFav?: (shot: ScreenshotBrief) => void;
}
export function Card({ shot, onOpen, onToggleFav }: Props) {
const date = new Date(shot.captured_at).toLocaleString("zh-CN", {
hour12: false,
});
return (
<button
onClick={() => onOpen(shot.id)}
className="card-hover group relative flex w-full flex-col overflow-hidden rounded-xl border border-slate-800 bg-slate-900/40 text-left"
>
<div className="relative aspect-[4/3] w-full overflow-hidden bg-slate-800">
{shot.thumb_url ? (
<img
src={shot.thumb_url}
alt=""
loading="lazy"
className="h-full w-full object-cover transition group-hover:scale-[1.02]"
/>
) : (
<div className="flex h-full w-full items-center justify-center text-xs text-slate-500">
</div>
)}
{shot.category && (
<span
className="absolute left-2 top-2 inline-flex items-center rounded-full bg-black/55 px-2 py-0.5 text-[10px] text-white backdrop-blur"
style={{
borderLeft: `3px solid ${shot.category.color ?? "#6366f1"}`,
}}
>
{shot.category.name}
</span>
)}
<button
className={`absolute right-2 top-2 rounded-full p-1.5 transition ${
shot.is_favorite
? "bg-amber-400/90 text-slate-900"
: "bg-black/40 text-slate-300 opacity-0 group-hover:opacity-100"
}`}
onClick={(e) => {
e.stopPropagation();
onToggleFav?.(shot);
}}
aria-label="收藏"
>
<Star size={14} fill={shot.is_favorite ? "currentColor" : "none"} />
</button>
</div>
<div className="flex flex-1 flex-col gap-1 px-3 py-2">
<div className="line-clamp-2 text-sm font-medium text-slate-100">
{shot.ai_title || "(未生成标题)"}
</div>
<div className="mt-auto flex items-center justify-between text-[11px] text-slate-500">
<span>{date}</span>
<StatusBadge status={shot.ai_status} />
</div>
</div>
</button>
);
}