92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
import { notFound } from "next/navigation";
|
|
import { prisma } from "@/lib/db";
|
|
import { ChapterList } from "@/components/ChapterList";
|
|
import type { Metadata } from "next";
|
|
|
|
type Props = {
|
|
params: Promise<{ slug: string }>;
|
|
};
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params;
|
|
const manga = await prisma.manga.findUnique({ where: { slug } });
|
|
if (!manga) return { title: "Not Found" };
|
|
return {
|
|
title: manga.title,
|
|
description: manga.description,
|
|
openGraph: {
|
|
title: manga.title,
|
|
description: manga.description,
|
|
images: [manga.coverUrl],
|
|
},
|
|
};
|
|
}
|
|
|
|
export default async function MangaDetailPage({ params }: Props) {
|
|
const { slug } = await params;
|
|
|
|
const manga = await prisma.manga.findUnique({
|
|
where: { slug },
|
|
include: {
|
|
chapters: {
|
|
orderBy: { number: "asc" },
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!manga) notFound();
|
|
|
|
return (
|
|
<div className="max-w-3xl mx-auto px-4 py-6">
|
|
{/* Hero section */}
|
|
<div className="flex gap-4 mb-6">
|
|
<div className="w-28 sm:w-36 shrink-0">
|
|
<div className="aspect-[3/4] rounded-xl overflow-hidden bg-card">
|
|
<img
|
|
src={manga.coverUrl}
|
|
alt={manga.title}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 min-w-0 py-1">
|
|
<h1 className="text-xl sm:text-2xl font-bold leading-tight mb-2">
|
|
{manga.title}
|
|
</h1>
|
|
<div className="flex flex-wrap items-center gap-2 mb-3">
|
|
<span className="px-2 py-0.5 text-[11px] font-semibold bg-accent/20 text-accent rounded-full">
|
|
{manga.genre}
|
|
</span>
|
|
<span className="px-2 py-0.5 text-[11px] font-semibold bg-surface text-muted rounded-full border border-border">
|
|
{manga.status}
|
|
</span>
|
|
<span className="text-xs text-muted">
|
|
{manga.chapters.length} chapter
|
|
{manga.chapters.length !== 1 ? "s" : ""}
|
|
</span>
|
|
</div>
|
|
<p className="text-sm text-muted leading-relaxed line-clamp-4 sm:line-clamp-none">
|
|
{manga.description}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Continue reading button */}
|
|
{manga.chapters.length > 0 && (
|
|
<a
|
|
href={`/manga/${manga.slug}/${manga.chapters[0].number}`}
|
|
className="block w-full py-3 mb-6 text-center text-sm font-semibold bg-accent hover:bg-accent-hover text-white rounded-xl transition-colors active:scale-[0.98]"
|
|
>
|
|
Start Reading — Ch. {manga.chapters[0].number}
|
|
</a>
|
|
)}
|
|
|
|
{/* Chapters */}
|
|
<div>
|
|
<h2 className="text-lg font-bold mb-3">Chapters</h2>
|
|
<ChapterList chapters={manga.chapters} mangaSlug={manga.slug} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|