feat: fullscreen mode
This commit is contained in:
@@ -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} />
|
||||||
|
|||||||
@@ -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 */}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user