71 lines
2.4 KiB
TypeScript
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>
|
||
|
|
);
|
||
|
|
}
|