Added a poc marker for where a bookmark resides.

Added a marker where a highlight might reside too.

Can move forward with a proper implementation.
This commit is contained in:
Joseph Milazzo 2025-06-29 16:45:44 -05:00
parent e5d949161e
commit 32ee60e1de
14 changed files with 257 additions and 76 deletions

View file

@ -326,8 +326,8 @@ export class ReaderService {
return this.httpClient.get<Array<PersonalToC>>(this.baseUrl + 'reader/ptoc?chapterId=' + chapterId);
}
createPersonalToC(libraryId: number, seriesId: number, volumeId: number, chapterId: number, pageNumber: number, title: string, bookScrollId: string | null) {
return this.httpClient.post(this.baseUrl + 'reader/create-ptoc', {libraryId, seriesId, volumeId, chapterId, pageNumber, title, bookScrollId});
createPersonalToC(libraryId: number, seriesId: number, volumeId: number, chapterId: number, pageNumber: number, title: string, bookScrollId: string | null, selectedText: string) {
return this.httpClient.post(this.baseUrl + 'reader/create-ptoc', {libraryId, seriesId, volumeId, chapterId, pageNumber, title, bookScrollId, selectedText});
}
getElementFromXPath(path: string) {

View file

@ -1,11 +1,15 @@
import {
ChangeDetectionStrategy, ChangeDetectorRef,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
ElementRef, EventEmitter, HostListener,
ElementRef,
EventEmitter,
HostListener,
inject,
Input,
OnInit, Output,
OnInit,
Output,
} from '@angular/core';
import {CommonModule} from '@angular/common';
import {fromEvent, merge, of} from "rxjs";
@ -125,7 +129,7 @@ export class BookLineOverlayComponent implements OnInit {
createPTOC() {
this.readerService.createPersonalToC(this.libraryId, this.seriesId, this.volumeId, this.chapterId, this.pageNumber,
this.bookmarkForm.get('name')?.value, this.xPath).pipe(catchError(err => {
this.bookmarkForm.get('name')?.value, this.xPath, this.selectedText).pipe(catchError(err => {
this.focusOnBookmarkInput();
return of();
})).subscribe(() => {

View file

@ -13,7 +13,8 @@ import {
OnInit,
Renderer2,
RendererStyleFlags2,
ViewChild
ViewChild,
ViewContainerRef
} from '@angular/core';
import {DOCUMENT, NgClass, NgIf, NgStyle, NgTemplateOutlet} from '@angular/common';
import {ActivatedRoute, Router} from '@angular/router';
@ -63,6 +64,7 @@ import {
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {ReadingProfile} from "../../../_models/preferences/reading-profiles";
import {ConfirmService} from "../../../shared/confirm.service";
import {EpubHighlightComponent} from "../epub-highlight/epub-highlight.component";
enum TabID {
@ -351,6 +353,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('readingSection', {static: false}) readingSectionElemRef!: ElementRef<HTMLDivElement>;
@ViewChild('stickyTop', {static: false}) stickyTopElemRef!: ElementRef<HTMLDivElement>;
@ViewChild('reader', {static: false}) reader!: ElementRef;
@ViewChild('readingHtml', { read: ViewContainerRef }) readingContainer!: ViewContainerRef;
/**
* Disables the Left most button
@ -543,7 +546,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
})
)
.subscribe();
}
handleScrollEvent() {
@ -1093,6 +1095,21 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
this.saveProgress();
this.isLoading = false;
this.cdRef.markForCheck();
// Make the highlight components "real"
const highlightElems = this.document.querySelectorAll('app-epub-highlight');
for (let i = 0; i < highlightElems.length; i++) {
const highlight = highlightElems[i];
const componentRef = this.readingContainer.createComponent<EpubHighlightComponent>(EpubHighlightComponent,
{projectableNodes: [[document.createTextNode(highlight.innerHTML)]]});
if (highlight.parentNode != null) {
highlight.parentNode.replaceChild(componentRef.location.nativeElement, highlight);
}
//componentRef.instance.cdRef.markForCheck();
}
}
private addEmptyPageIfRequired(): void {
@ -1316,7 +1333,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
getFirstVisibleElementXPath() {
let resumeElement: string | null = null;
if (this.bookContentElemRef === null) return null;
if (!this.bookContentElemRef || !this.bookContentElemRef.nativeElement) return null;
const intersectingEntries = Array.from(this.bookContentElemRef.nativeElement.querySelectorAll('div,o,p,ul,li,a,img,h1,h2,h3,h4,h5,h6,span'))
.filter(element => !element.classList.contains('no-observe'))

View file

@ -0,0 +1,6 @@
<span
[class]="highlightClasses()"
[attr.data-highlight-color]="color()">
<i class="fa-solid fa-pen-clip" role="button" (click)="toggleHighlight()"></i>
<ng-content></ng-content>
</span>

View file

@ -0,0 +1,32 @@
.epub-highlight {
position: relative;
transition: all 0.2s ease-in-out;
}
.epub-highlight-blue {
background-color: rgba(59, 130, 246, 0.3);
border-radius: 3px;
padding: 1px 2px;
}
.epub-highlight-green {
background-color: rgba(34, 197, 94, 0.3);
border-radius: 3px;
padding: 1px 2px;
}
.epub-highlight-blue:hover {
background-color: rgba(59, 130, 246, 0.4);
}
.epub-highlight-green:hover {
background-color: rgba(34, 197, 94, 0.4);
}
.epub-highlight-blue {
border-bottom: 1px solid rgba(59, 130, 246, 0.5);
}
.epub-highlight-green {
border-bottom: 1px solid rgba(34, 197, 94, 0.5);
}

View file

@ -0,0 +1,30 @@
import {Component, computed, input, model} from '@angular/core';
export type HighlightColor = 'blue' | 'green';
@Component({
selector: 'app-epub-highlight',
imports: [],
templateUrl: './epub-highlight.component.html',
styleUrl: './epub-highlight.component.scss'
})
export class EpubHighlightComponent {
showHighlight = model<boolean>(false);
color = input<HighlightColor>('blue');
highlightClasses = computed(() => {
const baseClass = 'epub-highlight';
if (!this.showHighlight()) {
return baseClass;
}
const colorClass = `epub-highlight-${this.color()}`;
return `${baseClass} ${colorClass}`;
});
toggleHighlight() {
this.showHighlight.set(!this.showHighlight());
}
}