From ebca13a3dce6bf797d8ffb3d6514ef4ac310e096 Mon Sep 17 00:00:00 2001 From: Gslmao Date: Sat, 26 Sep 2026 16:03:25 +0530 Subject: [PATCH 1/3] feat: press f to toggle fullscreen --- src/components/newPdfViewer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/newPdfViewer.tsx b/src/components/newPdfViewer.tsx index 6556ec6..7fa587b 100644 --- a/src/components/newPdfViewer.tsx +++ b/src/components/newPdfViewer.tsx @@ -202,7 +202,7 @@ @@ -545,6 +545,8 @@ if (e.key === "r" || e.key === "R") { toggleReadingMode(); + } else if (e.key === 'f' || e.key === 'F') { + toggleFullscreen(); } else if (e.key === "Escape" && isReadingMode) { setIsReadingMode(false); onReadingModeChange?.(false); From a208753af8b890803ac18c173516774d0f815397 Mon Sep 17 00:00:00 2001 From: Gslmao Date: Sat, 26 Sep 2026 16:04:52 +0530 Subject: [PATCH 2/3] fix: disable mode toggle on key press when modifiers are pressed --- src/components/newPdfViewer.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/newPdfViewer.tsx b/src/components/newPdfViewer.tsx index 7fa587b..0b821a9 100644 --- a/src/components/newPdfViewer.tsx +++ b/src/components/newPdfViewer.tsx @@ -542,7 +542,8 @@ const handleKeydown = (e: KeyboardEvent) => { const target = e.target as HTMLElement | null; if (target && ["INPUT", "TEXTAREA"].includes(target.tagName)) return; - + if (e.ctrlKey || e.metaKey || e.altKey) return; + if (e.key === "r" || e.key === "R") { toggleReadingMode(); } else if (e.key === 'f' || e.key === 'F') { From 27569f745465e775b72726c4099fa886c2f935a1 Mon Sep 17 00:00:00 2001 From: Gslmao Date: Sat, 26 Sep 2026 16:06:09 +0530 Subject: [PATCH 3/3] chore: remove extra indentation --- src/components/newPdfViewer.tsx | 1350 +++++++++++++++---------------- 1 file changed, 675 insertions(+), 675 deletions(-) diff --git a/src/components/newPdfViewer.tsx b/src/components/newPdfViewer.tsx index ee65029..ad9fde7 100644 --- a/src/components/newPdfViewer.tsx +++ b/src/components/newPdfViewer.tsx @@ -1,652 +1,707 @@ - "use client" - import { createPluginRegistration } from '@embedpdf/core'; - import { EmbedPDF } from '@embedpdf/core/react'; - import { usePdfiumEngine } from '@embedpdf/engines/react'; - import { Viewport, ViewportPluginPackage } from '@embedpdf/plugin-viewport/react'; - import { useScroll, useScrollCapability, Scroller, ScrollPluginPackage } from '@embedpdf/plugin-scroll/react'; - import { DocumentContent, DocumentManagerPluginPackage } from '@embedpdf/plugin-document-manager/react'; - import { useZoom, ZoomPluginPackage, ZoomMode } from '@embedpdf/plugin-zoom/react'; - import { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/react'; - import { ExportPluginPackage } from '@embedpdf/plugin-export/react'; - - import { Download, ZoomIn, ZoomOut, Maximize2, Minimize2, BookOpenText, X } from "lucide-react"; - import posthog from "posthog-js"; - import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; - import { downloadFile } from "../lib/utils/download"; - import { Button } from "./ui/button"; - import ShareButton from "./ShareButton"; - import ReportButton from "./ReportButton"; - import { useTheme } from "next-themes"; - - interface ControlProps { - documentId: string; - toggleFullscreen: () => void; - isFullscreen: boolean; - onDownload: () => Promise; - forceMobile?: boolean; - isMobile: boolean; - isSmall: boolean; - viewerRef: React.RefObject; - isReadingMode: boolean; - toggleReadingMode: () => void; - showReadingCoachmark: boolean; - dismissReadingCoachmark: () => void; - } +"use client" +import { createPluginRegistration } from '@embedpdf/core'; +import { EmbedPDF } from '@embedpdf/core/react'; +import { usePdfiumEngine } from '@embedpdf/engines/react'; +import { Viewport, ViewportPluginPackage } from '@embedpdf/plugin-viewport/react'; +import { useScroll, useScrollCapability, Scroller, ScrollPluginPackage } from '@embedpdf/plugin-scroll/react'; +import { DocumentContent, DocumentManagerPluginPackage } from '@embedpdf/plugin-document-manager/react'; +import { useZoom, ZoomPluginPackage, ZoomMode } from '@embedpdf/plugin-zoom/react'; +import { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/react'; +import { ExportPluginPackage } from '@embedpdf/plugin-export/react'; + +import { Download, ZoomIn, ZoomOut, Maximize2, Minimize2, BookOpenText, X } from "lucide-react"; +import posthog from "posthog-js"; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { downloadFile } from "../lib/utils/download"; +import { Button } from "./ui/button"; +import ShareButton from "./ShareButton"; +import ReportButton from "./ReportButton"; +import { useTheme } from "next-themes"; + +interface ControlProps { + documentId: string; + toggleFullscreen: () => void; + isFullscreen: boolean; + onDownload: () => Promise; + forceMobile?: boolean; + isMobile: boolean; + isSmall: boolean; + viewerRef: React.RefObject; + isReadingMode: boolean; + toggleReadingMode: () => void; + showReadingCoachmark: boolean; + dismissReadingCoachmark: () => void; +} + +interface PdfViewerProps { + url: string; + name: string; + className?: string; + height?: string; + hideControls?: boolean; + backgroundColor?: string; + hideScrollbar?: boolean; + isolateFromTheme?: boolean; + onReadingModeChange?: (isReadingMode: boolean) => void; +} + +interface WheelZoomProps { + documentId: string; + viewerRef: React.RefObject; +} + +function useBreakpoint() { + const [width, setWidth] = useState(null); + + useEffect(() => { + setWidth(window.innerWidth); + const handler = () => setWidth(window.innerWidth); + window.addEventListener("resize", handler); + return () => window.removeEventListener("resize", handler); + }, []); + + return {isMobile: width !== null && width < 768, isSmall: width !== null && width < 640}; +} + +const Controls = memo(function Controls({documentId, toggleFullscreen, isFullscreen, onDownload, + forceMobile, isMobile, isSmall, viewerRef, isReadingMode, toggleReadingMode, + showReadingCoachmark, dismissReadingCoachmark}: ControlProps) { + + const { provides: zoomProv, state: zoomState } = useZoom(documentId); + const { provides: scrollProv, state: scrollState } = useScroll(documentId); + const { provides: scrollCapability } = useScrollCapability(); + const [pageNo, setPageNo] = useState("1"); + const [totalPages, setTotalPages] = useState(0); + const editingRef = useRef(false); + + useEffect(() => { + if (!scrollCapability) return; + const unsub = scrollCapability.onLayoutReady((event) => { + if (event.documentId === documentId) { + setTotalPages(event.totalPages); + } + }); + return () => { + unsub(); + setTotalPages(0); + }; + }, [scrollCapability, documentId]); + + useEffect(() => { + if (!scrollProv) return; + const unsub = scrollProv.onPageChange((event) => { + setTotalPages(event.totalPages); + if (!editingRef.current) { + setPageNo(String(event.pageNumber)); + } + }); + return () => unsub(); + }, [scrollProv]); + + const effectiveTotalPages = + totalPages > 0 ? totalPages : (scrollState?.totalPages ?? 0); + +const pageChange = useCallback( + (e: React.KeyboardEvent) => { + if (e.key !== "Enter") return; + const page = parseInt(pageNo, 10); + if (isNaN(page)) return; + if (page >= 1 && page <= effectiveTotalPages) { + scrollProv?.scrollToPage({ pageNumber: page, behavior: "smooth" }); + } else { + setPageNo(String(scrollProv?.getCurrentPage() ?? 1)); + } + }, + [pageNo, effectiveTotalPages, scrollProv] + ); - interface PdfViewerProps { - url: string; - name: string; - className?: string; - height?: string; - hideControls?: boolean; - backgroundColor?: string; - hideScrollbar?: boolean; - isolateFromTheme?: boolean; - onReadingModeChange?: (isReadingMode: boolean) => void; - } + if (!zoomProv || !scrollProv) return null; - interface WheelZoomProps { - documentId: string; - viewerRef: React.RefObject; + if (isReadingMode) { + return ( + + ); } - function useBreakpoint() { - const [width, setWidth] = useState(null); - - useEffect(() => { - setWidth(window.innerWidth); - const handler = () => setWidth(window.innerWidth); - window.addEventListener("resize", handler); - return () => window.removeEventListener("resize", handler); - }, []); - - return {isMobile: width !== null && width < 768, isSmall: width !== null && width < 640}; + const zoomIn = () => zoomProv.zoomIn(); + const zoomOut = () => zoomProv.zoomOut(); + const { zoomLevel } = zoomState; + const fullScreenStyle = { + bottom: 20, + left: "50%", + transform: "translateX(-50%)", } - const Controls = memo(function Controls({documentId, toggleFullscreen, isFullscreen, onDownload, - forceMobile, isMobile, isSmall, viewerRef, isReadingMode, toggleReadingMode, - showReadingCoachmark, dismissReadingCoachmark}: ControlProps) { - - const { provides: zoomProv, state: zoomState } = useZoom(documentId); - const { provides: scrollProv, state: scrollState } = useScroll(documentId); - const { provides: scrollCapability } = useScrollCapability(); - const [pageNo, setPageNo] = useState("1"); - const [totalPages, setTotalPages] = useState(0); - const editingRef = useRef(false); - - useEffect(() => { - if (!scrollCapability) return; - const unsub = scrollCapability.onLayoutReady((event) => { - if (event.documentId === documentId) { - setTotalPages(event.totalPages); - } - }); - return () => { - unsub(); - setTotalPages(0); - }; - }, [scrollCapability, documentId]); - - useEffect(() => { - if (!scrollProv) return; - const unsub = scrollProv.onPageChange((event) => { - setTotalPages(event.totalPages); - if (!editingRef.current) { - setPageNo(String(event.pageNumber)); - } - }); - return () => unsub(); - }, [scrollProv]); - - const effectiveTotalPages = - totalPages > 0 ? totalPages : (scrollState?.totalPages ?? 0); - - const pageChange = useCallback( - (e: React.KeyboardEvent) => { - if (e.key !== "Enter") return; - const page = parseInt(pageNo, 10); - if (isNaN(page)) return; - if (page >= 1 && page <= effectiveTotalPages) { - scrollProv?.scrollToPage({ pageNumber: page, behavior: "smooth" }); - } else { - setPageNo(String(scrollProv?.getCurrentPage() ?? 1)); - } - }, - [pageNo, effectiveTotalPages, scrollProv] - ); - - if (!zoomProv || !scrollProv) return null; - - if (isReadingMode) { - return ( - - ); - } - - const zoomIn = () => zoomProv.zoomIn(); - const zoomOut = () => zoomProv.zoomOut(); - const { zoomLevel } = zoomState; - const fullScreenStyle = { - bottom: 20, - left: "50%", - transform: "translateX(-50%)", - } - - const pageInput = ( -
- { - editingRef.current = true; - setPageNo(e.target.value.replace(/[^0-9]/g, "")); - }} - onKeyDown={pageChange} - onFocus={(e) => { - editingRef.current = true; - e.target.select(); - }} - onBlur={() => { - editingRef.current = false; - setPageNo(String(scrollProv?.getCurrentPage() ?? 1)); - }} - inputMode="numeric" - className="h-9 w-14 rounded border bg-[#e7e9ff] p-1 text-center text-sm [appearance:textfield] dark:bg-[#1f1f2a] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" - /> - of {totalPages ?? 1} -
- ) - - const toolSet = ( - <> -
- {showReadingCoachmark && ( -
-
- New: Reading Mode. Hides - everything but the paper. Lighter than Fullscreen, your tabs - stay put. - -
-
+ const pageInput = ( +
+ { + editingRef.current = true; + setPageNo(e.target.value.replace(/[^0-9]/g, "")); + }} + onKeyDown={pageChange} + onFocus={(e) => { + editingRef.current = true; + e.target.select(); + }} + onBlur={() => { + editingRef.current = false; + setPageNo(String(scrollProv?.getCurrentPage() ?? 1)); + }} + inputMode="numeric" + className="h-9 w-14 rounded border bg-[#e7e9ff] p-1 text-center text-sm [appearance:textfield] dark:bg-[#1f1f2a] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none" + /> + of {totalPages ?? 1} +
+ ) + + const toolSet = ( + <> +
+ {showReadingCoachmark && ( +
+
+ New: Reading Mode. Hides + everything but the paper. Lighter than Fullscreen, your tabs + stay put. +
- )} - {showReadingCoachmark && ( - - )} - -
- - - +
+
+ )} + {showReadingCoachmark && ( + + )} +
- + - + - - {typeof zoomLevel === "number" ? `${Math.round(zoomLevel * 100)}%` : "100%"} - + - + + + + {typeof zoomLevel === "number" ? `${Math.round(zoomLevel * 100)}%` : "100%"} + + + - {isSmall && } + {isSmall && } - - ) + + ) - if (!forceMobile) { - return ( - <> - {!isSmall ? + if (!forceMobile) { + return ( + <> + {!isSmall ? +
+ {toolSet} + {pageInput} + {!isSmall && } +
: +
+ {pageInput}
{toolSet} - {pageInput} - {!isSmall && } -
: -
- {pageInput} -
- {toolSet} -
- -
} - - - ); - } - - return( -
- {isSmall ? ( - <> - {pageInput} -
- {toolSet} -
- - ) : ( - <> - {toolSet} - {pageInput} - - - )} -
- ) - }); - - function WheelZoom({ documentId, viewerRef }: WheelZoomProps) { - const { provides: zoomProv } = useZoom(documentId); - const accumulatedDelta = useRef(0); - const rafId = useRef(null); - const curZoom = useRef(1); - - useEffect(() => { - if (!zoomProv) return; - curZoom.current = zoomProv.getState().currentZoomLevel; - const unsub = zoomProv.onZoomChange((e) => { - curZoom.current = e.newZoom; - }); - return unsub; - }, [zoomProv]); - - const handleWheel = useCallback( - (e: WheelEvent) => { - if (!e.ctrlKey || !zoomProv) return; - e.preventDefault(); - - const isTrackpad = Math.abs(e.deltaY) < 50; - const scaleFactor = isTrackpad ? 0.008 : 0.08; - accumulatedDelta.current += -e.deltaY * scaleFactor; - - if (rafId.current !== null) cancelAnimationFrame(rafId.current); - rafId.current = requestAnimationFrame(() => { - const clamped = Math.max(-0.15, Math.min(accumulatedDelta.current, 0.15)); - - if (isTrackpad) { - const target = Math.max(0.25, Math.min(curZoom.current + clamped, 4)); - zoomProv.requestZoom(target) - curZoom.current = target; - } else { - zoomProv.requestZoomBy(clamped); - } - - accumulatedDelta.current = 0; - rafId.current = null; - }); - }, - [zoomProv] +
+ +
} + + ); - - useEffect(() => { - const viewer = viewerRef.current; - if (!viewer) return; - viewer.addEventListener("wheel", handleWheel, { passive: false }); - return () => { - viewer.removeEventListener("wheel", handleWheel); - if (rafId.current !== null) cancelAnimationFrame(rafId.current); - }; - }, [handleWheel, viewerRef]); - - return null; } - function useLoadingMessage(messages: string[], interval = 2200) { - const [index, setIndex] = useState(0); - const [visible, setVisible] = useState(true); - - useEffect(() => { - const timer = setInterval(() => { - setVisible(false); - setTimeout(() => { - setIndex(i => (i + 1) % messages.length); - setVisible(true); - }, 400); - }, interval); - return () => clearInterval(timer); - }, [messages, interval]); - - return { message: messages[index], visible }; - } + return( +
+ {isSmall ? ( + <> + {pageInput} +
+ {toolSet} +
+ + ) : ( + <> + {toolSet} + {pageInput} + + + )} +
+ ) +}); + +function WheelZoom({ documentId, viewerRef }: WheelZoomProps) { + const { provides: zoomProv } = useZoom(documentId); + const accumulatedDelta = useRef(0); + const rafId = useRef(null); + const curZoom = useRef(1); + + useEffect(() => { + if (!zoomProv) return; + curZoom.current = zoomProv.getState().currentZoomLevel; + const unsub = zoomProv.onZoomChange((e) => { + curZoom.current = e.newZoom; + }); + return unsub; + }, [zoomProv]); + + const handleWheel = useCallback( + (e: WheelEvent) => { + if (!e.ctrlKey || !zoomProv) return; + e.preventDefault(); + + const isTrackpad = Math.abs(e.deltaY) < 50; + const scaleFactor = isTrackpad ? 0.008 : 0.08; + accumulatedDelta.current += -e.deltaY * scaleFactor; + + if (rafId.current !== null) cancelAnimationFrame(rafId.current); + rafId.current = requestAnimationFrame(() => { + const clamped = Math.max(-0.15, Math.min(accumulatedDelta.current, 0.15)); + + if (isTrackpad) { + const target = Math.max(0.25, Math.min(curZoom.current + clamped, 4)); + zoomProv.requestZoom(target) + curZoom.current = target; + } else { + zoomProv.requestZoomBy(clamped); + } - const LOADING_MESSAGES = [ - "Loading document", - "Preparing pages", - "Almost there", - ]; - - export function Loader({ - backgroundColor = "#070114", - textColor = "rgba(255,255,255,0.5)", - }: { - backgroundColor?: string; - textColor?: string; - }) { - const { message, visible } = useLoadingMessage(LOADING_MESSAGES); - return ( -
-
- - {message} - -
- ); - } - export default function PDFViewer({ - url, - name, - className, - height = "100dvh", - hideControls = false, - backgroundColor, - hideScrollbar = false, - isolateFromTheme = true, - onReadingModeChange, - }: PdfViewerProps) { - const { engine, isLoading } = usePdfiumEngine(); - const { isMobile, isSmall } = useBreakpoint(); - const { resolvedTheme } = useTheme(); - const [isFullscreen, setIsFullscreen] = useState(false); - const [isReadingMode, setIsReadingMode] = useState(false); - const [showReadingCoachmark, setShowReadingCoachmark] = useState(false); - const viewerRef = useRef(null); - const effectiveBackgroundColor = - backgroundColor ?? (resolvedTheme === "light" ? "#F3F5FF" : "#070114"); - const loaderTextColor = - resolvedTheme === "light" ? "rgba(17,24,39,0.6)" : "rgba(255,255,255,0.5)"; - - const handleDownload = useCallback(async () => { - window.dataLayer?.push({ - event: "pdf_download_start", - paper_title: name, - paper_url: url, - }); - posthog.capture("paper_downloaded", { - paper_name: name, + accumulatedDelta.current = 0; + rafId.current = null; }); - await downloadFile(url, `${name}.pdf`); - }, [url, name]); - - const toggleFullscreen = useCallback(() => { - if (!document.fullscreenElement) { - void viewerRef.current?.requestFullscreen(); - } else { - void document.exitFullscreen(); + }, + [zoomProv] + ); + + useEffect(() => { + const viewer = viewerRef.current; + if (!viewer) return; + viewer.addEventListener("wheel", handleWheel, { passive: false }); + return () => { + viewer.removeEventListener("wheel", handleWheel); + if (rafId.current !== null) cancelAnimationFrame(rafId.current); + }; + }, [handleWheel, viewerRef]); + + return null; +} + +function useLoadingMessage(messages: string[], interval = 2200) { + const [index, setIndex] = useState(0); + const [visible, setVisible] = useState(true); + + useEffect(() => { + const timer = setInterval(() => { + setVisible(false); + setTimeout(() => { + setIndex(i => (i + 1) % messages.length); + setVisible(true); + }, 400); + }, interval); + return () => clearInterval(timer); + }, [messages, interval]); + + return { message: messages[index], visible }; +} + +const LOADING_MESSAGES = [ + "Loading document", + "Preparing pages", + "Almost there", +]; + +export function Loader({ + backgroundColor = "#070114", + textColor = "rgba(255,255,255,0.5)", +}: { + backgroundColor?: string; + textColor?: string; +}) { + const { message, visible } = useLoadingMessage(LOADING_MESSAGES); + return ( +
+
+ + {message} + +
+ ); +} +export default function PDFViewer({ + url, + name, + className, + height = "100dvh", + hideControls = false, + backgroundColor, + hideScrollbar = false, + isolateFromTheme = true, + onReadingModeChange, +}: PdfViewerProps) { + const { engine, isLoading } = usePdfiumEngine(); + const { isMobile, isSmall } = useBreakpoint(); + const { resolvedTheme } = useTheme(); + const [isFullscreen, setIsFullscreen] = useState(false); + const [isReadingMode, setIsReadingMode] = useState(false); + const [showReadingCoachmark, setShowReadingCoachmark] = useState(false); + const viewerRef = useRef(null); + const effectiveBackgroundColor = + backgroundColor ?? (resolvedTheme === "light" ? "#F3F5FF" : "#070114"); + const loaderTextColor = + resolvedTheme === "light" ? "rgba(17,24,39,0.6)" : "rgba(255,255,255,0.5)"; + + const handleDownload = useCallback(async () => { + window.dataLayer?.push({ + event: "pdf_download_start", + paper_title: name, + paper_url: url, + }); + posthog.capture("paper_downloaded", { + paper_name: name, + }); + await downloadFile(url, `${name}.pdf`); + }, [url, name]); + + const toggleFullscreen = useCallback(() => { + if (!document.fullscreenElement) { + void viewerRef.current?.requestFullscreen(); + } else { + void document.exitFullscreen(); + } + }, []); + + useEffect(() => { + const handleFullscreenChange = () => + setIsFullscreen(!!document.fullscreenElement); + document.addEventListener("fullscreenchange", handleFullscreenChange); + return () => document.removeEventListener("fullscreenchange", handleFullscreenChange); + }, []); + + const dismissReadingCoachmark = useCallback(() => { + setShowReadingCoachmark(false); + try { + window.localStorage.setItem("pdfReadingModeSeen", "1"); + } catch { + // localStorage unavailable (private mode, etc) — coachmark just won't persist + } + }, []); + + const toggleReadingMode = useCallback(() => { + setIsReadingMode((r) => { + const next = !r; + posthog.capture("reading_mode_toggled", { enabled: next }); + onReadingModeChange?.(next); + return next; + }); + dismissReadingCoachmark(); + }, [dismissReadingCoachmark, onReadingModeChange]); + + useEffect(() => { + try { + if (!window.localStorage.getItem("pdfReadingModeSeen")) { + setShowReadingCoachmark(true); } - }, []); - - useEffect(() => { - const handleFullscreenChange = () => - setIsFullscreen(!!document.fullscreenElement); - document.addEventListener("fullscreenchange", handleFullscreenChange); - return () => document.removeEventListener("fullscreenchange", handleFullscreenChange); - }, []); - - const dismissReadingCoachmark = useCallback(() => { - setShowReadingCoachmark(false); - try { - window.localStorage.setItem("pdfReadingModeSeen", "1"); - } catch { - // localStorage unavailable (private mode, etc) — coachmark just won't persist + } catch { + // ignore + } + }, []); + + useEffect(() => { + if (!isReadingMode) return; + const prevOverflow = document.body.style.overflow; + document.body.style.overflow = "hidden"; + return () => { + document.body.style.overflow = prevOverflow; + }; + }, [isReadingMode]); + + useEffect(() => { + const handleKeydown = (e: KeyboardEvent) => { + const target = e.target as HTMLElement | null; + if (target && ["INPUT", "TEXTAREA"].includes(target.tagName)) return; + if (e.ctrlKey || e.metaKey || e.altKey) return; + + if (e.key === "r" || e.key === "R") { + toggleReadingMode(); + } else if (e.key === 'f' || e.key === 'F') { + toggleFullscreen(); + } else if (e.key === "Escape" && isReadingMode) { + setIsReadingMode(false); + onReadingModeChange?.(false); } - }, []); - - const toggleReadingMode = useCallback(() => { - setIsReadingMode((r) => { - const next = !r; - posthog.capture("reading_mode_toggled", { enabled: next }); - onReadingModeChange?.(next); - return next; - }); - dismissReadingCoachmark(); - }, [dismissReadingCoachmark, onReadingModeChange]); + }; + window.addEventListener("keydown", handleKeydown); + return () => window.removeEventListener("keydown", handleKeydown); + }, [isReadingMode, toggleReadingMode, onReadingModeChange]); + + const plugins = useMemo(() => [ + createPluginRegistration(DocumentManagerPluginPackage, { + initialDocuments: [{ url }], + }), + createPluginRegistration(ViewportPluginPackage), + createPluginRegistration(ScrollPluginPackage), + createPluginRegistration(RenderPluginPackage), + createPluginRegistration(ZoomPluginPackage, { + defaultZoomLevel: ZoomMode.FitPage, + }), + createPluginRegistration(ExportPluginPackage, { + defaultFileName: `${name}.pdf`, + }), + ], [url, name]); + +if (isLoading || !engine) { + return ( + + ); +} + + return ( + <> + {hideScrollbar && ( + + )} + {isolateFromTheme && ( + - )} - {isolateFromTheme && ( - - )} -
- - {({ activeDocumentId }) => - activeDocumentId && ( - <> - - {!hideControls && (isMobile && !isFullscreen) && + [data-pdf-viewer-theme="light"] canvas, + [data-pdf-viewer-theme="light"] img, + [data-pdf-viewer-theme="light"] svg { + filter: none !important; + forced-color-adjust: none; + } + `} + )} +
+ + {({ activeDocumentId }) => + activeDocumentId && ( + <> + + {!hideControls && (isMobile && !isFullscreen) && + } + + {({ isLoaded }) => ( + <> +
+ +
+ + ( +
e.stopPropagation()} + > + +
+ )} + /> +
+ + )} +
+ + {!hideControls && (!isMobile || isFullscreen) && ( } - - {({ isLoaded }) => ( - <> -
- -
- - ( -
e.stopPropagation()} - > - -
- )} - /> -
- - )} -
- - {!hideControls && (!isMobile || isFullscreen) && ( - - )} - - ) - } -
-
- - ); - } \ No newline at end of file + /> + )} + + ) + } +
+
+ + ); +} \ No newline at end of file