fix: restore reader direction and double-page navigation UI
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m6s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m6s
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback, useRef } from "react";
|
||||
@@ -218,6 +217,7 @@ export function PhotoswipeReader({ book, pages, onClose, nextBook }: BookReaderP
|
||||
shouldShowDoublePage={(page) => shouldShowDoublePage(page, pages.length)}
|
||||
imageBlobUrls={imageBlobUrls}
|
||||
getPageUrl={getPageUrl}
|
||||
isRTL={isRTL}
|
||||
/>
|
||||
|
||||
<NavigationBar
|
||||
|
||||
@@ -179,7 +179,7 @@ export const ControlButtons = ({
|
||||
iconClassName="h-8 w-8"
|
||||
className={cn(
|
||||
"absolute top-1/2 z-20 -translate-y-1/2 rounded-full border border-border/60 bg-background/55 shadow-[0_8px_24px_-16px_rgba(0,0,0,0.75)] backdrop-blur-xl transition-all duration-300 hover:bg-background/70",
|
||||
direction === "rtl" ? "right-4" : "left-4",
|
||||
"left-4",
|
||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
)}
|
||||
/>
|
||||
@@ -199,7 +199,7 @@ export const ControlButtons = ({
|
||||
iconClassName="h-8 w-8"
|
||||
className={cn(
|
||||
"absolute top-1/2 z-20 -translate-y-1/2 rounded-full border border-border/60 bg-background/55 shadow-[0_8px_24px_-16px_rgba(0,0,0,0.75)] backdrop-blur-xl transition-all duration-300 hover:bg-background/70",
|
||||
direction === "rtl" ? "left-4" : "right-4",
|
||||
"right-4",
|
||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useReadingDirection } from "../hooks/useReadingDirection";
|
||||
|
||||
interface PageDisplayProps {
|
||||
currentPage: number;
|
||||
@@ -9,6 +8,7 @@ interface PageDisplayProps {
|
||||
shouldShowDoublePage: (page: number) => boolean;
|
||||
imageBlobUrls: Record<number, string>;
|
||||
getPageUrl: (pageNum: number) => string;
|
||||
isRTL: boolean;
|
||||
}
|
||||
|
||||
export function PageDisplay({
|
||||
@@ -18,12 +18,12 @@ export function PageDisplay({
|
||||
shouldShowDoublePage,
|
||||
imageBlobUrls,
|
||||
getPageUrl,
|
||||
isRTL,
|
||||
}: PageDisplayProps) {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const [secondPageLoading, setSecondPageLoading] = useState(true);
|
||||
const [secondPageHasError, setSecondPageHasError] = useState(false);
|
||||
const { isRTL } = useReadingDirection();
|
||||
|
||||
const handleImageLoad = useCallback(() => {
|
||||
setIsLoading(false);
|
||||
@@ -53,7 +53,7 @@ export function PageDisplay({
|
||||
|
||||
return (
|
||||
<div className="relative flex w-full flex-1 items-center justify-center overflow-hidden">
|
||||
<div className="relative flex h-[calc(100vh-2.5rem)] w-full items-center justify-center gap-1 px-2 sm:px-4">
|
||||
<div className="relative flex h-[calc(100vh-2.5rem)] w-full items-center justify-center px-2 sm:px-4">
|
||||
{/* Page 1 */}
|
||||
<div
|
||||
className={cn(
|
||||
@@ -61,8 +61,8 @@ export function PageDisplay({
|
||||
isDoublePage && shouldShowDoublePage(currentPage) ? "w-1/2" : "w-full justify-center",
|
||||
isDoublePage &&
|
||||
shouldShowDoublePage(currentPage) && {
|
||||
"order-2 justify-center": isRTL,
|
||||
"order-1 justify-center": !isRTL,
|
||||
"order-2 justify-start": isRTL,
|
||||
"order-1 justify-end": !isRTL,
|
||||
}
|
||||
)}
|
||||
>
|
||||
@@ -79,10 +79,21 @@ export function PageDisplay({
|
||||
)}
|
||||
{hasError ? (
|
||||
<div className="flex flex-col items-center justify-center gap-3 text-muted-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="opacity-40">
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/>
|
||||
<circle cx="9" cy="9" r="2"/>
|
||||
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="opacity-40"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<circle cx="9" cy="9" r="2" />
|
||||
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
|
||||
</svg>
|
||||
<span className="text-sm opacity-60">Image non disponible</span>
|
||||
</div>
|
||||
@@ -94,7 +105,7 @@ export function PageDisplay({
|
||||
src={imageBlobUrls[currentPage] || getPageUrl(currentPage)}
|
||||
alt={`Page ${currentPage}`}
|
||||
className={cn(
|
||||
"max-h-full max-w-full cursor-pointer rounded-md object-contain transition-opacity",
|
||||
"max-h-full max-w-full cursor-pointer object-contain transition-opacity",
|
||||
isLoading ? "opacity-0" : "opacity-100"
|
||||
)}
|
||||
loading="eager"
|
||||
@@ -114,9 +125,9 @@ export function PageDisplay({
|
||||
{/* Page 2 (double page) */}
|
||||
{isDoublePage && shouldShowDoublePage(currentPage) && (
|
||||
<div
|
||||
className={cn("relative h-full w-1/2 flex items-center justify-center", {
|
||||
"order-1": isRTL,
|
||||
"order-2": !isRTL,
|
||||
className={cn("relative h-full w-1/2 flex items-center", {
|
||||
"order-1 justify-end": isRTL,
|
||||
"order-2 justify-start": !isRTL,
|
||||
})}
|
||||
>
|
||||
{secondPageLoading && (
|
||||
@@ -132,10 +143,21 @@ export function PageDisplay({
|
||||
)}
|
||||
{secondPageHasError ? (
|
||||
<div className="flex flex-col items-center justify-center gap-3 text-muted-foreground">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="opacity-40">
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/>
|
||||
<circle cx="9" cy="9" r="2"/>
|
||||
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="opacity-40"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<circle cx="9" cy="9" r="2" />
|
||||
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
|
||||
</svg>
|
||||
<span className="text-sm opacity-60">Image non disponible</span>
|
||||
</div>
|
||||
@@ -147,7 +169,7 @@ export function PageDisplay({
|
||||
src={imageBlobUrls[currentPage + 1] || getPageUrl(currentPage + 1)}
|
||||
alt={`Page ${currentPage + 1}`}
|
||||
className={cn(
|
||||
"max-h-full max-w-full cursor-pointer rounded-md object-contain transition-opacity",
|
||||
"max-h-full max-w-full cursor-pointer object-contain transition-opacity",
|
||||
secondPageLoading ? "opacity-0" : "opacity-100"
|
||||
)}
|
||||
loading="eager"
|
||||
|
||||
Reference in New Issue
Block a user