frontend/components/manga-card.tsx
2025-10-21 20:49:47 -03:00

121 lines
3.8 KiB
TypeScript

import Link from "next/link";
import Image from "next/image";
import { Star, Calendar, Database } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
interface Manga {
id: number;
title: string;
coverImageKey?: string;
status?: string;
publishedFrom?: string;
publishedTo?: string;
providerCount?: number;
authors: string[];
genres: string[];
score: number;
// chapters: number
}
interface MangaCardProps {
manga: Manga;
}
export function MangaCard({ manga }: MangaCardProps) {
const formatter = new Intl.DateTimeFormat("en-US", {
month: "2-digit",
day: "2-digit",
year: "numeric",
});
const publishedTo = manga.publishedTo
? formatter.format(new Date(manga.publishedTo))
: null;
const publishedFrom = manga.publishedFrom
? formatter.format(new Date(manga.publishedFrom))
: null;
const dateRange = publishedTo
? `${publishedFrom} - ${publishedTo}`
: `${publishedFrom} - Present`;
const author = manga.authors.join(", ");
return (
<Link href={`/manga/${manga.id}`}>
<Card className="group overflow-hidden border-border bg-card py-0 gap-0 transition-all hover:border-primary/50 hover:shadow-lg hover:shadow-primary/10 cursor-pointer">
<CardContent className="p-0">
<div className="relative aspect-[2/3] overflow-hidden bg-muted">
<Image
src={
(manga.coverImageKey &&
"http://omv.badger-pirarucu.ts.net:9000/mangamochi/" +
manga.coverImageKey) ||
"/placeholder.svg"
}
alt={manga.title}
fill
className="object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div className="absolute right-2 top-2">
<Badge
variant="secondary"
className="border border-border/50 bg-background/80 text-foreground backdrop-blur-sm"
>
{manga.status}
</Badge>
</div>
</div>
{/* Info */}
<div className="space-y-2 p-4">
<h3 className="line-clamp-2 text-sm font-semibold leading-tight text-foreground">
{manga.title}
</h3>
<p className="text-xs text-muted-foreground">{author}</p>
{publishedFrom && (
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<Calendar className="h-3 w-3" />
<span>{dateRange}</span>
</div>
)}
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<Star className="h-3.5 w-3.5 fill-primary text-primary" />
<span className="text-xs font-medium text-foreground">
{manga.score}
</span>
</div>
{/*<span className="text-xs text-muted-foreground">Ch. {manga.chapters}</span>*/}
</div>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<Database className="h-3 w-3" />
<span>
{manga.providerCount}{" "}
{manga.providerCount === 1 ? "provider" : "providers"}
</span>
</div>
<div className="flex flex-wrap gap-1">
{manga.genres.map((genre) => (
<Badge
key={genre}
variant="outline"
className="border-border text-xs text-muted-foreground"
>
{genre}
</Badge>
))}
</div>
</div>
</CardContent>
</Card>
</Link>
);
}