feat: fullscreen mode

This commit is contained in:
Julien Froidefond
2025-02-16 22:56:55 +01:00
parent a4b52a1ee8
commit 86529d4994
3 changed files with 73 additions and 6 deletions

View File

@@ -4,7 +4,7 @@ import { BookReaderProps } from "./types";
import { useOrientation } from "./hooks/useOrientation"; import { useOrientation } from "./hooks/useOrientation";
import { usePageNavigation } from "./hooks/usePageNavigation"; import { usePageNavigation } from "./hooks/usePageNavigation";
import { usePageCache } from "./hooks/usePageCache"; import { usePageCache } from "./hooks/usePageCache";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback, useRef } from "react";
import { NavigationBar } from "./components/NavigationBar"; import { NavigationBar } from "./components/NavigationBar";
import { ControlButtons } from "./components/ControlButtons"; import { ControlButtons } from "./components/ControlButtons";
import { ImageLoader } from "@/components/ui/image-loader"; import { ImageLoader } from "@/components/ui/image-loader";
@@ -13,6 +13,8 @@ import { cn } from "@/lib/utils";
export function BookReader({ book, pages, onClose }: BookReaderProps) { export function BookReader({ book, pages, onClose }: BookReaderProps) {
const [isDoublePage, setIsDoublePage] = useState(false); const [isDoublePage, setIsDoublePage] = useState(false);
const [showControls, setShowControls] = useState(false); const [showControls, setShowControls] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
const readerRef = useRef<HTMLDivElement>(null);
const isLandscape = useOrientation(); const isLandscape = useOrientation();
const { const {
@@ -138,6 +140,34 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
setIsDoublePage(isLandscape); setIsDoublePage(isLandscape);
}, [isLandscape]); }, [isLandscape]);
// Effet pour gérer le fullscreen
useEffect(() => {
const enterFullscreen = async () => {
try {
if (readerRef.current && !isFullscreen) {
await readerRef.current.requestFullscreen();
setIsFullscreen(true);
}
} catch (error) {
console.error("Erreur lors du passage en plein écran:", error);
}
};
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement);
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
enterFullscreen();
return () => {
document.removeEventListener("fullscreenchange", handleFullscreenChange);
if (document.fullscreenElement) {
document.exitFullscreen().catch(console.error);
}
};
}, []);
const handleThumbnailLoad = useCallback( const handleThumbnailLoad = useCallback(
(pageNumber: number) => { (pageNumber: number) => {
if (pageNumber === currentPage) { if (pageNumber === currentPage) {
@@ -150,7 +180,10 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
); );
return ( return (
<div className="fixed inset-0 bg-background/95 backdrop-blur-sm z-50 overflow-hidden touch-none"> <div
ref={readerRef}
className="fixed inset-0 bg-background/95 backdrop-blur-sm z-50 overflow-hidden touch-none"
>
<div <div
className="relative h-full flex flex-col items-center justify-center" className="relative h-full flex flex-col items-center justify-center"
onClick={() => setShowControls(!showControls)} onClick={() => setShowControls(!showControls)}
@@ -167,6 +200,18 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
totalPages={pages.length} totalPages={pages.length}
isDoublePage={isDoublePage} isDoublePage={isDoublePage}
onToggleDoublePage={() => setIsDoublePage(!isDoublePage)} onToggleDoublePage={() => setIsDoublePage(!isDoublePage)}
isFullscreen={isFullscreen}
onToggleFullscreen={async () => {
try {
if (isFullscreen) {
await document.exitFullscreen();
} else if (readerRef.current) {
await readerRef.current.requestFullscreen();
}
} catch (error) {
console.error("Erreur lors du changement de mode plein écran:", error);
}
}}
/> />
{/* Pages */} {/* Pages */}
@@ -175,8 +220,8 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
{/* Page courante */} {/* Page courante */}
<div <div
className={cn( className={cn(
"relative h-full flex items-center justify-end", "relative h-full flex items-center",
isDoublePage ? "w-1/2" : "w-full" isDoublePage ? "w-1/2 justify-end" : "w-full justify-center"
)} )}
> >
<ImageLoader isLoading={isLoading} /> <ImageLoader isLoading={isLoading} />

View File

@@ -1,6 +1,14 @@
import { ControlButtonsProps } from "../types"; import { ControlButtonsProps } from "../types";
import {
ChevronLeft,
ChevronRight,
X,
SplitSquareVertical,
LayoutTemplate,
Maximize2,
Minimize2,
} from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { ChevronLeft, ChevronRight, X, SplitSquareVertical, LayoutTemplate } from "lucide-react";
export const ControlButtons = ({ export const ControlButtons = ({
showControls, showControls,
@@ -12,13 +20,15 @@ export const ControlButtons = ({
totalPages, totalPages,
isDoublePage, isDoublePage,
onToggleDoublePage, onToggleDoublePage,
isFullscreen,
onToggleFullscreen,
}: ControlButtonsProps) => { }: ControlButtonsProps) => {
return ( return (
<> <>
{/* Bouton mode double page */} {/* Bouton mode double page */}
<div <div
className={cn( className={cn(
"absolute top-4 left-4 z-30 transition-all duration-300", "absolute top-4 left-4 z-30 flex items-center gap-2 transition-all duration-300",
showControls ? "opacity-100" : "opacity-0 pointer-events-none" showControls ? "opacity-100" : "opacity-0 pointer-events-none"
)} )}
> >
@@ -38,6 +48,16 @@ export const ControlButtons = ({
<SplitSquareVertical className="h-6 w-6" /> <SplitSquareVertical className="h-6 w-6" />
)} )}
</button> </button>
<button
onClick={(e) => {
e.stopPropagation();
onToggleFullscreen();
}}
className="p-2 rounded-full bg-background/50 hover:bg-background/80 transition-colors"
aria-label={isFullscreen ? "Quitter le plein écran" : "Plein écran"}
>
{isFullscreen ? <Minimize2 className="h-6 w-6" /> : <Maximize2 className="h-6 w-6" />}
</button>
</div> </div>
{/* Bouton fermer */} {/* Bouton fermer */}

View File

@@ -43,6 +43,8 @@ export interface ControlButtonsProps {
totalPages: number; totalPages: number;
isDoublePage: boolean; isDoublePage: boolean;
onToggleDoublePage: () => void; onToggleDoublePage: () => void;
isFullscreen: boolean;
onToggleFullscreen: () => void;
} }
export interface UsePageNavigationProps { export interface UsePageNavigationProps {