diff --git a/src/app/[game]/[chapter]/page.tsx b/src/app/[game]/[chapter]/page.tsx new file mode 100644 index 0000000..3ad1bf1 --- /dev/null +++ b/src/app/[game]/[chapter]/page.tsx @@ -0,0 +1,54 @@ +import { notFound } from "next/navigation"; +import { getAllGames, getGame, getChapter, getAdjacentChapters } from "@/lib/content"; +import ChapterReader from "@/components/ChapterReader"; + +interface PageProps { + params: { game: string; chapter: string }; +} + +export function generateStaticParams() { + const games = getAllGames(); + const paths: { game: string; chapter: string }[] = []; + + for (const gameMeta of games) { + const game = getGame(gameMeta.slug); + for (const chapter of game.chapters) { + paths.push({ game: gameMeta.slug, chapter: chapter.slug }); + } + } + + return paths; +} + +export function generateMetadata({ params }: PageProps) { + try { + const game = getGame(params.game); + const chapter = getChapter(params.game, params.chapter); + return { + title: `${chapter.title} - ${game.title} | Cronicas de los Reinos`, + description: `Capitulo ${chapter.number} de ${game.title}`, + }; + } catch { + return { title: "No encontrado" }; + } +} + +export default function ChapterPage({ params }: PageProps) { + try { + const game = getGame(params.game); + const chapter = getChapter(params.game, params.chapter); + const { prev, next } = getAdjacentChapters(params.game, params.chapter); + + return ( + + ); + } catch { + notFound(); + } +} diff --git a/src/components/ChapterReader.tsx b/src/components/ChapterReader.tsx new file mode 100644 index 0000000..fb5fd66 --- /dev/null +++ b/src/components/ChapterReader.tsx @@ -0,0 +1,96 @@ +import Link from "next/link"; +import { MDXRemote } from "next-mdx-remote/rsc"; +import { GameMeta, Chapter } from "@/types"; +import ReadingProgress from "./ReadingProgress"; + +interface Props { + game: GameMeta; + chapter: Chapter; + totalChapters: number; + prevChapter: string | null; + nextChapter: string | null; +} + +export default function ChapterReader({ + game, + chapter, + totalChapters, + prevChapter, + nextChapter, +}: Props) { + return ( +
+ + + {/* Header */} +
+ + {game.title} + +
+ + {/* Chapter heading */} +
+

+ Capitulo {chapter.number} de {totalChapters} +

+

+ {chapter.title} +

+
+
+
+
+
+
+ + {/* Chapter content */} +
+ +
+ + {/* Chapter navigation */} + +
+ ); +} diff --git a/src/components/ReadingProgress.tsx b/src/components/ReadingProgress.tsx new file mode 100644 index 0000000..54c4e01 --- /dev/null +++ b/src/components/ReadingProgress.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { useEffect, useState } from "react"; + +export default function ReadingProgress({ color }: { color: string }) { + const [progress, setProgress] = useState(0); + + useEffect(() => { + function handleScroll() { + const scrollTop = window.scrollY; + const docHeight = document.documentElement.scrollHeight - window.innerHeight; + setProgress(docHeight > 0 ? (scrollTop / docHeight) * 100 : 0); + } + + window.addEventListener("scroll", handleScroll, { passive: true }); + return () => window.removeEventListener("scroll", handleScroll); + }, []); + + return ( +
+
+
+ ); +}