Run code formatting (prettier/eslint) on existing reader format files that were not migrated to the new structure. This ensures consistent code style across the codebase. ## Changes ### Formatting Applied - Added newlines at end of files - Fixed line length and indentation - Updated import statements for consistency - Applied code style rules uniformly ### Files Affected - **Comic**: background-color, chapter-markers, page-order, panel-gap - **Ebook**: font-loader, search, view-modes - **Manga**: vertical-scroll-mode - **PDF**: annotation-layer, pdf-navigation, pdf-text-selection ## Purpose These files will be removed in subsequent commits as they are replaced by the new modular structure. The formatting ensures consistency during the transition period and maintains code quality standards. Note: These are non-functional formatting changes only. No logic or behavior was modified in this commit.
124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
// Annotation layer for rendering highlights and notes on PDFs
|
|
// Feature Registration Pattern implementation
|
|
|
|
import { ReaderContext } from "../core/reader-context";
|
|
|
|
export function init(context: ReaderContext): void {
|
|
const highlights = new Map<string, HTMLElement>();
|
|
|
|
context.events.on(
|
|
"pdf:highlights:render",
|
|
(detail: { container: HTMLElement; highlights: any[] }) => {
|
|
clearPDFHighlights(detail.container);
|
|
for (const highlight of detail.highlights) {
|
|
renderSinglePDFHighlight(detail.container, highlight, highlights);
|
|
}
|
|
},
|
|
);
|
|
|
|
context.events.on(
|
|
"pdf:highlights:clear",
|
|
(detail: { container: HTMLElement }) => {
|
|
clearPDFHighlights(detail.container);
|
|
},
|
|
);
|
|
|
|
context.events.on(
|
|
"pdf:highlight:remove",
|
|
(detail: { highlightId: string }) => {
|
|
removePDFHighlight(detail.highlightId, highlights);
|
|
},
|
|
);
|
|
|
|
context.events.on("reader:unload", () => {
|
|
highlights.forEach((element) => element.remove());
|
|
highlights.clear();
|
|
});
|
|
}
|
|
|
|
interface PDFHighlight {
|
|
id: string;
|
|
pageNumber: number;
|
|
rects: DOMRect[];
|
|
text: string;
|
|
color: string;
|
|
noteId?: string;
|
|
}
|
|
|
|
function renderSinglePDFHighlight(
|
|
container: HTMLElement,
|
|
highlight: PDFHighlight,
|
|
highlights: Map<string, HTMLElement>,
|
|
): void {
|
|
const overlay = document.createElement("div");
|
|
overlay.className = "pdf-highlight-annotation";
|
|
overlay.dataset.highlightId = highlight.id;
|
|
overlay.style.backgroundColor = parseColor(highlight.color);
|
|
|
|
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);
|
|
}
|
|
|
|
if (highlight.noteId) {
|
|
overlay.style.cursor = "pointer";
|
|
overlay.addEventListener("click", () => {
|
|
showNotePopup(highlight);
|
|
});
|
|
}
|
|
|
|
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);
|
|
const event = new CustomEvent("pdf:note-show", {
|
|
detail: { highlightId: highlight.id },
|
|
});
|
|
window.dispatchEvent(event);
|
|
}
|
|
|
|
export function clearPDFHighlights(container: HTMLElement): void {
|
|
const highlights = container.querySelectorAll(".pdf-highlight-annotation");
|
|
Array.from(highlights).forEach((element) => element.remove());
|
|
}
|
|
|
|
export function removePDFHighlight(
|
|
highlightId: string,
|
|
highlights: Map<string, HTMLElement>,
|
|
): void {
|
|
const element = highlights.get(highlightId);
|
|
if (element) {
|
|
element.remove();
|
|
highlights.delete(highlightId);
|
|
}
|
|
}
|
|
|