Reading progress
- New ReadingProgressButton client component that reads/writes
localStorage key "sunnymh:last-read:{slug}"
- PageReader writes the currently-visible chapter as the user scrolls
through continuous chapters
- Manga detail CTA now reads: "开始阅读" on first visit, or
"继续阅读 · #{N} {title}" when a prior chapter is stored (with
spacing and truncation for long titles)
Multiple genres
- lib/genres.ts with parseGenres() and collectGenres() helpers to
split "冒险, 恋爱, 魔幻" into a list and aggregate across a collection
- Manga detail renders one pill per genre
- GenreTabs filters via parseGenres(...).includes(activeGenre) so a
multi-genre manga appears under each of its genres
- Home / Genre pages compute the tab list from collectGenres(signedManga)
- Card captions (GenreTabs + TrendingCarousel) show "冒险 · 恋爱 · 魔幻"
with truncation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
33 lines
1000 B
TypeScript
33 lines
1000 B
TypeScript
import { prisma } from "@/lib/db";
|
|
import { signCoverUrls } from "@/lib/r2";
|
|
import { collectGenres } from "@/lib/genres";
|
|
import { TrendingCarousel } from "@/components/TrendingCarousel";
|
|
import { GenreTabs } from "@/components/GenreTabs";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function Home() {
|
|
const manga = await prisma.manga.findMany({
|
|
where: { status: "PUBLISHED" },
|
|
orderBy: { updatedAt: "desc" },
|
|
include: { _count: { select: { chapters: true } } },
|
|
});
|
|
|
|
const signedManga = await signCoverUrls(manga);
|
|
|
|
// Top 10 for trending
|
|
const trending = signedManga.slice(0, 10);
|
|
|
|
const genres = collectGenres(signedManga);
|
|
|
|
return (
|
|
<div className="max-w-6xl mx-auto px-4 py-5 space-y-8">
|
|
{/* Trending section — Webtoon-style ranked carousel */}
|
|
<TrendingCarousel manga={trending} />
|
|
|
|
{/* Genre browsing section — horizontal tabs + filtered grid */}
|
|
<GenreTabs manga={signedManga} genres={genres} />
|
|
</div>
|
|
);
|
|
}
|