feat(bookreader): thumbnails on clic and UI
This commit is contained in:
@@ -351,37 +351,31 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
|||||||
setLoadedThumbnails((prev) => ({ ...prev, [pageNumber]: true }));
|
setLoadedThumbnails((prev) => ({ ...prev, [pageNumber]: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fonction pour scroller jusqu'à la miniature active
|
// Effet pour scroller jusqu'à la miniature active
|
||||||
const scrollToActiveThumbnail = useCallback(() => {
|
const scrollToActiveThumbnail = useCallback(() => {
|
||||||
const container = document.getElementById("thumbnails-container");
|
const thumbnail = document.getElementById(`thumbnail-${currentPage}`);
|
||||||
const activeThumbnail = document.getElementById(`thumbnail-${currentPage}`);
|
if (thumbnail) {
|
||||||
if (container && activeThumbnail) {
|
thumbnail.scrollIntoView({
|
||||||
const containerWidth = container.clientWidth;
|
behavior: "smooth",
|
||||||
const thumbnailLeft = activeThumbnail.offsetLeft;
|
block: "nearest",
|
||||||
const thumbnailWidth = activeThumbnail.clientWidth;
|
inline: "center",
|
||||||
|
});
|
||||||
// Centrer la miniature dans le conteneur
|
|
||||||
container.scrollLeft = thumbnailLeft - containerWidth / 2 + thumbnailWidth / 2;
|
|
||||||
}
|
}
|
||||||
}, [currentPage]);
|
}, [currentPage]);
|
||||||
|
|
||||||
// Effet pour scroller jusqu'à la miniature active au chargement et au changement de page
|
// Effet pour centrer la miniature active quand les contrôles deviennent visibles
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showNavigation) {
|
if (showControls) {
|
||||||
scrollToActiveThumbnail();
|
scrollToActiveThumbnail();
|
||||||
}
|
}
|
||||||
}, [currentPage, showNavigation, scrollToActiveThumbnail]);
|
}, [showControls, scrollToActiveThumbnail]);
|
||||||
|
|
||||||
// Effet pour scroller jusqu'à la miniature active quand la navigation devient visible
|
// Effet pour centrer la miniature active au changement de page
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showNavigation) {
|
if (showControls) {
|
||||||
// Petit délai pour laisser le temps à la barre de s'afficher
|
scrollToActiveThumbnail();
|
||||||
const timer = setTimeout(() => {
|
|
||||||
scrollToActiveThumbnail();
|
|
||||||
}, 100);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}
|
}
|
||||||
}, [showNavigation, scrollToActiveThumbnail]);
|
}, [currentPage, showControls, scrollToActiveThumbnail]);
|
||||||
|
|
||||||
// Fonction pour calculer les miniatures à afficher autour de la page courante
|
// Fonction pour calculer les miniatures à afficher autour de la page courante
|
||||||
const updateVisibleThumbnails = useCallback(() => {
|
const updateVisibleThumbnails = useCallback(() => {
|
||||||
@@ -504,20 +498,6 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
|||||||
<SplitSquareVertical className="h-6 w-6" />
|
<SplitSquareVertical className="h-6 w-6" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setShowNavigation(!showNavigation);
|
|
||||||
}}
|
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
|
||||||
aria-label={showNavigation ? "Masquer la navigation" : "Afficher la navigation"}
|
|
||||||
>
|
|
||||||
<ChevronUp
|
|
||||||
className={`h-6 w-6 transition-transform duration-200 ${
|
|
||||||
showNavigation ? "rotate-180" : ""
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
{/* Bouton précédent */}
|
{/* Bouton précédent */}
|
||||||
{currentPage > 1 && (
|
{currentPage > 1 && (
|
||||||
@@ -630,31 +610,17 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
|||||||
<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",
|
||||||
showNavigation ? "h-48 opacity-100" : "h-0 opacity-0",
|
showControls ? "h-64 opacity-100" : "h-0 opacity-0"
|
||||||
showControls ? "" : "pointer-events-none"
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{showNavigation && (
|
{showControls && (
|
||||||
<>
|
<>
|
||||||
<div className="absolute inset-y-0 left-4 flex items-center z-40">
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const container = document.getElementById("thumbnails-container");
|
|
||||||
if (container) {
|
|
||||||
container.scrollLeft -= container.clientWidth;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
|
||||||
aria-label="Pages précédentes"
|
|
||||||
>
|
|
||||||
<ChevronLeft className="h-6 w-6" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="thumbnails-container"
|
id="thumbnails-container"
|
||||||
className="h-full mx-16 overflow-x-auto flex items-center gap-2 px-4 scroll-smooth"
|
className="h-full overflow-x-auto flex items-center gap-2 px-4 scroll-smooth snap-x snap-mandatory"
|
||||||
>
|
>
|
||||||
|
{/* Ajouter un élément vide au début pour le centrage */}
|
||||||
|
<div className="w-[calc(50vw-18rem)] flex-shrink-0" />
|
||||||
{pages.map((_, index) => {
|
{pages.map((_, index) => {
|
||||||
const pageNumber = index + 1;
|
const pageNumber = index + 1;
|
||||||
const isVisible = visibleThumbnails.includes(pageNumber);
|
const isVisible = visibleThumbnails.includes(pageNumber);
|
||||||
@@ -674,10 +640,10 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
|||||||
setImageError(false);
|
setImageError(false);
|
||||||
syncReadProgress(pageNumber);
|
syncReadProgress(pageNumber);
|
||||||
}}
|
}}
|
||||||
className={`relative h-40 w-28 flex-shrink-0 rounded-md overflow-hidden transition-all cursor-pointer ${
|
className={`relative h-56 w-40 flex-shrink-0 rounded-md overflow-hidden transition-all cursor-pointer snap-center ${
|
||||||
currentPage === pageNumber
|
currentPage === pageNumber
|
||||||
? "ring-2 ring-primary scale-110 z-10"
|
? "ring-2 ring-primary scale-110 z-10"
|
||||||
: "opacity-60 hover:opacity-100 hover:scale-105"
|
: "opacity-80 hover:opacity-100 hover:scale-105"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isVisible && (
|
{isVisible && (
|
||||||
@@ -704,21 +670,8 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
|||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
{/* Ajouter un élément vide à la fin pour le centrage */}
|
||||||
|
<div className="w-[calc(50vw-18rem)] flex-shrink-0" />
|
||||||
<div className="absolute inset-y-0 right-4 flex items-center">
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const container = document.getElementById("thumbnails-container");
|
|
||||||
if (container) {
|
|
||||||
container.scrollLeft += container.clientWidth;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
|
|
||||||
aria-label="Pages suivantes"
|
|
||||||
>
|
|
||||||
<ChevronRight className="h-6 w-6" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Indicateur de page */}
|
{/* Indicateur de page */}
|
||||||
|
|||||||
Reference in New Issue
Block a user