Compare commits
7 Commits
e6eab32473
...
11da2335cd
| Author | SHA1 | Date | |
|---|---|---|---|
| 11da2335cd | |||
| feceb61e30 | |||
| 701a02b55c | |||
| b2664cce08 | |||
| ff44a781c8 | |||
| d535f9f28e | |||
| 2174579cc1 |
@@ -51,7 +51,7 @@ export function Header({
|
||||
<div className="mr-2 flex items-center md:mr-4">
|
||||
<a className="mr-2 flex items-center md:mr-6" href="/">
|
||||
<span className="inline-flex flex-col leading-none">
|
||||
<span className="bg-gradient-to-r from-primary via-cyan-500 to-fuchsia-500 bg-clip-text text-sm font-bold tracking-[0.06em] text-transparent sm:text-lg sm:tracking-[0.08em]">
|
||||
<span className="bg-gradient-to-r from-primary via-cyan-500 to-fuchsia-500 bg-clip-text text-base font-bold tracking-[0.06em] text-transparent sm:text-lg sm:tracking-[0.08em]">
|
||||
StripStream
|
||||
</span>
|
||||
<span className="mt-1 hidden text-[10px] font-medium uppercase tracking-[0.22em] text-foreground/70 sm:inline">
|
||||
|
||||
@@ -76,13 +76,30 @@ export function PhotoswipeReader({ book, pages, onClose, nextBook }: BookReaderP
|
||||
onPreviousPage: handlePreviousPage,
|
||||
onNextPage: handleNextPage,
|
||||
pswpRef,
|
||||
isRTL,
|
||||
});
|
||||
|
||||
// Activer le zoom dans le reader en enlevant la classe no-pinch-zoom
|
||||
// et reset le zoom lors des changements d'orientation (iOS applique un zoom automatique)
|
||||
useEffect(() => {
|
||||
document.body.classList.remove("no-pinch-zoom");
|
||||
|
||||
const handleOrientationChange = () => {
|
||||
const viewport = document.querySelector('meta[name="viewport"]');
|
||||
if (viewport) {
|
||||
const original = viewport.getAttribute("content") || "";
|
||||
viewport.setAttribute("content", original + ", maximum-scale=1");
|
||||
// Restaurer après que iOS ait appliqué le nouveau layout
|
||||
requestAnimationFrame(() => {
|
||||
viewport.setAttribute("content", original);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("orientationchange", handleOrientationChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("orientationchange", handleOrientationChange);
|
||||
document.body.classList.add("no-pinch-zoom");
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -173,7 +173,7 @@ export const ControlButtons = ({
|
||||
icon={ChevronLeft}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onPreviousPage();
|
||||
direction === "rtl" ? onNextPage() : onPreviousPage();
|
||||
}}
|
||||
tooltip={t("reader.controls.previousPage")}
|
||||
iconClassName="h-8 w-8"
|
||||
@@ -193,7 +193,7 @@ export const ControlButtons = ({
|
||||
icon={ChevronRight}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onNextPage();
|
||||
direction === "rtl" ? onPreviousPage() : onNextPage();
|
||||
}}
|
||||
tooltip={t("reader.controls.nextPage")}
|
||||
iconClassName="h-8 w-8"
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
import { useCallback, useRef, useEffect } from "react";
|
||||
import { useReadingDirection } from "./useReadingDirection";
|
||||
|
||||
interface UseTouchNavigationProps {
|
||||
onPreviousPage: () => void;
|
||||
onNextPage: () => void;
|
||||
pswpRef: React.MutableRefObject<unknown>;
|
||||
isRTL: boolean;
|
||||
}
|
||||
|
||||
export function useTouchNavigation({
|
||||
onPreviousPage,
|
||||
onNextPage,
|
||||
pswpRef,
|
||||
isRTL,
|
||||
}: UseTouchNavigationProps) {
|
||||
const { isRTL } = useReadingDirection();
|
||||
const touchStartXRef = useRef<number | null>(null);
|
||||
const touchStartYRef = useRef<number | null>(null);
|
||||
const isPinchingRef = useRef(false);
|
||||
|
||||
// Helper pour vérifier si la page est zoomée (zoom natif du navigateur)
|
||||
const isZoomed = useCallback(() => {
|
||||
// Utiliser visualViewport.scale pour détecter le zoom natif
|
||||
// Si scale > 1, la page est zoomée
|
||||
if (window.visualViewport) {
|
||||
return window.visualViewport.scale > 1;
|
||||
return window.visualViewport.scale > 1.05;
|
||||
}
|
||||
// Fallback pour les navigateurs qui ne supportent pas visualViewport
|
||||
// Comparer la taille de la fenêtre avec la taille réelle
|
||||
return window.innerWidth !== window.screen.width;
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -34,11 +34,14 @@ export class StripstreamAdapter {
|
||||
volume: book.volume ?? null,
|
||||
pageCount: book.page_count ?? 0,
|
||||
thumbnailUrl: `/api/stripstream/images/books/${book.id}/thumbnail`,
|
||||
readProgress: {
|
||||
page: book.reading_current_page ?? null,
|
||||
completed: book.reading_status === "read",
|
||||
lastReadAt: book.reading_last_read_at ?? null,
|
||||
},
|
||||
readProgress:
|
||||
book.reading_status === "unread" && !book.reading_current_page
|
||||
? null
|
||||
: {
|
||||
page: book.reading_current_page ?? null,
|
||||
completed: book.reading_status === "read",
|
||||
lastReadAt: book.reading_last_read_at ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,11 +55,14 @@ export class StripstreamAdapter {
|
||||
volume: book.volume ?? null,
|
||||
pageCount: book.page_count ?? 0,
|
||||
thumbnailUrl: `/api/stripstream/images/books/${book.id}/thumbnail`,
|
||||
readProgress: {
|
||||
page: book.reading_current_page ?? null,
|
||||
completed: book.reading_status === "read",
|
||||
lastReadAt: book.reading_last_read_at ?? null,
|
||||
},
|
||||
readProgress:
|
||||
book.reading_status === "unread" && !book.reading_current_page
|
||||
? null
|
||||
: {
|
||||
page: book.reading_current_page ?? null,
|
||||
completed: book.reading_status === "read",
|
||||
lastReadAt: book.reading_last_read_at ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -222,11 +222,11 @@ export class StripstreamProvider implements IMediaProvider {
|
||||
|
||||
async getHomeData(): Promise<HomeData> {
|
||||
const homeOpts = { revalidate: CACHE_TTL_MED, tags: [HOME_CACHE_TAG] };
|
||||
const [ongoingBooksResult, ongoingSeriesResult, booksPage, libraries] = await Promise.allSettled([
|
||||
const [ongoingBooksResult, ongoingSeriesResult, booksPage, latestSeriesResult] = await Promise.allSettled([
|
||||
this.client.fetch<StripstreamBookItem[]>("books/ongoing", { limit: "20" }, homeOpts),
|
||||
this.client.fetch<StripstreamSeriesItem[]>("series/ongoing", { limit: "10" }, homeOpts),
|
||||
this.client.fetch<StripstreamBooksPage>("books", { limit: "10" }, homeOpts),
|
||||
this.client.fetch<StripstreamLibraryResponse[]>("libraries", undefined, { revalidate: CACHE_TTL_LONG, tags: [HOME_CACHE_TAG] }),
|
||||
this.client.fetch<StripstreamBooksPage>("books", { sort: "latest", limit: "10" }, homeOpts),
|
||||
this.client.fetch<StripstreamSeriesPage>("series", { sort: "latest", limit: "10" }, homeOpts),
|
||||
]);
|
||||
|
||||
// /books/ongoing returns both currently reading and next unread per series
|
||||
@@ -242,23 +242,9 @@ export class StripstreamProvider implements IMediaProvider {
|
||||
? booksPage.value.items.map(StripstreamAdapter.toNormalizedBook)
|
||||
: [];
|
||||
|
||||
let latestSeries: NormalizedSeries[] = [];
|
||||
if (libraries.status === "fulfilled" && libraries.value.length > 0) {
|
||||
const allSeriesResults = await Promise.allSettled(
|
||||
libraries.value.map((lib) =>
|
||||
this.client.fetch<StripstreamSeriesPage>(
|
||||
`libraries/${lib.id}/series`,
|
||||
{ limit: "10" },
|
||||
homeOpts
|
||||
)
|
||||
)
|
||||
);
|
||||
latestSeries = allSeriesResults
|
||||
.filter((r): r is PromiseFulfilledResult<StripstreamSeriesPage> => r.status === "fulfilled")
|
||||
.flatMap((r) => r.value.items)
|
||||
.map(StripstreamAdapter.toNormalizedSeries)
|
||||
.slice(0, 10);
|
||||
}
|
||||
const latestSeries = latestSeriesResult.status === "fulfilled"
|
||||
? latestSeriesResult.value.items.map(StripstreamAdapter.toNormalizedSeries)
|
||||
: [];
|
||||
|
||||
return {
|
||||
ongoing: ongoingSeries,
|
||||
|
||||
@@ -118,11 +118,14 @@ body.no-pinch-zoom * {
|
||||
font-family: var(--font-ui);
|
||||
}
|
||||
|
||||
/* Empêche le zoom automatique iOS sur les inputs */
|
||||
}
|
||||
|
||||
/* Empêche le zoom automatique iOS sur les inputs (hors @layer pour surcharger text-sm) */
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
input,
|
||||
textarea,
|
||||
select {
|
||||
font-size: 16px;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user