fix: restore reader direction and double-page navigation UI
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m6s

This commit is contained in:
2026-03-04 06:49:40 +01:00
parent 6a06e5a7d3
commit 23fa884af7
3 changed files with 43 additions and 21 deletions

View File

@@ -1,4 +1,3 @@
"use client"; "use client";
import { useEffect, useState, useCallback, useRef } from "react"; 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)} shouldShowDoublePage={(page) => shouldShowDoublePage(page, pages.length)}
imageBlobUrls={imageBlobUrls} imageBlobUrls={imageBlobUrls}
getPageUrl={getPageUrl} getPageUrl={getPageUrl}
isRTL={isRTL}
/> />
<NavigationBar <NavigationBar

View File

@@ -179,7 +179,7 @@ export const ControlButtons = ({
iconClassName="h-8 w-8" iconClassName="h-8 w-8"
className={cn( 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", "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" showControls ? "opacity-100" : "opacity-0 pointer-events-none"
)} )}
/> />
@@ -199,7 +199,7 @@ export const ControlButtons = ({
iconClassName="h-8 w-8" iconClassName="h-8 w-8"
className={cn( 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", "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" showControls ? "opacity-100" : "opacity-0 pointer-events-none"
)} )}
/> />

View File

@@ -1,6 +1,5 @@
import { useState, useCallback, useEffect } from "react"; import { useState, useCallback, useEffect } from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { useReadingDirection } from "../hooks/useReadingDirection";
interface PageDisplayProps { interface PageDisplayProps {
currentPage: number; currentPage: number;
@@ -9,6 +8,7 @@ interface PageDisplayProps {
shouldShowDoublePage: (page: number) => boolean; shouldShowDoublePage: (page: number) => boolean;
imageBlobUrls: Record<number, string>; imageBlobUrls: Record<number, string>;
getPageUrl: (pageNum: number) => string; getPageUrl: (pageNum: number) => string;
isRTL: boolean;
} }
export function PageDisplay({ export function PageDisplay({
@@ -18,12 +18,12 @@ export function PageDisplay({
shouldShowDoublePage, shouldShowDoublePage,
imageBlobUrls, imageBlobUrls,
getPageUrl, getPageUrl,
isRTL,
}: PageDisplayProps) { }: PageDisplayProps) {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false); const [hasError, setHasError] = useState(false);
const [secondPageLoading, setSecondPageLoading] = useState(true); const [secondPageLoading, setSecondPageLoading] = useState(true);
const [secondPageHasError, setSecondPageHasError] = useState(false); const [secondPageHasError, setSecondPageHasError] = useState(false);
const { isRTL } = useReadingDirection();
const handleImageLoad = useCallback(() => { const handleImageLoad = useCallback(() => {
setIsLoading(false); setIsLoading(false);
@@ -53,7 +53,7 @@ export function PageDisplay({
return ( return (
<div className="relative flex w-full flex-1 items-center justify-center overflow-hidden"> <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 */} {/* Page 1 */}
<div <div
className={cn( className={cn(
@@ -61,8 +61,8 @@ export function PageDisplay({
isDoublePage && shouldShowDoublePage(currentPage) ? "w-1/2" : "w-full justify-center", isDoublePage && shouldShowDoublePage(currentPage) ? "w-1/2" : "w-full justify-center",
isDoublePage && isDoublePage &&
shouldShowDoublePage(currentPage) && { shouldShowDoublePage(currentPage) && {
"order-2 justify-center": isRTL, "order-2 justify-start": isRTL,
"order-1 justify-center": !isRTL, "order-1 justify-end": !isRTL,
} }
)} )}
> >
@@ -79,7 +79,18 @@ export function PageDisplay({
)} )}
{hasError ? ( {hasError ? (
<div className="flex flex-col items-center justify-center gap-3 text-muted-foreground"> <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"> <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" /> <rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
<circle cx="9" cy="9" r="2" /> <circle cx="9" cy="9" r="2" />
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" /> <path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
@@ -94,7 +105,7 @@ export function PageDisplay({
src={imageBlobUrls[currentPage] || getPageUrl(currentPage)} src={imageBlobUrls[currentPage] || getPageUrl(currentPage)}
alt={`Page ${currentPage}`} alt={`Page ${currentPage}`}
className={cn( 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" isLoading ? "opacity-0" : "opacity-100"
)} )}
loading="eager" loading="eager"
@@ -114,9 +125,9 @@ export function PageDisplay({
{/* Page 2 (double page) */} {/* Page 2 (double page) */}
{isDoublePage && shouldShowDoublePage(currentPage) && ( {isDoublePage && shouldShowDoublePage(currentPage) && (
<div <div
className={cn("relative h-full w-1/2 flex items-center justify-center", { className={cn("relative h-full w-1/2 flex items-center", {
"order-1": isRTL, "order-1 justify-end": isRTL,
"order-2": !isRTL, "order-2 justify-start": !isRTL,
})} })}
> >
{secondPageLoading && ( {secondPageLoading && (
@@ -132,7 +143,18 @@ export function PageDisplay({
)} )}
{secondPageHasError ? ( {secondPageHasError ? (
<div className="flex flex-col items-center justify-center gap-3 text-muted-foreground"> <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"> <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" /> <rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
<circle cx="9" cy="9" r="2" /> <circle cx="9" cy="9" r="2" />
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" /> <path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
@@ -147,7 +169,7 @@ export function PageDisplay({
src={imageBlobUrls[currentPage + 1] || getPageUrl(currentPage + 1)} src={imageBlobUrls[currentPage + 1] || getPageUrl(currentPage + 1)}
alt={`Page ${currentPage + 1}`} alt={`Page ${currentPage + 1}`}
className={cn( 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" secondPageLoading ? "opacity-0" : "opacity-100"
)} )}
loading="eager" loading="eager"