feat: add thumbnail display toggle functionality in BookReader component

This commit is contained in:
Julien Froidefond
2025-10-16 13:13:05 +02:00
parent 0a126540fd
commit f6c702d787
4 changed files with 37 additions and 9 deletions

View File

@@ -18,6 +18,7 @@ import { useTranslate } from "@/hooks/useTranslate";
export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps) { export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps) {
const [isDoublePage, setIsDoublePage] = useState(false); const [isDoublePage, setIsDoublePage] = useState(false);
const [showControls, setShowControls] = useState(false); const [showControls, setShowControls] = useState(false);
const [showThumbnails, setShowThumbnails] = useState(false);
const readerRef = useRef<HTMLDivElement>(null); const readerRef = useRef<HTMLDivElement>(null);
const isLandscape = useOrientation(); const isLandscape = useOrientation();
const { direction, toggleDirection, isRTL } = useReadingDirection(); const { direction, toggleDirection, isRTL } = useReadingDirection();
@@ -126,6 +127,8 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
onToggleFullscreen={() => toggleFullscreen(readerRef.current)} onToggleFullscreen={() => toggleFullscreen(readerRef.current)}
direction={direction} direction={direction}
onToggleDirection={toggleDirection} onToggleDirection={toggleDirection}
showThumbnails={showThumbnails}
onToggleThumbnails={() => setShowThumbnails(!showThumbnails)}
/> />
<ReaderContent <ReaderContent
@@ -148,6 +151,7 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
pages={pages} pages={pages}
onPageChange={navigateToPage} onPageChange={navigateToPage}
showControls={showControls} showControls={showControls}
showThumbnails={showThumbnails}
book={book} book={book}
/> />
</div> </div>

View File

@@ -9,6 +9,7 @@ import {
Minimize2, Minimize2,
MoveRight, MoveRight,
MoveLeft, MoveLeft,
Images,
} from "lucide-react"; } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { PageInput } from "./PageInput"; import { PageInput } from "./PageInput";
@@ -29,6 +30,8 @@ export const ControlButtons = ({
direction, direction,
onToggleDirection, onToggleDirection,
onPageChange, onPageChange,
showThumbnails,
onToggleThumbnails,
}: ControlButtonsProps) => { }: ControlButtonsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -95,6 +98,21 @@ export const ControlButtons = ({
> >
{isFullscreen ? <Minimize2 className="h-6 w-6" /> : <Maximize2 className="h-6 w-6" />} {isFullscreen ? <Minimize2 className="h-6 w-6" /> : <Maximize2 className="h-6 w-6" />}
</button> </button>
<button
onClick={(e) => {
e.stopPropagation();
onToggleThumbnails();
}}
className={cn(
"p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors",
showThumbnails && "ring-2 ring-primary"
)}
aria-label={t(
showThumbnails ? "reader.controls.thumbnails.hide" : "reader.controls.thumbnails.show"
)}
>
<Images className="h-6 w-6" />
</button>
<div className="p-2 rounded-full bg-background/50" onClick={(e) => e.stopPropagation()}> <div className="p-2 rounded-full bg-background/50" onClick={(e) => e.stopPropagation()}>
<PageInput <PageInput
currentPage={currentPage} currentPage={currentPage}

View File

@@ -9,6 +9,7 @@ export const NavigationBar = ({
pages, pages,
onPageChange, onPageChange,
showControls, showControls,
showThumbnails,
book, book,
}: NavigationBarProps) => { }: NavigationBarProps) => {
const [isTooSmall, setIsTooSmall] = useState(false); const [isTooSmall, setIsTooSmall] = useState(false);
@@ -31,21 +32,21 @@ export const NavigationBar = ({
return () => window.removeEventListener("resize", checkHeight); return () => window.removeEventListener("resize", checkHeight);
}, []); }, []);
// Scroll à l'ouverture des contrôles et au changement de page // Scroll à l'ouverture des vignettes et au changement de page
useEffect(() => { useEffect(() => {
if (showControls && !isTooSmall) { if (showThumbnails && !isTooSmall) {
requestAnimationFrame(() => { requestAnimationFrame(() => {
const thumbnail = document.getElementById(`thumbnail-${currentPage}`); const thumbnail = document.getElementById(`thumbnail-${currentPage}`);
if (thumbnail) { if (thumbnail) {
thumbnail.scrollIntoView({ thumbnail.scrollIntoView({
behavior: showControls ? "instant" : "smooth", behavior: showThumbnails ? "instant" : "smooth",
block: "nearest", block: "nearest",
inline: "center", inline: "center",
}); });
} }
}); });
} }
}, [showControls, currentPage, isTooSmall]); }, [showThumbnails, currentPage, isTooSmall]);
if (isTooSmall) { if (isTooSmall) {
return null; return null;
@@ -55,10 +56,10 @@ export const NavigationBar = ({
<div <div
className={cn( className={cn(
"absolute bottom-0 left-0 right-0 bg-background/50 backdrop-blur-sm border-t border-border/40 transition-all duration-300 ease-in-out z-30", "absolute bottom-0 left-0 right-0 bg-background/50 backdrop-blur-sm border-t border-border/40 transition-all duration-300 ease-in-out z-30",
showControls ? "h-52 opacity-100" : "h-0 opacity-0" showThumbnails ? "h-52 opacity-100" : "h-0 opacity-0"
)} )}
> >
{showControls && ( {showThumbnails && (
<> <>
<div <div
id="thumbnails-container" id="thumbnails-container"
@@ -88,9 +89,11 @@ export const NavigationBar = ({
<div className="w-[calc(50vw-18rem)] flex-shrink-0" /> <div className="w-[calc(50vw-18rem)] flex-shrink-0" />
</div> </div>
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full px-4 py-2 rounded-full bg-background/50 text-sm"> {showControls && (
Page {currentPage} / {pages.length} <div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full px-4 py-2 rounded-full bg-background/50 text-sm">
</div> Page {currentPage} / {pages.length}
</div>
)}
</> </>
)} )}
</div> </div>

View File

@@ -31,6 +31,7 @@ export interface NavigationBarProps {
pages: number[]; pages: number[];
onPageChange: (page: number) => void; onPageChange: (page: number) => void;
showControls: boolean; showControls: boolean;
showThumbnails: boolean;
book: KomgaBook; book: KomgaBook;
} }
@@ -49,6 +50,8 @@ export interface ControlButtonsProps {
onToggleFullscreen: () => void; onToggleFullscreen: () => void;
direction: "ltr" | "rtl"; direction: "ltr" | "rtl";
onToggleDirection: () => void; onToggleDirection: () => void;
showThumbnails: boolean;
onToggleThumbnails: () => void;
} }
export interface UsePageNavigationProps { export interface UsePageNavigationProps {