Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 118 additions & 100 deletions components/pdf-container/pdf-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { RenderLayer, RenderPluginPackage } from "@embedpdf/plugin-render/react"
import { Scroller, ScrollPluginPackage, ScrollStrategy } from "@embedpdf/plugin-scroll/react"
import { SearchLayer, SearchPluginPackage } from "@embedpdf/plugin-search/react"
import { SelectionLayer, SelectionPluginPackage } from "./plugin-selection-2"
import { ThumbnailPluginPackage } from "@embedpdf/plugin-thumbnail/react"
import { TilingLayer, TilingPluginPackage } from "@embedpdf/plugin-tiling/react"
import { Viewport, ViewportPluginPackage } from "@embedpdf/plugin-viewport/react"
import { PinchWrapper, ZoomMode, ZoomPluginPackage } from "@embedpdf/plugin-zoom/react"
Expand All @@ -21,6 +22,8 @@ import AnnotationStoreSync from "../annotation-store/annotation-store-sync"
import { Spinner } from "../shadcn-ui/spinner"
import { AnnotationLayer, AnnotationPluginPackage } from "./plugin-annotation-2"
import Toolbar from "./toolbar"
import ThumbnailSidebar from "./thumbnail-sidebar"
import { Sidebar, SidebarContent, SidebarProvider } from "@/components/shadcn-ui/sidebar"

const logger = new ConsoleLogger()

Expand All @@ -46,106 +49,121 @@ export default function PDFContainer({ url }: PDFContainerProps) {
}

return (
<div className="flex h-screen flex-1 flex-col overflow-hidden" ref={containerRef}>
<div className="flex flex-1 overflow-hidden" data-testid="embedpdf">
<EmbedPDF
logger={logger}
engine={engine}
plugins={[
// register Loader first
createPluginRegistration(LoaderPluginPackage, {
loadingOptions: {
type: "url",
pdfFile: {
id: "1",
url: url,
},
options: {
mode: "full-fetch",
},
},
}),
createPluginRegistration(ViewportPluginPackage, {
viewportGap: 5,
}),
createPluginRegistration(ScrollPluginPackage, {
strategy: ScrollStrategy.Vertical,
}),
createPluginRegistration(RenderPluginPackage),
createPluginRegistration(InteractionManagerPluginPackage),
createPluginRegistration(TilingPluginPackage, {
tileSize: 768,
overlapPx: 2.5,
extraRings: 0,
}),
createPluginRegistration(SelectionPluginPackage),
// register Annotation after InteractionManager, Seletion
createPluginRegistration(AnnotationPluginPackage),
// register Export after Annotation
createPluginRegistration(ExportPluginPackage),
// register Zoom after InteractionManager, Viewport, Scroll
createPluginRegistration(ZoomPluginPackage, {
defaultZoomLevel: ZoomMode.Automatic,
}),
createPluginRegistration(SearchPluginPackage),
]}
>
{({ pluginsReady }) => {
return (
<GlobalPointerProvider>
<AnnotationStoreSync />
<Toolbar data-testid="annotation-toolbar" />
<Viewport className="h-full w-full flex-1 overflow-auto bg-gray-100 select-none">
{!pluginsReady && (
<div className="flex h-full w-full items-center justify-center">
<Spinner data-testid="spinner1" />
</div>
)}
{pluginsReady && (
<PinchWrapper>
<Scroller
renderPage={({ pageIndex, scale, width, height }) => (
<PagePointerProvider
pageIndex={pageIndex}
scale={scale}
pageWidth={width}
pageHeight={height}
rotation={0}
>
{/* RednerLayer must go first */}
<RenderLayer pageIndex={pageIndex} className="pointer-events-none" />
<TilingLayer
pageIndex={pageIndex}
scale={scale}
className="pointer-events-none"
/>
<AnnotationLayer
pageIndex={pageIndex}
scale={scale}
pageWidth={width}
pageHeight={height}
rotation={0}
data-testid="annotation-layer"
/>
<SearchLayer
pageIndex={pageIndex}
scale={scale}
highlightColor={"#FFFF00"}
activeHighlightColor={"#FFFF00"}
/>
{/* SelectionLayer must go last */}
<SelectionLayer pageIndex={pageIndex} scale={scale} />
</PagePointerProvider>
)}
/>
</PinchWrapper>
)}
</Viewport>
</GlobalPointerProvider>
)
}}
</EmbedPDF>
<SidebarProvider>
<div className="flex h-screen w-full" ref={containerRef}>
<div className="flex flex-1 flex-col overflow-hidden">
<div className="flex flex-1 overflow-hidden" data-testid="embedpdf">
<EmbedPDF
logger={logger}
engine={engine}
plugins={[
// register Loader first
createPluginRegistration(LoaderPluginPackage, {
loadingOptions: {
type: "url",
pdfFile: {
id: "1",
url: url,
},
options: {
mode: "full-fetch",
},
},
}),
createPluginRegistration(ViewportPluginPackage, {
viewportGap: 5,
}),
createPluginRegistration(ScrollPluginPackage, {
strategy: ScrollStrategy.Vertical,
}),
createPluginRegistration(RenderPluginPackage),
createPluginRegistration(InteractionManagerPluginPackage),
createPluginRegistration(TilingPluginPackage, {
tileSize: 768,
overlapPx: 2.5,
extraRings: 0,
}),
createPluginRegistration(SelectionPluginPackage),
// register Annotation after InteractionManager, Seletion
createPluginRegistration(AnnotationPluginPackage),
// register Export after Annotation
createPluginRegistration(ExportPluginPackage),
// register Zoom after InteractionManager, Viewport, Scroll
createPluginRegistration(ZoomPluginPackage, {
defaultZoomLevel: ZoomMode.Automatic,
}),
createPluginRegistration(SearchPluginPackage),
createPluginRegistration(ThumbnailPluginPackage, {
width: 120,
}),
]}
>
{({ pluginsReady }) => {
return (
<GlobalPointerProvider>
<AnnotationStoreSync />
<Toolbar data-testid="annotation-toolbar" />
<Viewport className="h-full w-full flex-1 overflow-auto bg-gray-100 select-none">
{!pluginsReady && (
<div className="flex h-full w-full items-center justify-center">
<Spinner data-testid="spinner1" />
</div>
)}
{pluginsReady && (
<PinchWrapper>
<Scroller
renderPage={({ pageIndex, scale, width, height }) => (
<PagePointerProvider
pageIndex={pageIndex}
scale={scale}
pageWidth={width}
pageHeight={height}
rotation={0}
>
{/* RednerLayer must go first */}
<RenderLayer
pageIndex={pageIndex}
className="pointer-events-none"
/>
<TilingLayer
pageIndex={pageIndex}
scale={scale}
className="pointer-events-none"
/>
<AnnotationLayer
pageIndex={pageIndex}
scale={scale}
pageWidth={width}
pageHeight={height}
rotation={0}
data-testid="annotation-layer"
/>
<SearchLayer
pageIndex={pageIndex}
scale={scale}
highlightColor={"#FFFF00"}
activeHighlightColor={"#FFFF00"}
/>
{/* SelectionLayer must go last */}
<SelectionLayer pageIndex={pageIndex} scale={scale} />
</PagePointerProvider>
)}
/>
</PinchWrapper>
)}
</Viewport>
</GlobalPointerProvider>
)
}}
</EmbedPDF>
</div>
</div>
<Sidebar side="right" variant="floating" collapsible="none">
<SidebarContent className="p-0">
<ThumbnailSidebar />
</SidebarContent>
</Sidebar>
</div>
</div>
</SidebarProvider>
)
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './selection-layer';
export * from './copy-to-clipboard';
export * from "./selection-layer"
export * from "./copy-to-clipboard"
2 changes: 1 addition & 1 deletion components/pdf-container/plugin-selection-2/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './use-selection';
export * from "./use-selection"
52 changes: 52 additions & 0 deletions components/pdf-container/thumbnail-sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client"

import { useScroll } from "@embedpdf/plugin-scroll/react"
import { ThumbImg, ThumbnailsPane } from "@embedpdf/plugin-thumbnail/react"
import { ScrollArea } from "@/components/shadcn-ui/scroll-area"

const ThumbnailSidebar = () => {
const { state, provides } = useScroll()

return (
<ScrollArea className="h-full w-[120px] border-l border-gray-200 bg-white">
<div className="relative">
<ThumbnailsPane>
{(m) => {
const isActive = state.currentPage === m.pageIndex + 1
return (
<div
key={m.pageIndex}
style={{
position: "absolute",
top: m.top,
height: m.wrapperHeight,
}}
onClick={() => provides?.scrollToPage({ pageNumber: m.pageIndex + 1 })}
className="w-full cursor-pointer transition-colors hover:bg-gray-50"
>
<div
style={{
border: `2px solid ${isActive ? "#3b82f6" : "#d1d5db"}`,
width: m.width,
height: m.height,
}}
className="mx-auto"
>
<ThumbImg meta={m} />
</div>
<span
style={{ height: m.labelHeight }}
className="flex items-center justify-center text-xs font-medium"
>
{m.pageIndex + 1}
</span>
</div>
)
}}
</ThumbnailsPane>
</div>
</ScrollArea>
)
}

export default ThumbnailSidebar
24 changes: 22 additions & 2 deletions components/pdf-container/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@ import { useZoom } from "@embedpdf/plugin-zoom/react"
import {
Download,
Highlighter,
Images,
Redo2,
Trash2,
Underline,
Undo2,
ZoomIn,
ZoomOut,
} from "lucide-react"
import { useSidebar } from "@/components/shadcn-ui/sidebar"

const Toolbar = () => {
interface ToolbarProps {
"data-testid"?: string
}

const Toolbar = ({ "data-testid": dataTestId }: ToolbarProps) => {
const { provides: exportApi } = useExportCapability()
const { provides: zoom } = useZoom()
const { toggleSidebar } = useSidebar()

const {
capability: annotationApi,
Expand All @@ -36,7 +43,10 @@ const Toolbar = () => {
]

return (
<div className="mt-4 mb-4 flex flex-wrap items-center gap-2 rounded-lg border border-gray-200 bg-white p-2 shadow-sm">
<div
className="mt-4 mb-4 flex flex-wrap items-center gap-2 rounded-lg border border-gray-200 bg-white p-2 shadow-sm"
data-testid={dataTestId}
>
{tools.map((tool) => (
<button
key={tool.id}
Expand All @@ -54,6 +64,16 @@ const Toolbar = () => {

<div className="h-6 w-px bg-gray-200" />

<button
onClick={() => toggleSidebar()}
className="rounded-md bg-gray-100 px-3 py-1 text-sm font-medium transition-colors hover:bg-gray-200"
title="Toggle Thumbnails Sidebar"
>
<Images size={18} />
</button>

<div className="h-6 w-px bg-gray-200" />

<button
onClick={() => zoom?.zoomOut()}
disabled={!zoom}
Expand Down
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@embedpdf/plugin-scroll": "1.3.16",
"@embedpdf/plugin-search": "1.3.16",
"@embedpdf/plugin-selection": "1.3.16",
"@embedpdf/plugin-thumbnail": "1.3.16",
"@embedpdf/plugin-tiling": "1.3.16",
"@embedpdf/plugin-viewport": "1.3.16",
"@embedpdf/plugin-zoom": "1.3.16",
Expand Down
Loading