import React, { useState, useEffect } from 'react'; import { Box, ScrollArea, ActionIcon, Tooltip } from '@mantine/core'; import { LocalIcon } from '../shared/LocalIcon'; import '../../types/embedPdf'; interface ThumbnailSidebarProps { visible: boolean; onToggle: () => void; colorScheme: 'light' | 'dark' | 'auto'; } export function ThumbnailSidebar({ visible, onToggle, colorScheme }: ThumbnailSidebarProps) { const [selectedPage, setSelectedPage] = useState(1); const [thumbnails, setThumbnails] = useState<{ [key: number]: string }>({}); const [totalPages, setTotalPages] = useState(0); // Convert color scheme const actualColorScheme = colorScheme === 'auto' ? 'light' : colorScheme; // Get total pages from scroll API useEffect(() => { const scrollAPI = window.embedPdfScroll; if (scrollAPI && scrollAPI.totalPages) { setTotalPages(scrollAPI.totalPages); } }, [visible]); // Generate thumbnails when sidebar becomes visible useEffect(() => { if (!visible || totalPages === 0) return; const thumbnailAPI = window.embedPdfThumbnail?.thumbnailAPI; console.log('📄 ThumbnailSidebar useEffect triggered:', { visible, thumbnailAPI: !!thumbnailAPI, totalPages, existingThumbnails: Object.keys(thumbnails).length }); if (!thumbnailAPI) return; const generateThumbnails = async () => { console.log('📄 Starting thumbnail generation for', totalPages, 'pages'); for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) { if (thumbnails[pageIndex]) continue; // Skip if already generated try { console.log('📄 Attempting to generate thumbnail for page', pageIndex + 1); const thumbTask = thumbnailAPI.renderThumb(pageIndex, 1.0); console.log('📄 Received thumbTask:', thumbTask); // Convert Task to Promise and handle properly thumbTask.toPromise().then((thumbBlob: Blob) => { console.log('📄 Thumbnail generated successfully for page', pageIndex + 1, 'blob:', thumbBlob); const thumbUrl = URL.createObjectURL(thumbBlob); console.log('📄 Created blob URL:', thumbUrl); setThumbnails(prev => ({ ...prev, [pageIndex]: thumbUrl })); }).catch((error: any) => { console.error('📄 Failed to generate thumbnail for page', pageIndex + 1, error); setThumbnails(prev => ({ ...prev, [pageIndex]: 'error' })); }); } catch (error) { console.error('Failed to generate thumbnail for page', pageIndex + 1, error); // Set a placeholder or error state setThumbnails(prev => ({ ...prev, [pageIndex]: 'error' })); } } }; generateThumbnails(); // Cleanup blob URLs when component unmounts return () => { Object.values(thumbnails).forEach(url => { if (url.startsWith('blob:')) { URL.revokeObjectURL(url); } }); }; }, [visible, totalPages]); const handlePageClick = (pageIndex: number) => { const pageNumber = pageIndex + 1; // Convert to 1-based setSelectedPage(pageNumber); // Use scroll API to navigate to page const scrollAPI = window.embedPdfScroll; if (scrollAPI && scrollAPI.scrollToPage) { scrollAPI.scrollToPage(pageNumber); } }; return ( <> {/* Thumbnail Sidebar */} {visible && ( {/* Thumbnails Container */}
{Array.from({ length: totalPages }, (_, pageIndex) => ( handlePageClick(pageIndex)} style={{ cursor: 'pointer', borderRadius: '8px', padding: '8px', backgroundColor: selectedPage === pageIndex + 1 ? (actualColorScheme === 'dark' ? '#364FC7' : '#e7f5ff') : 'transparent', border: selectedPage === pageIndex + 1 ? '2px solid #1c7ed6' : '2px solid transparent', transition: 'all 0.2s ease', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }} onMouseEnter={(e) => { if (selectedPage !== pageIndex + 1) { e.currentTarget.style.backgroundColor = actualColorScheme === 'dark' ? '#25262b' : '#f1f3f5'; } }} onMouseLeave={(e) => { if (selectedPage !== pageIndex + 1) { e.currentTarget.style.backgroundColor = 'transparent'; } }} > {/* Thumbnail Image */} {thumbnails[pageIndex] && thumbnails[pageIndex] !== 'error' ? ( {`Page ) : thumbnails[pageIndex] === 'error' ? (
Failed
) : (
Loading...
)} {/* Page Number */}
Page {pageIndex + 1}
))}
)} ); }