PostCard's Link is inline by default; wrapped in a div on the pool detail page it stopped being blockified like a grid child, so its rating-tinted border collapsed into a vertical line on the left. The card is now block-level, and the pool grid only wraps blacklisted posts (for the red ring), so normal cards render exactly like the Online grid.
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { CheckCircle2 } from "lucide-react";
|
|
import { Link } from "react-router-dom";
|
|
|
|
import { cn } from "@/lib/cn";
|
|
import type { E621Post } from "@/lib/e621";
|
|
import { formatBytes } from "@/lib/format";
|
|
|
|
const ratingBorder: Record<string, string> = {
|
|
s: "border-ctp-green/25 hover:border-ctp-green/60",
|
|
q: "border-ctp-peach/25 hover:border-ctp-peach/60",
|
|
e: "border-ctp-red/25 hover:border-ctp-red/60",
|
|
};
|
|
|
|
const ratingPill: Record<string, string> = {
|
|
s: "bg-ctp-green text-ctp-crust",
|
|
q: "bg-ctp-peach text-ctp-crust",
|
|
e: "bg-ctp-red text-ctp-crust",
|
|
};
|
|
|
|
export function PostCard({
|
|
post,
|
|
inLibrary,
|
|
from,
|
|
}: {
|
|
post: E621Post;
|
|
inLibrary: boolean;
|
|
from?: string;
|
|
}) {
|
|
return (
|
|
<Link
|
|
to={`/detail/${post.id}`}
|
|
state={from ? { from } : undefined}
|
|
className={cn(
|
|
"group block overflow-hidden rounded-lg border bg-ctp-base transition",
|
|
ratingBorder[post.rating] ?? "border-ctp-surface0",
|
|
)}
|
|
>
|
|
<div className="relative aspect-square overflow-hidden bg-ctp-mantle">
|
|
{post.preview.url ? (
|
|
<img
|
|
src={post.preview.url}
|
|
alt={`Post #${post.id}`}
|
|
loading="lazy"
|
|
className="h-full w-full object-cover transition duration-200 group-hover:scale-[1.03]"
|
|
/>
|
|
) : (
|
|
<div className="flex h-full w-full items-center justify-center text-xs text-ctp-overlay0">
|
|
No preview
|
|
</div>
|
|
)}
|
|
<span
|
|
className={cn(
|
|
"absolute left-2 top-2 rounded-full px-1.5 py-0.5 font-mono text-[10px] font-semibold uppercase",
|
|
ratingPill[post.rating] ?? "bg-ctp-surface1 text-ctp-text",
|
|
)}
|
|
>
|
|
{post.rating}
|
|
</span>
|
|
<span className="absolute right-2 top-2 rounded-sm bg-ctp-crust/80 px-1.5 py-0.5 font-mono text-[10px] uppercase text-ctp-overlay1">
|
|
{post.file.ext}
|
|
</span>
|
|
{inLibrary ? (
|
|
<span
|
|
className="absolute bottom-2 right-2 flex items-center gap-1 rounded-full bg-ctp-green/90 px-1.5 py-0.5 font-mono text-[10px] font-medium text-ctp-crust"
|
|
title="Already in your library"
|
|
>
|
|
<CheckCircle2 className="h-3 w-3" /> IN
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
<div className="flex items-center justify-between gap-2 px-2.5 py-2">
|
|
<span className="font-mono text-xs text-ctp-subtext1">#{post.id}</span>
|
|
<span className="font-mono text-[11px] text-ctp-overlay0">
|
|
▲ {post.score.total} · {formatBytes(post.file.size)}
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|