{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "thumbnail-viewer", "dependencies": [ "react-pdf", "@wojtekmaj/react-hooks", "lucide-react" ], "registryDependencies": [ "button" ], "files": [ { "path": "registry/reusables/pdf-viewers/thumbnail-viewer.tsx", "content": "\"use client\"\n\nimport { useCallback, useState } from \"react\"\nimport { useResizeObserver } from \"@wojtekmaj/react-hooks\"\nimport { Document, Page, pdfjs } from \"react-pdf\"\n\nimport { cn } from \"@/lib/utils\"\n\nimport { LoadingSpinner } from \"./loading-spinner\"\n\npdfjs.GlobalWorkerOptions.workerSrc = new URL(\n \"pdfjs-dist/build/pdf.worker.min.mjs\",\n import.meta.url\n).toString()\n\nconst resizeObserverOptions = {}\nconst maxWidth = 800\n\ninterface ThumbnailViewerProps {\n url: string\n}\n\nexport const ThumbnailViewer = ({ url }: ThumbnailViewerProps) => {\n const [numPages, setNumPages] = useState(null)\n const [pageNumber, setPageNumber] = useState(1)\n const [containerRef, setContainerRef] = useState(null)\n const [containerWidth, setContainerWidth] = useState()\n const [pageHeight, setPageHeight] = useState(0)\n\n const onResize = useCallback((entries) => {\n const [entry] = entries\n if (entry) {\n setContainerWidth(entry.contentRect.width)\n }\n }, [])\n\n useResizeObserver(containerRef, resizeObserverOptions, onResize)\n\n const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {\n setNumPages(numPages)\n }\n\n // Calculate main viewer width based on container width\n const mainViewerWidth =\n containerWidth ? Math.min(containerWidth - 48, maxWidth) : maxWidth\n\n // Calculate thumbnail width - more responsive now\n const thumbnailWidth =\n containerWidth ? Math.min(120, containerWidth * 0.15) : 96\n\n return (\n
\n
\n {/* Thumbnails */}\n \n {Array.from(new Array(numPages), (_, index) => (\n setPageNumber(index + 1)}\n className={cn(\n \"relative shrink-0 overflow-hidden rounded-lg transition-all\",\n \"hover:ring-2 hover:ring-primary/50\",\n \"bg-background/50\",\n pageNumber === index + 1 && \"ring-2 ring-primary\"\n )}\n style={{\n width: thumbnailWidth,\n height: thumbnailWidth * 1.4,\n }}\n >\n \n \n }\n />\n \n \n ))}\n
\n\n {/* Main Viewer */}\n
\n \n \n }\n className={cn(\n \"flex flex-col items-center\",\n \"[&_.react-pdf__Page]:my-0\"\n )}\n >\n \n }\n onLoadSuccess={(page) => {\n setPageHeight(page.height * (mainViewerWidth / page.width))\n }}\n />\n \n
\n
\n \n \n )\n}\n", "type": "registry:component", "target": "components/pdf-viewers/thumbnail-viewer.tsx" }, { "path": "registry/reusables/pdf-viewers/loading-spinner.tsx", "content": "import { Loader2 } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface LoadingSpinnerProps {\n minHeight?: string\n minWidth?: string\n className?: string\n spinnerClassName?: string\n}\n\nexport const LoadingSpinner = ({\n minHeight = \"600px\",\n minWidth = \"800px\",\n className,\n spinnerClassName,\n}: LoadingSpinnerProps) => {\n return (\n \n \n \n )\n}\n", "type": "registry:component", "target": "components/pdf-viewers/loading-spinner.tsx" } ], "type": "registry:component" }