Add comprehensive PDF reader enhancements

- pdf-page-sizes.ts: Dynamic page sizing and layout detection
- pdf-rotation.ts: Page rotation with orientation detection
- pdf-minimap.ts: Thumbnail minimap for navigation
- pdf-dual-page.ts: Dual page spread support
- pdf-links.ts: Clickable link handling
- pdf-clipbooard.ts: Copy to clipboard functionality
- pdf-bookmarks.ts: Bookmark management
- pdf-outline.ts: Document outline/TOC integration
- pdf-text-selection.ts: Text selection and highlighting
- page-cache.ts: PDF page caching system
- pdf-search.ts: Full-text search within PDF
- pdf-navigation.ts: Navigation controls and history
- annotation-layer.ts: PDF annotation rendering
- text-layer-renderer.ts: Text layer overlay rendering
- pdfjs-wrapper.ts: PDF.js wrapper with utilities
This commit is contained in:
2026-04-04 01:00:49 -04:00
parent d60469a757
commit c94679ec1e
15 changed files with 2121 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
// Annotation layer for rendering highlights and notes on PDFs
// Procedural style: Functions, not classes
interface PDFHighlight {
id: string;
pageNumber: number;
rects: DOMRect[];
text: string;
color: string;
noteId?: string;
}
const highlights = new Map<string, HTMLElement>();
export function renderPDFHighlights(
container: HTMLElement,
highlightList: PDFHighlight[],
): void {
// Clear existing highlights
clearPDFHighlights(container);
for (const highlight of highlightList) {
renderSinglePDFHighlight(container, highlight);
}
}
function renderSinglePDFHighlight(
container: HTMLElement,
highlight: PDFHighlight,
): void {
const overlay = document.createElement("div");
overlay.className = "pdf-highlight-annotation";
overlay.dataset.highlightId = highlight.id;
overlay.style.backgroundColor = parseColor(highlight.color);
// Position highlight rectangles
for (const rect of highlight.rects) {
const rectDiv = document.createElement("div");
rectDiv.className = "pdf-highlight-rect";
rectDiv.style.left = `${rect.left}px`;
rectDiv.style.top = `${rect.top}px`;
rectDiv.style.width = `${rect.width}px`;
rectDiv.style.height = `${rect.height}px`;
overlay.appendChild(rectDiv);
}
// Add click handler for note popup
if (highlight.noteId) {
overlay.style.cursor = "pointer";
overlay.addEventListener("click", () => {
showNotePopup(highlight);
});
}
// Add hover effect
overlay.addEventListener("mouseenter", () => {
overlay.style.opacity = "0.8";
});
overlay.addEventListener("mouseleave", () => {
overlay.style.opacity = "0.5";
});
container.appendChild(overlay);
highlights.set(highlight.id, overlay);
}
function parseColor(color: string): string {
if (color.startsWith("#")) {
const hex = color.slice(1);
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, 0.4)`;
}
return color;
}
function showNotePopup(highlight: PDFHighlight): void {
console.log("Show note for highlight:", highlight.id);
}
export function clearPDFHighlights(container: HTMLElement): void {
highlights.forEach((element) => element.remove());
highlights.clear();
}
export function removePDFHighlight(highlightId: string): void {
const element = highlights.get(highlightId);
if (element) {
element.remove();
highlights.delete(highlightId);
}
}