diff --git a/COPILOT_CONTEXT_EN.md b/COPILOT_CONTEXT_EN.md index 5069e1eb..6a492f22 100644 --- a/COPILOT_CONTEXT_EN.md +++ b/COPILOT_CONTEXT_EN.md @@ -70,7 +70,8 @@ Conversions: - Fetches PDF via `DocumentService.GetDocumentAsync(EnvelopeKey)` - Converts to base64 data URL: `data:application/pdf;base64,{base64}` - Initializes PDF.js viewer via JSInterop with `DotNetObjectReference` for callbacks -- Displays controls: Zoom In/Out, Page Navigation, Zoom percentage +- Displays controls: Zoom In/Out, Page Navigation, Zoom percentage, Thumbnail toggle +- Thumbnail sidebar with resizable splitter (150px-400px range) - CSS externalized to `envelope-viewer.css` **JavaScript (`pdf-viewer.js`):** @@ -78,10 +79,15 @@ Conversions: window.pdfViewer = { pdfDoc, canvas, ctx, scale, currentRenderTask, dotNetReference, wheelEventAttached, + isResizing, resizeMouseMoveHandler, resizeMouseUpHandler, initialize(canvasId, pdfDataUrl, dotNetRef), renderPage(num), + renderThumbnail(pageNum, canvasId), attachWheelEvent(), // Global Ctrl+Wheel zoom + attachResizeListeners(dotNetRef), // Splitter resize + detachResizeListeners(), + startResize(), zoomIn(), zoomOut(), nextPage(), previousPage(), dispose() @@ -91,7 +97,10 @@ window.pdfViewer = { **CSS (`envelope-viewer.css`):** - `.envelope-viewer-layout`: Full-height gradient background - `.envelope-action-bar`: Top bar with logo, title, controls (sticky) -- `.pdf-frame`: Fixed-size white container (`calc(100vh - 200px)` × 90% width, max 1200px) +- `.pdf-frame`: Flex container (row) with thumbnails + canvas side-by-side +- `.pdf-thumbnails`: Left sidebar (260px default, resizable 150-400px), no header +- `.pdf-splitter`: 4px resizable divider with `col-resize` cursor +- `.pdf-canvas-wrapper`: Flex-grow container with scroll, padding, centered canvas - `.pdf-canvas`: `display: inline-block`, unlimited zoom, scrollable when exceeds frame - Modern glassmorphism design with gradients and shadows @@ -113,9 +122,30 @@ window.pdfViewer = { - Catches `RenderingCancelledException` to avoid console errors - Queue system (`pageNumPending`) for rapid page changes -4. **Responsive Design:** +4. **Thumbnail Sidebar:** + - Left panel with page previews (sequential rendering, 50ms delay) + - Click to navigate to specific page + - Active page highlighted with gradient border + - No header/title (maximizes thumbnail space) + - Toggle button in toolbar to show/hide + +5. **Resizable Splitter:** + - 4px draggable divider between thumbnails and canvas + - Min width: 150px, Max width: 400px + - Visual feedback: gradient on hover/active + - User preference saved to localStorage (`envelopeViewer_thumbnailWidth`) + - Global mouse events (works anywhere during drag) + - `col-resize` cursor (?) for intuitive UX + +6. **Flex Layout:** + - Thumbnails and canvas in same container (`.pdf-frame`) + - `display: flex, flex-direction: row, align-items: stretch` + - Perfect vertical alignment (same top/bottom position) + - Responsive: column layout on mobile (<768px) + +7. **Responsive Design:** - Desktop: 90% width, 1200px max - - Mobile: 95% width, adjusted heights + - Mobile: 95% width, adjusted heights, thumbnails collapse to top - Adaptive padding and font sizes ### Flow @@ -127,21 +157,28 @@ window.pdfViewer = { - Convert to base64 data URL - Set _isLoading = false - OnAfterRenderAsync(): + OnAfterRenderAsync(firstRender): + - Load saved thumbnail width from localStorage - Create DotNetObjectReference - JSRuntime.InvokeAsync("pdfViewer.initialize", canvasId, pdfDataUrl, dotNetRef) + - Attach resize listeners for splitter - Update _totalPages, _currentPage, _pdfLoaded + - Render thumbnails sequentially (50ms delay between pages) ``` 2. **User Interaction:** - Button clicks ? `ZoomIn()`/`ZoomOut()` ? `JSRuntime.InvokeVoidAsync("pdfViewer.zoomIn")` - Ctrl+Wheel ? JS `attachWheelEvent()` ? `dotNetRef.invokeMethodAsync('OnZoomChanged')` - Page buttons ? `NextPage()`/`PreviousPage()` ? `JSRuntime.InvokeAsync("pdfViewer.nextPage")` + - Thumbnail click ? `GoToPageFromThumbnail(pageNum)` ? `pdfViewer.goToPage(pageNum)` + - Toggle button ? `ToggleThumbnails()` ? `_showThumbnails = !_showThumbnails` + - Splitter drag ? `OnSplitterMouseDown()` ? JS global mouse events ? `OnSplitterMouseMove(clientX)` ? width update ? `OnSplitterMouseUp()` ? save to localStorage 3. **Cleanup:** ```csharp DisposeAsync(): - JSRuntime.InvokeVoidAsync("pdfViewer.dispose") + - Detach resize listeners - _dotNetRef?.Dispose() ``` @@ -269,6 +306,8 @@ return report; | **Mouse wheel on `.pdf-frame` only** | **Only works when mouse over PDF; should work anywhere on page** | | **OnAfterRenderAsync without `firstRender` guard** | **Creates infinite loop when `StateHasChanged` is called repeatedly** | | **Conditional rendering with `@if (_pdfLoaded)` wrapping canvas** | **Canvas not in DOM when initialize called, causing perpetual failure** | +| **Thumbnail sidebar with `position: absolute`** | **Independent from PDF canvas, breaks alignment on screen resize** | +| **Thumbnail header with title/close button** | **Wastes valuable space; toolbar toggle is sufficient** | --- @@ -303,81 +342,93 @@ Our use case is **visual/image stamping** at specific page coordinates | **11** | **2025-01-XX** | **Added PDF thumbnail sidebar (left panel) with page previews and navigation** | | **11** | **2025-01-XX** | **Implemented thumbnail rendering system with sequential loading (50ms delay between pages)** | | **11** | **2025-01-XX** | **Fixed thumbnail rendering: retry logic (10x 100ms) for canvas availability** | -| **11** | **2025-01-XX** | **Refactored layout: Side-by-side flex design (thumbnails left, PDF right), responsive mobile (horizontal scroll thumbnails)** | -| **11** | **2025-01-XX** | **Updated COPILOT_CONTEXT_EN.md: EnvelopeViewer replaces ReportViewer for read-only viewing** | -| **11** | **2025-01-XX** | **?? UNRESOLVED: Infinite render loop causing blank screen — Canvas not found error repeating, `_pdfLoaded` never becomes true** | +| **11** | **2025-01-XX** | **Refactored layout: Moved thumbnails inside `pdf-frame` for flex side-by-side design** | +| **11** | **2025-01-XX** | **Removed thumbnail header (title + close button) to maximize thumbnail space** | +| **11** | **2025-01-XX** | **Added resizable splitter: 4px draggable divider, 150-400px range, localStorage persistence** | +| **11** | **2025-01-XX** | **Fixed vertical alignment: `align-items: stretch` ensures thumbnails and canvas have same height** | +| **11** | **2025-01-XX** | **Updated COPILOT_CONTEXT_EN.md: Documented resizable splitter and layout refactoring** | --- -## Known Issues +## Layout Architecture (EnvelopeViewer) -### EnvelopeViewer — Blank Screen / Infinite Loop (UNRESOLVED) +### HTML Structure +```html +