Add auto-hide nav bars on scroll and chapter selector bottom sheet
Nav bars hide when scrolling down and reappear on scroll up. Replace static page count with a chapter picker that opens as a bottom sheet drawer for quick chapter navigation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6257f6c79d
commit
e7dc39738c
@ -53,6 +53,11 @@ export default async function ChapterReaderPage({ params }: Props) {
|
|||||||
? manga.chapters[chapterIndex + 1].number
|
? manga.chapters[chapterIndex + 1].number
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const allChapters = manga.chapters.map((c) => ({
|
||||||
|
number: c.number,
|
||||||
|
title: c.title,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageReader
|
<PageReader
|
||||||
pages={currentChapter.pages}
|
pages={currentChapter.pages}
|
||||||
@ -62,6 +67,7 @@ export default async function ChapterReaderPage({ params }: Props) {
|
|||||||
chapterTitle={currentChapter.title}
|
chapterTitle={currentChapter.title}
|
||||||
prevChapter={prevChapter}
|
prevChapter={prevChapter}
|
||||||
nextChapter={nextChapter}
|
nextChapter={nextChapter}
|
||||||
|
chapters={allChapters}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
type PageData = {
|
type PageData = {
|
||||||
@ -8,6 +8,11 @@ type PageData = {
|
|||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ChapterInfo = {
|
||||||
|
number: number;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
|
||||||
type PageReaderProps = {
|
type PageReaderProps = {
|
||||||
pages: PageData[];
|
pages: PageData[];
|
||||||
mangaSlug: string;
|
mangaSlug: string;
|
||||||
@ -16,6 +21,7 @@ type PageReaderProps = {
|
|||||||
chapterTitle: string;
|
chapterTitle: string;
|
||||||
prevChapter: number | null;
|
prevChapter: number | null;
|
||||||
nextChapter: number | null;
|
nextChapter: number | null;
|
||||||
|
chapters: ChapterInfo[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function PageReader({
|
export function PageReader({
|
||||||
@ -26,8 +32,26 @@ export function PageReader({
|
|||||||
chapterTitle,
|
chapterTitle,
|
||||||
prevChapter,
|
prevChapter,
|
||||||
nextChapter,
|
nextChapter,
|
||||||
|
chapters,
|
||||||
}: PageReaderProps) {
|
}: PageReaderProps) {
|
||||||
const [showUI, setShowUI] = useState(true);
|
const [showUI, setShowUI] = useState(true);
|
||||||
|
const [showDrawer, setShowDrawer] = useState(false);
|
||||||
|
const lastScrollY = useRef(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
const currentY = window.scrollY;
|
||||||
|
if (currentY > lastScrollY.current && currentY > 50) {
|
||||||
|
setShowUI(false);
|
||||||
|
} else if (currentY < lastScrollY.current) {
|
||||||
|
setShowUI(true);
|
||||||
|
}
|
||||||
|
lastScrollY.current = currentY;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-black relative">
|
<div className="min-h-screen bg-black relative">
|
||||||
@ -106,9 +130,23 @@ export function PageReader({
|
|||||||
) : (
|
) : (
|
||||||
<div />
|
<div />
|
||||||
)}
|
)}
|
||||||
<span className="text-white/50 text-xs">
|
<button
|
||||||
{pages.length} pages
|
onClick={() => setShowDrawer(true)}
|
||||||
</span>
|
className="flex items-center gap-1 text-white/80 hover:text-white text-sm transition-colors"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={2}
|
||||||
|
className="w-5 h-5"
|
||||||
|
>
|
||||||
|
<line x1="3" y1="6" x2="21" y2="6" />
|
||||||
|
<line x1="3" y1="12" x2="21" y2="12" />
|
||||||
|
<line x1="3" y1="18" x2="21" y2="18" />
|
||||||
|
</svg>
|
||||||
|
Ch. {chapterNumber}
|
||||||
|
</button>
|
||||||
{nextChapter ? (
|
{nextChapter ? (
|
||||||
<Link
|
<Link
|
||||||
href={`/manga/${mangaSlug}/${nextChapter}`}
|
href={`/manga/${mangaSlug}/${nextChapter}`}
|
||||||
@ -135,6 +173,49 @@ export function PageReader({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Chapter drawer overlay */}
|
||||||
|
{showDrawer && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 z-[60]"
|
||||||
|
onClick={() => setShowDrawer(false)}
|
||||||
|
>
|
||||||
|
{/* Backdrop */}
|
||||||
|
<div className="absolute inset-0 bg-black/60" />
|
||||||
|
|
||||||
|
{/* Bottom sheet */}
|
||||||
|
<div
|
||||||
|
className="absolute bottom-0 left-0 right-0 max-h-[60vh] bg-zinc-900 rounded-t-2xl overflow-hidden"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{/* Handle + header */}
|
||||||
|
<div className="sticky top-0 bg-zinc-900 z-10">
|
||||||
|
<div className="flex justify-center pt-2 pb-1">
|
||||||
|
<div className="w-10 h-1 rounded-full bg-white/20" />
|
||||||
|
</div>
|
||||||
|
<div className="px-4 pb-2 border-b border-white/10">
|
||||||
|
<span className="text-white text-sm font-medium">Chapters</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Chapter list */}
|
||||||
|
<div className="overflow-y-auto max-h-[calc(60vh-3rem)] pb-safe">
|
||||||
|
{chapters.map((ch) => (
|
||||||
|
<Link
|
||||||
|
key={ch.number}
|
||||||
|
href={`/manga/${mangaSlug}/${ch.number}`}
|
||||||
|
className={`block px-4 py-3 text-sm transition-colors ${
|
||||||
|
ch.number === chapterNumber
|
||||||
|
? "bg-white/10 text-white font-medium"
|
||||||
|
: "text-white/70 hover:bg-white/5 hover:text-white"
|
||||||
|
}`}
|
||||||
|
onClick={() => setShowDrawer(false)}
|
||||||
|
>
|
||||||
|
Ch. {ch.number} — {ch.title}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user