100 lines
3.5 KiB
TypeScript
100 lines
3.5 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>
|
|
)
|
|
}
|