epub-flow 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -13
- package/epub-flow-0.0.3.tgz +0 -0
- package/fesm2022/epub-flow.mjs +156 -84
- package/fesm2022/epub-flow.mjs.map +1 -1
- package/lib/add-notes/add-notes.component.d.ts +3 -3
- package/lib/epub-common-popup/epub-common-popup.component.d.ts +5 -5
- package/lib/epub-notification/notification-toast.component.d.ts +14 -0
- package/lib/epub-notification/notification.service.d.ts +21 -0
- package/lib/epub-reader.module.d.ts +5 -8
- package/lib/reader-main/reader-main.component.d.ts +3 -3
- package/package.json +2 -4
- package/public-api.d.ts +2 -0
- package/epub-flow-0.0.2.tgz +0 -0
package/fesm2022/epub-flow.mjs
CHANGED
|
@@ -14,15 +14,8 @@ import { Editor, NgxEditorModule } from 'ngx-editor';
|
|
|
14
14
|
import * as i1$1 from '@angular/cdk/overlay';
|
|
15
15
|
import { OverlayConfig } from '@angular/cdk/overlay';
|
|
16
16
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
17
|
-
import * as i4 from 'primeng/api';
|
|
18
17
|
import * as i1$3 from '@angular/platform-browser';
|
|
19
|
-
import * as i8 from 'primeng/tabview';
|
|
20
|
-
import { TabViewModule } from 'primeng/tabview';
|
|
21
18
|
import ePub from 'epubjs';
|
|
22
|
-
import * as i1$4 from 'primeng/progressbar';
|
|
23
|
-
import { ProgressBarModule } from 'primeng/progressbar';
|
|
24
|
-
import { TableModule } from 'primeng/table';
|
|
25
|
-
import { ButtonModule } from 'primeng/button';
|
|
26
19
|
|
|
27
20
|
class EpubReaderService {
|
|
28
21
|
http;
|
|
@@ -197,13 +190,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
197
190
|
args: [{ providedIn: 'root' }]
|
|
198
191
|
}] });
|
|
199
192
|
|
|
193
|
+
class NotificationService {
|
|
194
|
+
notificationSubject = new Subject();
|
|
195
|
+
notifications$ = this.notificationSubject.asObservable();
|
|
196
|
+
counter = 0;
|
|
197
|
+
show(message, type = 'info', title, duration = 3000) {
|
|
198
|
+
this.notificationSubject.next({
|
|
199
|
+
id: ++this.counter,
|
|
200
|
+
message,
|
|
201
|
+
type,
|
|
202
|
+
title,
|
|
203
|
+
duration
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
success(message, title = 'Success', duration) {
|
|
207
|
+
this.show(message, 'success', title, duration);
|
|
208
|
+
}
|
|
209
|
+
error(message, title = 'Error', duration) {
|
|
210
|
+
this.show(message, 'error', title, duration);
|
|
211
|
+
}
|
|
212
|
+
info(message, title = 'Info', duration) {
|
|
213
|
+
this.show(message, 'info', title, duration);
|
|
214
|
+
}
|
|
215
|
+
warn(message, title = 'Warning', duration) {
|
|
216
|
+
this.show(message, 'warning', title, duration);
|
|
217
|
+
}
|
|
218
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
219
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NotificationService, providedIn: 'root' });
|
|
220
|
+
}
|
|
221
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NotificationService, decorators: [{
|
|
222
|
+
type: Injectable,
|
|
223
|
+
args: [{
|
|
224
|
+
providedIn: 'root'
|
|
225
|
+
}]
|
|
226
|
+
}] });
|
|
227
|
+
|
|
200
228
|
class AddNotesComponent {
|
|
201
229
|
dialog;
|
|
202
230
|
sharedService;
|
|
203
231
|
epubReader;
|
|
204
232
|
userApi;
|
|
205
233
|
dialogRef;
|
|
206
|
-
|
|
234
|
+
notificationService;
|
|
207
235
|
editor; // Editor instance
|
|
208
236
|
textToAddorEdit;
|
|
209
237
|
toolbar = [
|
|
@@ -230,13 +258,13 @@ class AddNotesComponent {
|
|
|
230
258
|
return this.form.get('editorContent');
|
|
231
259
|
}
|
|
232
260
|
onDestroy$ = new Subject();
|
|
233
|
-
constructor(dialog, sharedService, epubReader, userApi, dialogRef,
|
|
261
|
+
constructor(dialog, sharedService, epubReader, userApi, dialogRef, notificationService) {
|
|
234
262
|
this.dialog = dialog;
|
|
235
263
|
this.sharedService = sharedService;
|
|
236
264
|
this.epubReader = epubReader;
|
|
237
265
|
this.userApi = userApi;
|
|
238
266
|
this.dialogRef = dialogRef;
|
|
239
|
-
this.
|
|
267
|
+
this.notificationService = notificationService;
|
|
240
268
|
}
|
|
241
269
|
ngOnInit() {
|
|
242
270
|
// Initialize the editor
|
|
@@ -301,12 +329,7 @@ class AddNotesComponent {
|
|
|
301
329
|
.pipe(takeUntil(this.onDestroy$))
|
|
302
330
|
.subscribe({
|
|
303
331
|
next: (res) => {
|
|
304
|
-
this.
|
|
305
|
-
key: 'notifyToast',
|
|
306
|
-
severity: 'success', // Use 'warn' for orange color
|
|
307
|
-
summary: 'Success',
|
|
308
|
-
detail: res.message,
|
|
309
|
-
});
|
|
332
|
+
this.notificationService.success(res.message);
|
|
310
333
|
this.dialog.closeAll();
|
|
311
334
|
},
|
|
312
335
|
error: (err) => {
|
|
@@ -347,12 +370,7 @@ class AddNotesComponent {
|
|
|
347
370
|
.pipe(takeUntil(this.onDestroy$))
|
|
348
371
|
.subscribe({
|
|
349
372
|
next: (res) => {
|
|
350
|
-
this.
|
|
351
|
-
key: 'notifyToast',
|
|
352
|
-
severity: 'success', // Use 'warn' for orange color
|
|
353
|
-
summary: 'Success',
|
|
354
|
-
detail: res.message,
|
|
355
|
-
});
|
|
373
|
+
this.notificationService.success(res.message);
|
|
356
374
|
this.dialog.closeAll();
|
|
357
375
|
},
|
|
358
376
|
error: (err) => {
|
|
@@ -364,13 +382,13 @@ class AddNotesComponent {
|
|
|
364
382
|
},
|
|
365
383
|
});
|
|
366
384
|
}
|
|
367
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AddNotesComponent, deps: [{ token: CustomDialogService }, { token: SharedService }, { token: EpubReaderService }, { token: HttpApiService }, { token: CustomDialogRef }, { token:
|
|
385
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AddNotesComponent, deps: [{ token: CustomDialogService }, { token: SharedService }, { token: EpubReaderService }, { token: HttpApiService }, { token: CustomDialogRef }, { token: NotificationService }], target: i0.ɵɵFactoryTarget.Component });
|
|
368
386
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: AddNotesComponent, isStandalone: false, selector: "app-add-notes", host: { listeners: { "document:dragover": "onDragOver($event)", "document:drop": "onDrop($event)", "document:dragstart": "onDragStart($event)", "document:contextmenu": "onRightClick($event)", "document:keydown": "onKeyDown($event)", "document:copy": "onCopy($event)" } }, ngImport: i0, template: "<div class=\"note-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">{{ dialogRef.data.addNote ? 'Add Note' : 'Edit Note' }}</h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n <form class=\"note-form\" [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <!-- Editor Section -->\n <section class=\"editor-section\">\n <ngx-editor-menu [editor]=\"editor\" [toolbar]=\"toolbar\">\n </ngx-editor-menu>\n\n <ngx-editor class=\"editor-body\" [editor]=\"editor\" formControlName=\"editorContent\">\n </ngx-editor>\n </section>\n\n <!-- Validation -->\n <p class=\"error\" *ngIf=\"editorContent.invalid && editorContent.touched\">\n Content is required.\n </p>\n\n <!-- Footer / Actions -->\n <footer class=\"action-bar\">\n @if (dialogRef.data.addNote) {\n <button type=\"submit\" class=\"btn btn-primary\" (click)=\"addNote()\"\n [disabled]=\"!hasValidContent(editorContent.value) || isSubmitting\">\n Add Note\n </button>\n } @else {\n <button type=\"submit\" class=\"btn btn-primary\" (click)=\"updateNote()\"\n [disabled]=\"!hasValidContent(editorContent.value) || isSubmitting\">\n Update Note\n </button>\n }\n </footer>\n </form>\n</div>", styles: [":host{display:block;font-family:Figtree,sans-serif;--primary: #34c759;--primary-hover: #2ebd50;--bg: #ffffff;--text: #1f2937;--border: #e5e7eb}:host-context(.dark-mode){--bg: #1f2937;--text: #f9fafb;--border: #374151}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuBar{background:#1f2937;border-color:#374151}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem{color:#e5e7eb}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem:hover{background-color:#374151;color:#fff}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem.NgxEditor__MenuItem--Active{background-color:#374151;color:#34c759}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem svg{fill:currentColor}:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown .NgxEditor__Dropdown--Selected,:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown .NgxEditor__Dropdown--Open,:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown:hover{background-color:#374151;color:#fff}.note-container{width:100%;max-width:560px;height:auto;min-height:480px;max-height:85vh;background:var(--bg);color:var(--text);border-radius:16px;box-shadow:0 20px 25px -5px #00000026;overflow:hidden;display:flex;flex-direction:column}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px 0}.popup-title{margin:0;font-size:1.125rem;font-weight:600;color:var(--text)}.close-btn{background:transparent;border:none;cursor:pointer;padding:8px;margin:-8px -8px -8px 0;border-radius:50%;color:var(--text);display:flex;align-items:center;justify-content:center;opacity:.7;transition:all .2s}.close-btn:hover{background-color:#0000000d;opacity:1}:host-context(.dark-mode) .close-btn:hover{background-color:#ffffff1a}.note-form{display:flex;flex-direction:column;flex:1;padding:1.5rem;overflow:hidden}.editor-section{display:flex;flex-direction:column;flex:1;min-height:250px;border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:border-color .2s ease;background:var(--bg)}.editor-section:focus-within{border-color:var(--primary);box-shadow:0 0 0 3px #34c75926}::ng-deep .NgxEditor__MenuBar{background:var(--bg);border-bottom:1px solid var(--border);padding:.5rem;gap:.25rem;flex-wrap:wrap}::ng-deep .NgxEditor{flex:1;height:100%;min-height:300px;padding:1rem;border:none!important;background:var(--bg);color:var(--text);font-size:.95rem;line-height:1.6;overflow-y:auto}.error{color:#ef4444;font-size:.85rem;margin:.5rem 0 0}.action-bar{display:flex;justify-content:flex-end;padding-top:.75rem}::ng-deep .NgxEditor__Popup{position:absolute;top:calc(var(--ngx-editor-menubar-height) + 2px);box-shadow:var(--ngx-editor-popup-shadow);border-radius:var(--ngx-editor-popup-border-radius);background-color:var(--ngx-editor-popup-bg-color);z-index:100;min-width:101px;padding:8px;right:2px}.btn{min-width:140px;padding:10px 24px;border-radius:10px;font-weight:600;border:none;cursor:pointer;transition:all .2s ease}.btn-primary{background:var(--primary);color:#fff;box-shadow:0 4px 6px #34c7594d}.btn-primary:hover:not(:disabled){background:var(--primary-hover);transform:translateY(-1px)}.btn-primary:disabled{opacity:.6;cursor:not-allowed;box-shadow:none}@media (max-width: 640px){.note-container{height:100vh;border-radius:0}.note-form{padding:.75rem}.action-bar{justify-content:stretch}.btn{width:100%}}\n"], dependencies: [{ kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.NgxEditorComponent, selector: "ngx-editor", inputs: ["editor", "outputFormat", "placeholder"], outputs: ["focusOut", "focusIn"] }, { kind: "component", type: i6.NgxEditorMenuComponent, selector: "ngx-editor-menu", inputs: ["toolbar", "colorPresets", "disabled", "editor", "customMenuRef", "dropdownPlacement"] }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i7.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
369
387
|
}
|
|
370
388
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AddNotesComponent, decorators: [{
|
|
371
389
|
type: Component,
|
|
372
390
|
args: [{ selector: 'app-add-notes', standalone: false, template: "<div class=\"note-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">{{ dialogRef.data.addNote ? 'Add Note' : 'Edit Note' }}</h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n <form class=\"note-form\" [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <!-- Editor Section -->\n <section class=\"editor-section\">\n <ngx-editor-menu [editor]=\"editor\" [toolbar]=\"toolbar\">\n </ngx-editor-menu>\n\n <ngx-editor class=\"editor-body\" [editor]=\"editor\" formControlName=\"editorContent\">\n </ngx-editor>\n </section>\n\n <!-- Validation -->\n <p class=\"error\" *ngIf=\"editorContent.invalid && editorContent.touched\">\n Content is required.\n </p>\n\n <!-- Footer / Actions -->\n <footer class=\"action-bar\">\n @if (dialogRef.data.addNote) {\n <button type=\"submit\" class=\"btn btn-primary\" (click)=\"addNote()\"\n [disabled]=\"!hasValidContent(editorContent.value) || isSubmitting\">\n Add Note\n </button>\n } @else {\n <button type=\"submit\" class=\"btn btn-primary\" (click)=\"updateNote()\"\n [disabled]=\"!hasValidContent(editorContent.value) || isSubmitting\">\n Update Note\n </button>\n }\n </footer>\n </form>\n</div>", styles: [":host{display:block;font-family:Figtree,sans-serif;--primary: #34c759;--primary-hover: #2ebd50;--bg: #ffffff;--text: #1f2937;--border: #e5e7eb}:host-context(.dark-mode){--bg: #1f2937;--text: #f9fafb;--border: #374151}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuBar{background:#1f2937;border-color:#374151}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem{color:#e5e7eb}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem:hover{background-color:#374151;color:#fff}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem.NgxEditor__MenuItem--Active{background-color:#374151;color:#34c759}:host-context(.dark-mode) ::ng-deep .NgxEditor__MenuItem svg{fill:currentColor}:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown .NgxEditor__Dropdown--Selected,:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown .NgxEditor__Dropdown--Open,:host-context(.dark-mode) ::ng-deep .NgxEditor__Dropdown:hover{background-color:#374151;color:#fff}.note-container{width:100%;max-width:560px;height:auto;min-height:480px;max-height:85vh;background:var(--bg);color:var(--text);border-radius:16px;box-shadow:0 20px 25px -5px #00000026;overflow:hidden;display:flex;flex-direction:column}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px 0}.popup-title{margin:0;font-size:1.125rem;font-weight:600;color:var(--text)}.close-btn{background:transparent;border:none;cursor:pointer;padding:8px;margin:-8px -8px -8px 0;border-radius:50%;color:var(--text);display:flex;align-items:center;justify-content:center;opacity:.7;transition:all .2s}.close-btn:hover{background-color:#0000000d;opacity:1}:host-context(.dark-mode) .close-btn:hover{background-color:#ffffff1a}.note-form{display:flex;flex-direction:column;flex:1;padding:1.5rem;overflow:hidden}.editor-section{display:flex;flex-direction:column;flex:1;min-height:250px;border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:border-color .2s ease;background:var(--bg)}.editor-section:focus-within{border-color:var(--primary);box-shadow:0 0 0 3px #34c75926}::ng-deep .NgxEditor__MenuBar{background:var(--bg);border-bottom:1px solid var(--border);padding:.5rem;gap:.25rem;flex-wrap:wrap}::ng-deep .NgxEditor{flex:1;height:100%;min-height:300px;padding:1rem;border:none!important;background:var(--bg);color:var(--text);font-size:.95rem;line-height:1.6;overflow-y:auto}.error{color:#ef4444;font-size:.85rem;margin:.5rem 0 0}.action-bar{display:flex;justify-content:flex-end;padding-top:.75rem}::ng-deep .NgxEditor__Popup{position:absolute;top:calc(var(--ngx-editor-menubar-height) + 2px);box-shadow:var(--ngx-editor-popup-shadow);border-radius:var(--ngx-editor-popup-border-radius);background-color:var(--ngx-editor-popup-bg-color);z-index:100;min-width:101px;padding:8px;right:2px}.btn{min-width:140px;padding:10px 24px;border-radius:10px;font-weight:600;border:none;cursor:pointer;transition:all .2s ease}.btn-primary{background:var(--primary);color:#fff;box-shadow:0 4px 6px #34c7594d}.btn-primary:hover:not(:disabled){background:var(--primary-hover);transform:translateY(-1px)}.btn-primary:disabled{opacity:.6;cursor:not-allowed;box-shadow:none}@media (max-width: 640px){.note-container{height:100vh;border-radius:0}.note-form{padding:.75rem}.action-bar{justify-content:stretch}.btn{width:100%}}\n"] }]
|
|
373
|
-
}], ctorParameters: () => [{ type: CustomDialogService }, { type: SharedService }, { type: EpubReaderService }, { type: HttpApiService }, { type: CustomDialogRef }, { type:
|
|
391
|
+
}], ctorParameters: () => [{ type: CustomDialogService }, { type: SharedService }, { type: EpubReaderService }, { type: HttpApiService }, { type: CustomDialogRef }, { type: NotificationService }], propDecorators: { onDragOver: [{
|
|
374
392
|
type: HostListener,
|
|
375
393
|
args: ['document:dragover', ['$event']]
|
|
376
394
|
}], onDrop: [{
|
|
@@ -429,7 +447,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
429
447
|
class EpubCommonPopupComponent {
|
|
430
448
|
sanitizer;
|
|
431
449
|
userApi;
|
|
432
|
-
|
|
450
|
+
notificationService;
|
|
433
451
|
dialog;
|
|
434
452
|
dialogRef;
|
|
435
453
|
loaderService;
|
|
@@ -461,14 +479,14 @@ class EpubCommonPopupComponent {
|
|
|
461
479
|
searchData = null;
|
|
462
480
|
searchCharaSmall = false;
|
|
463
481
|
onDestroy$ = new Subject();
|
|
464
|
-
|
|
482
|
+
activeTab = 0;
|
|
465
483
|
Definition = [];
|
|
466
484
|
isLoading = false;
|
|
467
485
|
isSearchDataAvailable = false;
|
|
468
|
-
constructor(sanitizer, userApi,
|
|
486
|
+
constructor(sanitizer, userApi, notificationService, dialog, dialogRef, loaderService, epubService, sharedService) {
|
|
469
487
|
this.sanitizer = sanitizer;
|
|
470
488
|
this.userApi = userApi;
|
|
471
|
-
this.
|
|
489
|
+
this.notificationService = notificationService;
|
|
472
490
|
this.dialog = dialog;
|
|
473
491
|
this.dialogRef = dialogRef;
|
|
474
492
|
this.loaderService = loaderService;
|
|
@@ -496,23 +514,17 @@ class EpubCommonPopupComponent {
|
|
|
496
514
|
this.getDefinition();
|
|
497
515
|
}
|
|
498
516
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
*@Author: Aboobacker
|
|
502
|
-
*/
|
|
503
|
-
onTabChange(data) {
|
|
517
|
+
setActiveTab(index) {
|
|
518
|
+
this.activeTab = index;
|
|
504
519
|
this.paginationData = {
|
|
505
520
|
totalCount: 0,
|
|
506
521
|
pageSize: 10,
|
|
507
522
|
currentPage: 1,
|
|
508
523
|
};
|
|
509
|
-
if (
|
|
510
|
-
//noteas
|
|
511
|
-
this.tabviewIndex = data.index;
|
|
524
|
+
if (index === 1) {
|
|
512
525
|
this.getNotes();
|
|
513
526
|
}
|
|
514
527
|
else {
|
|
515
|
-
//highlights
|
|
516
528
|
this.getHighlightNotes();
|
|
517
529
|
}
|
|
518
530
|
}
|
|
@@ -634,12 +646,7 @@ class EpubCommonPopupComponent {
|
|
|
634
646
|
.subscribe({
|
|
635
647
|
next: (res) => {
|
|
636
648
|
this.loaderService.showHide(false);
|
|
637
|
-
this.
|
|
638
|
-
key: 'notifyToast',
|
|
639
|
-
severity: 'success',
|
|
640
|
-
summary: 'Success',
|
|
641
|
-
detail: res.message,
|
|
642
|
-
});
|
|
649
|
+
this.notificationService.success(res.message);
|
|
643
650
|
if (this.template == 1) {
|
|
644
651
|
this.dialog.closeAll();
|
|
645
652
|
}
|
|
@@ -723,13 +730,13 @@ class EpubCommonPopupComponent {
|
|
|
723
730
|
this.onDestroy$.next();
|
|
724
731
|
this.onDestroy$.complete();
|
|
725
732
|
}
|
|
726
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubCommonPopupComponent, deps: [{ token: i1$3.DomSanitizer }, { token: HttpApiService }, { token:
|
|
727
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: EpubCommonPopupComponent, isStandalone: false, selector: "app-epub-common-popup", ngImport: i0, template: "<!-- Template 1: Single Note View -->\n@if (dialogRef.data.template == 1) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">Note Details</h2>\n <div class=\"header-actions\">\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"popup-content content-padded\">\n <div class=\"inner-html-class text-lg text-primary mb-6\" [innerHTML]=\"htmlString\"></div>\n </div>\n\n <div class=\"dialog-footer\">\n <button class=\"btn btn-secondary\" (click)=\"close()\">\n {{ htmlStaticText.btnText.cancel }}\n </button>\n <button class=\"btn btn-primary\" (click)=\"editNote()\">\n {{ htmlStaticText.btnText.edit }}\n </button>\n <button class=\"btn btn-danger\" (click)=\"deleteAnnotations(1, this.singlenoteDetails.id)\">\n {{ htmlStaticText.btnText.remove }}\n </button>\n </div>\n</div>\n}\n\n<!-- Template 2: Highlights & Notes Tabs -->\n@if (dialogRef.data.template == 2) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16.035 2.977l4.988 4.989-12.022 12.021H4v-4.988L16.035 2.977z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Highlights & Notes\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <p-tabView (onChange)=\"onTabChange($event)\">\n\n <!-- Highlights Tab -->\n <p-tabPanel header=\"Highlights\">\n <div *ngIf=\"isLoading; else highlightsContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #highlightsContent>\n <div *ngIf=\"!notesandHighlights?.length; else noteList\" class=\"empty-state\">\n {{ htmlStaticText.htmlText.nohighlightsavailable }}\n </div>\n\n <ng-template #noteList>\n <div *ngFor=\"let note of notesandHighlights\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <div class=\"w-2 h-8 rounded-full\" [style.background-color]=\"note.colorCode\"\n style=\"width: 4px; height: 32px; border-radius: 4px;\"></div>\n </div>\n\n <div class=\"row-content\" (click)=\"gotoLocation(note.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ note.annotatedNotes }}</div>\n <div class=\"row-meta\">\n <span>Page {{ note.pageNumber || 'N/A' }}</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(2, note.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </p-tabPanel>\n\n <!-- Notes Tab -->\n <p-tabPanel header=\"Notes\">\n <div *ngIf=\"isLoading; else notesContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #notesContent>\n <div *ngIf=\"!notes?.length; else notesList\" class=\"empty-state\">\n No notes available.\n </div>\n\n <ng-template #notesList>\n <div *ngFor=\"let item of notes\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div class=\"row-content\" (click)=\"openNote(item)\">\n <div class=\"row-title line-clamp\"\n [innerHTML]=\"item.annotatedNotes ? item.annotatedNotes : item.customNotes\"></div>\n </div>\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(1, item.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </p-tabPanel>\n\n </p-tabView>\n </div>\n</div>\n}\n\n<!-- Template 3: Search -->\n@if (dialogRef.data.template == 3) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Search\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <svg class=\"search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <input [(ngModel)]=\"searchKey\" (keyup.enter)=\"updateSearchKey()\" type=\"text\" placeholder=\"Search in book...\"\n class=\"search-input\" autofocus />\n <div class=\"input-actions-wrapper\">\n <button *ngIf=\"searchKey\" class=\"icon-btn-clear\" (click)=\"clearSearch()\" title=\"Clear search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button class=\"btn btn-primary btn-sm\" (click)=\"updateSearchKey()\">\n Search\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"searchCharaSmall\" class=\"info-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\" />\n </svg>\n <span>{{ staticText.validationText.atleastThreeChara }}</span>\n </div>\n\n <div *ngIf=\"isSearchDataAvailable; else searchResults\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #searchResults>\n <div *ngIf=\"searchKey?.length && searchData && !searchData?.length\" class=\"empty-state\">\n <app-no-data-found></app-no-data-found>\n </div>\n\n <div class=\"search-results\">\n <div *ngFor=\"let item of searchData\" class=\"popup-row\" (click)=\"clickSearchItem(item.cfi)\">\n <div class=\"row-content\">\n <div class=\"row-title\" [innerHTML]=\"item.highlightedSentence\"></div>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 4: Bookmarks -->\n@if (dialogRef.data.template == 4) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Bookmarks\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"isLoading; else bookmarkContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #bookmarkContent>\n <div *ngIf=\"!bookMarkList || bookMarkList.length === 0\" class=\"empty-state\">\n No bookmarks yet.\n </div>\n\n <div *ngIf=\"bookMarkList && bookMarkList.length > 0\">\n <div *ngFor=\"let bookmark of bookMarkList\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <!-- Filled Bookmark Icon for list -->\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"\n [style.color]=\"bookmark.colorCode || '#3b82f6'\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" />\n </svg>\n </div>\n\n <div class=\"row-content\" (click)=\"closePopup(bookmark.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ bookmark.annotatedNotes || 'Bookmark' }}</div>\n <div class=\"row-meta mt-2\">\n <div class=\"progress-container\">\n <div class=\"progress-fill\" [style.width.%]=\"bookmark.customNotes\"></div>\n </div>\n <span>{{ bookmark.customNotes }}%</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(4, bookmark.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 5: Definitions -->\n@if (dialogRef.data.template == 5) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 19.5A2.5 2.5 0 016.5 17H20\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Definition\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content content-padded\">\n <h3 class=\"text-xl font-bold text-primary mb-4 select-text\">\n \"{{ dialogRef.data.selectedText }}\"\n </h3>\n\n <div *ngIf=\"isLoading; else defsContent\">\n <app-skeleton-loader [count]=\"3\" type=\"text\"></app-skeleton-loader>\n </div>\n\n <ng-template #defsContent>\n <div *ngIf=\"Definition?.length > 0; else noDefs\">\n <div *ngFor=\"let entry of Definition\" class=\"definition-group\">\n <span class=\"pos-tag\">{{ entry.partOfSpeech }}</span>\n\n <div *ngFor=\"let def of entry.definitions\" class=\"def-item\">\n <p class=\"def-text\">{{ def.definition }}</p>\n <p *ngIf=\"def.example\" class=\"def-example\">\"{{ def.example }}\"</p>\n </div>\n </div>\n </div>\n\n <ng-template #noDefs>\n <div class=\"empty-state\">No definitions found.</div>\n </ng-template>\n </ng-template>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #64748b;--border-soft: #e2e8f0;--accent: #3b82f6;--accent-hover: #2563eb;--danger: #ef4444;--danger-bg: #fef2f2}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-soft: #334155;--accent: #60a5fa;--accent-hover: #3b82f6;--danger: #f87171;--danger-bg: #450a0a}.popup-container{display:flex;flex-direction:column;width:500px;height:600px;max-width:95vw;max-height:85vh;background:var(--bg-primary);color:var(--text-primary);border-radius:16px;overflow:hidden;box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;background:var(--bg-secondary);border-bottom:1px solid var(--border-soft)}.popup-title{font-size:1.15rem;font-weight:600;color:var(--text-primary);display:flex;align-items:center;gap:12px;margin:0}.popup-title svg{color:var(--text-secondary)}.close-btn{background:transparent;border:none;color:var(--text-secondary);padding:8px;border-radius:50%;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.close-btn:hover{background-color:#e2e8f0;color:var(--text-primary)}.popup-content{flex:1;overflow-y:auto;position:relative}.content-padded{padding:24px}.search-container{padding:16px 24px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);position:sticky;top:0;z-index:10}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-wrapper svg.search-icon{position:absolute;left:12px;color:var(--text-secondary);z-index:1}.search-input{width:100%;padding:12px 110px 12px 40px;border-radius:10px;border:1px solid var(--border-soft);font-size:.95rem;background:var(--bg-secondary);color:var(--text-primary);transition:all .2s}.search-input:focus{outline:none;background:var(--bg-primary);border-color:var(--accent);box-shadow:0 0 0 3px #3b82f61a}.input-actions-wrapper{position:absolute;right:8px;display:flex;align-items:center;gap:8px}.icon-btn-clear{background:transparent;border:none;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;padding:4px;cursor:pointer;border-radius:4px}.icon-btn-clear:hover{background-color:var(--border-soft);color:var(--text-primary)}.info-banner{display:flex;align-items:center;gap:12px;margin:12px 24px;padding:12px 16px;background:var(--primary-lite);color:var(--primary);border-radius:8px;font-size:.85rem;font-weight:500;border:1px solid var(--border-color)}.info-banner svg{flex-shrink:0;opacity:.8}.btn-sm{padding:4px 12px;font-size:.85rem;height:32px}.popup-row{display:flex;align-items:flex-start;gap:16px;padding:16px 24px;border-bottom:1px solid var(--border-soft);cursor:pointer;transition:background-color .2s}.popup-row:hover{background-color:var(--bg-secondary)}.popup-row:hover .row-actions{opacity:1}.popup-row:last-child{border-bottom:none}.row-icon-container{flex-shrink:0;margin-top:2px;color:var(--text-secondary)}.row-content{flex:1;min-width:0}.row-title{font-size:.95rem;font-weight:500;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.row-meta{font-size:.8rem;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.row-actions{opacity:0;transition:opacity .2s;display:flex;align-items:center}.action-btn{background:transparent;border:none;color:var(--text-secondary);padding:6px;border-radius:6px;cursor:pointer;transition:all .2s}.action-btn:hover{background-color:var(--danger-bg);color:var(--danger)}.dialog-footer{padding:16px 24px;border-top:1px solid var(--border-soft);background:var(--bg-primary);display:flex;justify-content:flex-end;gap:12px}.btn{padding:8px 16px;border-radius:8px;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.btn-secondary{background:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-soft)}.btn-secondary:hover{background:#e2e8f0}.btn-primary{background:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover)}.btn-danger{background:var(--danger-bg);color:var(--danger)}.btn-danger:hover{background:#fee2e2}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-primary{color:var(--accent)}.mb-4{margin-bottom:1rem}.select-text{user-select:text;-webkit-user-select:text}.definition-group{margin-bottom:24px}.pos-tag{display:inline-block;font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent);background:#3b82f61a;padding:4px 8px;border-radius:6px;margin-bottom:12px}.def-item{padding-bottom:16px;margin-bottom:16px;border-bottom:1px dashed var(--border-soft)}.def-item:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.def-text{font-size:.95rem;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.def-example{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding-left:12px;border-left:2px solid var(--border-soft)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--text-secondary);text-align:center;font-style:italic}.progress-container{width:100px;height:6px;background:var(--bg-secondary);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:var(--accent);border-radius:3px}.line-clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}:host::ng-deep .p-tabview-nav{background:var(--bg-primary)!important;border-bottom:1px solid var(--border-soft)!important;justify-content:center;padding:0}:host::ng-deep .p-tabview-nav li .p-tabview-nav-link{background:transparent!important;border:none!important;color:var(--text-secondary)!important;font-weight:500;padding:16px 20px!important;box-shadow:none!important;font-size:.95rem}:host::ng-deep .p-tabview-nav li.p-highlight .p-tabview-nav-link{color:var(--accent)!important;border-bottom:2px solid var(--accent)!important}:host::ng-deep .p-tabview-panels{padding:0!important;background:transparent!important}:host::ng-deep .highlight-key{color:var(--danger)!important;font-weight:700;background-color:#ef444426;padding:0 4px;border-radius:3px}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i8.TabView, selector: "p-tabView", inputs: ["style", "styleClass", "controlClose", "scrollable", "activeIndex", "selectOnFocus", "nextButtonAriaLabel", "prevButtonAriaLabel", "autoHideButtons", "tabindex"], outputs: ["onChange", "onClose", "activeIndexChange"] }, { kind: "component", type: i8.TabPanel, selector: "p-tabPanel", inputs: ["closable", "headerStyle", "headerStyleClass", "cache", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "selected", "disabled", "header", "leftIcon", "rightIcon"] }, { kind: "component", type: NoDataFoundComponent, selector: "app-no-data-found", inputs: ["message"] }, { kind: "component", type: SkeletonLoaderComponent, selector: "app-skeleton-loader", inputs: ["count", "type"] }] });
|
|
733
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubCommonPopupComponent, deps: [{ token: i1$3.DomSanitizer }, { token: HttpApiService }, { token: NotificationService }, { token: CustomDialogService }, { token: CustomDialogRef }, { token: SharedService }, { token: EpubReaderService }, { token: SharedService }], target: i0.ɵɵFactoryTarget.Component });
|
|
734
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: EpubCommonPopupComponent, isStandalone: false, selector: "app-epub-common-popup", ngImport: i0, template: "<!-- Template 1: Single Note View -->\n@if (dialogRef.data.template == 1) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">Note Details</h2>\n <div class=\"header-actions\">\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"popup-content content-padded\">\n <div class=\"inner-html-class text-lg text-primary mb-6\" [innerHTML]=\"htmlString\"></div>\n </div>\n\n <div class=\"dialog-footer\">\n <button class=\"btn btn-secondary\" (click)=\"close()\">\n {{ htmlStaticText.btnText.cancel }}\n </button>\n <button class=\"btn btn-primary\" (click)=\"editNote()\">\n {{ htmlStaticText.btnText.edit }}\n </button>\n <button class=\"btn btn-danger\" (click)=\"deleteAnnotations(1, this.singlenoteDetails.id)\">\n {{ htmlStaticText.btnText.remove }}\n </button>\n </div>\n</div>\n}\n\n<!-- Template 2: Highlights & Notes Tabs -->\n@if (dialogRef.data.template == 2) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16.035 2.977l4.988 4.989-12.022 12.021H4v-4.988L16.035 2.977z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Highlights & Notes\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div class=\"custom-tabs\">\n <div class=\"tab-header\">\n <button class=\"tab-btn\" [class.active]=\"activeTab === 0\" (click)=\"setActiveTab(0)\">Highlights</button>\n <button class=\"tab-btn\" [class.active]=\"activeTab === 1\" (click)=\"setActiveTab(1)\">Notes</button>\n </div>\n\n <div class=\"tab-panels\">\n <!-- Highlights Tab -->\n <div class=\"tab-panel\" *ngIf=\"activeTab === 0\">\n <div *ngIf=\"isLoading; else highlightsContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #highlightsContent>\n <div *ngIf=\"!notesandHighlights?.length; else noteList\" class=\"empty-state\">\n {{ htmlStaticText.htmlText.nohighlightsavailable }}\n </div>\n\n <ng-template #noteList>\n <div *ngFor=\"let note of notesandHighlights\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <div class=\"w-2 h-8 rounded-full\" [style.background-color]=\"note.colorCode\"\n style=\"width: 4px; height: 32px; border-radius: 4px;\"></div>\n </div>\n\n <div class=\"row-content\" (click)=\"gotoLocation(note.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ note.annotatedNotes }}</div>\n <div class=\"row-meta\">\n <span>Page {{ note.pageNumber || 'N/A' }}</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(2, note.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </div>\n\n <!-- Notes Tab -->\n <div class=\"tab-panel\" *ngIf=\"activeTab === 1\">\n <div *ngIf=\"isLoading; else notesContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #notesContent>\n <div *ngIf=\"!notes?.length; else notesList\" class=\"empty-state\">\n No notes available.\n </div>\n\n <ng-template #notesList>\n <div *ngFor=\"let item of notes\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div class=\"row-content\" (click)=\"openNote(item)\">\n <div class=\"row-title line-clamp\"\n [innerHTML]=\"item.annotatedNotes ? item.annotatedNotes : item.customNotes\"></div>\n </div>\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(1, item.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n\n<!-- Template 3: Search -->\n@if (dialogRef.data.template == 3) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Search\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <svg class=\"search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <input [(ngModel)]=\"searchKey\" (keyup.enter)=\"updateSearchKey()\" type=\"text\" placeholder=\"Search in book...\"\n class=\"search-input\" autofocus />\n <div class=\"input-actions-wrapper\">\n <button *ngIf=\"searchKey\" class=\"icon-btn-clear\" (click)=\"clearSearch()\" title=\"Clear search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button class=\"btn btn-primary btn-sm\" (click)=\"updateSearchKey()\">\n Search\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"searchCharaSmall\" class=\"info-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\" />\n </svg>\n <span>{{ staticText.validationText.atleastThreeChara }}</span>\n </div>\n\n <div *ngIf=\"isSearchDataAvailable; else searchResults\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #searchResults>\n <div *ngIf=\"searchKey?.length && searchData && !searchData?.length\" class=\"empty-state\">\n <app-no-data-found></app-no-data-found>\n </div>\n\n <div class=\"search-results\">\n <div *ngFor=\"let item of searchData\" class=\"popup-row\" (click)=\"clickSearchItem(item.cfi)\">\n <div class=\"row-content\">\n <div class=\"row-title\" [innerHTML]=\"item.highlightedSentence\"></div>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 4: Bookmarks -->\n@if (dialogRef.data.template == 4) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Bookmarks\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"isLoading; else bookmarkContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #bookmarkContent>\n <div *ngIf=\"!bookMarkList || bookMarkList.length === 0\" class=\"empty-state\">\n No bookmarks yet.\n </div>\n\n <div *ngIf=\"bookMarkList && bookMarkList.length > 0\">\n <div *ngFor=\"let bookmark of bookMarkList\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <!-- Filled Bookmark Icon for list -->\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"\n [style.color]=\"bookmark.colorCode || '#3b82f6'\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" />\n </svg>\n </div>\n\n <div class=\"row-content\" (click)=\"closePopup(bookmark.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ bookmark.annotatedNotes || 'Bookmark' }}</div>\n <div class=\"row-meta mt-2\">\n <div class=\"progress-container\">\n <div class=\"progress-fill\" [style.width.%]=\"bookmark.customNotes\"></div>\n </div>\n <span>{{ bookmark.customNotes }}%</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(4, bookmark.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 5: Definitions -->\n@if (dialogRef.data.template == 5) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 19.5A2.5 2.5 0 016.5 17H20\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Definition\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content content-padded\">\n <h3 class=\"text-xl font-bold text-primary mb-4 select-text\">\n \"{{ dialogRef.data.selectedText }}\"\n </h3>\n\n <div *ngIf=\"isLoading; else defsContent\">\n <app-skeleton-loader [count]=\"3\" type=\"text\"></app-skeleton-loader>\n </div>\n\n <ng-template #defsContent>\n <div *ngIf=\"Definition?.length > 0; else noDefs\">\n <div *ngFor=\"let entry of Definition\" class=\"definition-group\">\n <span class=\"pos-tag\">{{ entry.partOfSpeech }}</span>\n\n <div *ngFor=\"let def of entry.definitions\" class=\"def-item\">\n <p class=\"def-text\">{{ def.definition }}</p>\n <p *ngIf=\"def.example\" class=\"def-example\">\"{{ def.example }}\"</p>\n </div>\n </div>\n </div>\n\n <ng-template #noDefs>\n <div class=\"empty-state\">No definitions found.</div>\n </ng-template>\n </ng-template>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #64748b;--border-soft: #e2e8f0;--accent: #3b82f6;--accent-hover: #2563eb;--danger: #ef4444;--danger-bg: #fef2f2}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-soft: #334155;--accent: #60a5fa;--accent-hover: #3b82f6;--danger: #f87171;--danger-bg: #450a0a}.popup-container{display:flex;flex-direction:column;width:500px;height:600px;max-width:95vw;max-height:85vh;background:var(--bg-primary);color:var(--text-primary);border-radius:16px;overflow:hidden;box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;background:var(--bg-secondary);border-bottom:1px solid var(--border-soft)}.popup-title{font-size:1.15rem;font-weight:600;color:var(--text-primary);display:flex;align-items:center;gap:12px;margin:0}.popup-title svg{color:var(--text-secondary)}.close-btn{background:transparent;border:none;color:var(--text-secondary);padding:8px;border-radius:50%;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.close-btn:hover{background-color:#e2e8f0;color:var(--text-primary)}.popup-content{flex:1;overflow-y:auto;position:relative}.content-padded{padding:24px}.search-container{padding:16px 24px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);position:sticky;top:0;z-index:10}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-wrapper svg.search-icon{position:absolute;left:12px;color:var(--text-secondary);z-index:1}.search-input{width:100%;padding:12px 110px 12px 40px;border-radius:10px;border:1px solid var(--border-soft);font-size:.95rem;background:var(--bg-secondary);color:var(--text-primary);transition:all .2s}.search-input:focus{outline:none;background:var(--bg-primary);border-color:var(--accent);box-shadow:0 0 0 3px #3b82f61a}.input-actions-wrapper{position:absolute;right:8px;display:flex;align-items:center;gap:8px}.icon-btn-clear{background:transparent;border:none;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;padding:4px;cursor:pointer;border-radius:4px}.icon-btn-clear:hover{background-color:var(--border-soft);color:var(--text-primary)}.info-banner{display:flex;align-items:center;gap:12px;margin:12px 24px;padding:12px 16px;background:var(--primary-lite);color:var(--primary);border-radius:8px;font-size:.85rem;font-weight:500;border:1px solid var(--border-color)}.info-banner svg{flex-shrink:0;opacity:.8}.btn-sm{padding:4px 12px;font-size:.85rem;height:32px}.popup-row{display:flex;align-items:flex-start;gap:16px;padding:16px 24px;border-bottom:1px solid var(--border-soft);cursor:pointer;transition:background-color .2s}.popup-row:hover{background-color:var(--bg-secondary)}.popup-row:hover .row-actions{opacity:1}.popup-row:last-child{border-bottom:none}.row-icon-container{flex-shrink:0;margin-top:2px;color:var(--text-secondary)}.row-content{flex:1;min-width:0}.row-title{font-size:.95rem;font-weight:500;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.row-meta{font-size:.8rem;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.row-actions{opacity:0;transition:opacity .2s;display:flex;align-items:center}.action-btn{background:transparent;border:none;color:var(--text-secondary);padding:6px;border-radius:6px;cursor:pointer;transition:all .2s}.action-btn:hover{background-color:var(--danger-bg);color:var(--danger)}.dialog-footer{padding:16px 24px;border-top:1px solid var(--border-soft);background:var(--bg-primary);display:flex;justify-content:flex-end;gap:12px}.btn{padding:8px 16px;border-radius:8px;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.btn-secondary{background:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-soft)}.btn-secondary:hover{background:#e2e8f0}.btn-primary{background:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover)}.btn-danger{background:var(--danger-bg);color:var(--danger)}.btn-danger:hover{background:#fee2e2}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-primary{color:var(--accent)}.mb-4{margin-bottom:1rem}.select-text{user-select:text;-webkit-user-select:text}.definition-group{margin-bottom:24px}.pos-tag{display:inline-block;font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent);background:#3b82f61a;padding:4px 8px;border-radius:6px;margin-bottom:12px}.def-item{padding-bottom:16px;margin-bottom:16px;border-bottom:1px dashed var(--border-soft)}.def-item:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.def-text{font-size:.95rem;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.def-example{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding-left:12px;border-left:2px solid var(--border-soft)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--text-secondary);text-align:center;font-style:italic}.progress-container{width:100px;height:6px;background:var(--bg-secondary);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:var(--accent);border-radius:3px}.line-clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.custom-tabs{display:flex;flex-direction:column;height:100%}.tab-header{display:flex;justify-content:center;gap:32px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);padding:0 24px}.tab-btn{background:transparent;border:none;padding:16px 4px;font-size:.95rem;font-weight:500;color:var(--text-secondary);cursor:pointer;position:relative;transition:all .2s}.tab-btn:after{content:\"\";position:absolute;bottom:-1px;left:0;width:100%;height:2px;background:transparent;transition:all .2s}.tab-btn:hover{color:var(--text-primary)}.tab-btn.active{color:var(--accent)}.tab-btn.active:after{background:var(--accent)}.tab-panels{flex:1;overflow-y:auto}.tab-panel{animation:fade-in .3s ease-out}@keyframes fade-in{0%{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}:host::ng-deep .highlight-key{color:var(--danger)!important;font-weight:700;background-color:#ef444426;padding:0 4px;border-radius:3px}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: NoDataFoundComponent, selector: "app-no-data-found", inputs: ["message"] }, { kind: "component", type: SkeletonLoaderComponent, selector: "app-skeleton-loader", inputs: ["count", "type"] }] });
|
|
728
735
|
}
|
|
729
736
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubCommonPopupComponent, decorators: [{
|
|
730
737
|
type: Component,
|
|
731
|
-
args: [{ selector: 'app-epub-common-popup', standalone: false, template: "<!-- Template 1: Single Note View -->\n@if (dialogRef.data.template == 1) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">Note Details</h2>\n <div class=\"header-actions\">\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"popup-content content-padded\">\n <div class=\"inner-html-class text-lg text-primary mb-6\" [innerHTML]=\"htmlString\"></div>\n </div>\n\n <div class=\"dialog-footer\">\n <button class=\"btn btn-secondary\" (click)=\"close()\">\n {{ htmlStaticText.btnText.cancel }}\n </button>\n <button class=\"btn btn-primary\" (click)=\"editNote()\">\n {{ htmlStaticText.btnText.edit }}\n </button>\n <button class=\"btn btn-danger\" (click)=\"deleteAnnotations(1, this.singlenoteDetails.id)\">\n {{ htmlStaticText.btnText.remove }}\n </button>\n </div>\n</div>\n}\n\n<!-- Template 2: Highlights & Notes Tabs -->\n@if (dialogRef.data.template == 2) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16.035 2.977l4.988 4.989-12.022 12.021H4v-4.988L16.035 2.977z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Highlights & Notes\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <p-tabView (onChange)=\"onTabChange($event)\">\n\n <!-- Highlights Tab -->\n <p-tabPanel header=\"Highlights\">\n <div *ngIf=\"isLoading; else highlightsContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #highlightsContent>\n <div *ngIf=\"!notesandHighlights?.length; else noteList\" class=\"empty-state\">\n {{ htmlStaticText.htmlText.nohighlightsavailable }}\n </div>\n\n <ng-template #noteList>\n <div *ngFor=\"let note of notesandHighlights\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <div class=\"w-2 h-8 rounded-full\" [style.background-color]=\"note.colorCode\"\n style=\"width: 4px; height: 32px; border-radius: 4px;\"></div>\n </div>\n\n <div class=\"row-content\" (click)=\"gotoLocation(note.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ note.annotatedNotes }}</div>\n <div class=\"row-meta\">\n <span>Page {{ note.pageNumber || 'N/A' }}</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(2, note.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </p-tabPanel>\n\n <!-- Notes Tab -->\n <p-tabPanel header=\"Notes\">\n <div *ngIf=\"isLoading; else notesContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #notesContent>\n <div *ngIf=\"!notes?.length; else notesList\" class=\"empty-state\">\n No notes available.\n </div>\n\n <ng-template #notesList>\n <div *ngFor=\"let item of notes\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div class=\"row-content\" (click)=\"openNote(item)\">\n <div class=\"row-title line-clamp\"\n [innerHTML]=\"item.annotatedNotes ? item.annotatedNotes : item.customNotes\"></div>\n </div>\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(1, item.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </p-tabPanel>\n\n </p-tabView>\n </div>\n</div>\n}\n\n<!-- Template 3: Search -->\n@if (dialogRef.data.template == 3) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Search\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <svg class=\"search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <input [(ngModel)]=\"searchKey\" (keyup.enter)=\"updateSearchKey()\" type=\"text\" placeholder=\"Search in book...\"\n class=\"search-input\" autofocus />\n <div class=\"input-actions-wrapper\">\n <button *ngIf=\"searchKey\" class=\"icon-btn-clear\" (click)=\"clearSearch()\" title=\"Clear search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button class=\"btn btn-primary btn-sm\" (click)=\"updateSearchKey()\">\n Search\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"searchCharaSmall\" class=\"info-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\" />\n </svg>\n <span>{{ staticText.validationText.atleastThreeChara }}</span>\n </div>\n\n <div *ngIf=\"isSearchDataAvailable; else searchResults\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #searchResults>\n <div *ngIf=\"searchKey?.length && searchData && !searchData?.length\" class=\"empty-state\">\n <app-no-data-found></app-no-data-found>\n </div>\n\n <div class=\"search-results\">\n <div *ngFor=\"let item of searchData\" class=\"popup-row\" (click)=\"clickSearchItem(item.cfi)\">\n <div class=\"row-content\">\n <div class=\"row-title\" [innerHTML]=\"item.highlightedSentence\"></div>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 4: Bookmarks -->\n@if (dialogRef.data.template == 4) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Bookmarks\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"isLoading; else bookmarkContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #bookmarkContent>\n <div *ngIf=\"!bookMarkList || bookMarkList.length === 0\" class=\"empty-state\">\n No bookmarks yet.\n </div>\n\n <div *ngIf=\"bookMarkList && bookMarkList.length > 0\">\n <div *ngFor=\"let bookmark of bookMarkList\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <!-- Filled Bookmark Icon for list -->\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"\n [style.color]=\"bookmark.colorCode || '#3b82f6'\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" />\n </svg>\n </div>\n\n <div class=\"row-content\" (click)=\"closePopup(bookmark.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ bookmark.annotatedNotes || 'Bookmark' }}</div>\n <div class=\"row-meta mt-2\">\n <div class=\"progress-container\">\n <div class=\"progress-fill\" [style.width.%]=\"bookmark.customNotes\"></div>\n </div>\n <span>{{ bookmark.customNotes }}%</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(4, bookmark.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 5: Definitions -->\n@if (dialogRef.data.template == 5) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 19.5A2.5 2.5 0 016.5 17H20\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Definition\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content content-padded\">\n <h3 class=\"text-xl font-bold text-primary mb-4 select-text\">\n \"{{ dialogRef.data.selectedText }}\"\n </h3>\n\n <div *ngIf=\"isLoading; else defsContent\">\n <app-skeleton-loader [count]=\"3\" type=\"text\"></app-skeleton-loader>\n </div>\n\n <ng-template #defsContent>\n <div *ngIf=\"Definition?.length > 0; else noDefs\">\n <div *ngFor=\"let entry of Definition\" class=\"definition-group\">\n <span class=\"pos-tag\">{{ entry.partOfSpeech }}</span>\n\n <div *ngFor=\"let def of entry.definitions\" class=\"def-item\">\n <p class=\"def-text\">{{ def.definition }}</p>\n <p *ngIf=\"def.example\" class=\"def-example\">\"{{ def.example }}\"</p>\n </div>\n </div>\n </div>\n\n <ng-template #noDefs>\n <div class=\"empty-state\">No definitions found.</div>\n </ng-template>\n </ng-template>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #64748b;--border-soft: #e2e8f0;--accent: #3b82f6;--accent-hover: #2563eb;--danger: #ef4444;--danger-bg: #fef2f2}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-soft: #334155;--accent: #60a5fa;--accent-hover: #3b82f6;--danger: #f87171;--danger-bg: #450a0a}.popup-container{display:flex;flex-direction:column;width:500px;height:600px;max-width:95vw;max-height:85vh;background:var(--bg-primary);color:var(--text-primary);border-radius:16px;overflow:hidden;box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;background:var(--bg-secondary);border-bottom:1px solid var(--border-soft)}.popup-title{font-size:1.15rem;font-weight:600;color:var(--text-primary);display:flex;align-items:center;gap:12px;margin:0}.popup-title svg{color:var(--text-secondary)}.close-btn{background:transparent;border:none;color:var(--text-secondary);padding:8px;border-radius:50%;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.close-btn:hover{background-color:#e2e8f0;color:var(--text-primary)}.popup-content{flex:1;overflow-y:auto;position:relative}.content-padded{padding:24px}.search-container{padding:16px 24px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);position:sticky;top:0;z-index:10}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-wrapper svg.search-icon{position:absolute;left:12px;color:var(--text-secondary);z-index:1}.search-input{width:100%;padding:12px 110px 12px 40px;border-radius:10px;border:1px solid var(--border-soft);font-size:.95rem;background:var(--bg-secondary);color:var(--text-primary);transition:all .2s}.search-input:focus{outline:none;background:var(--bg-primary);border-color:var(--accent);box-shadow:0 0 0 3px #3b82f61a}.input-actions-wrapper{position:absolute;right:8px;display:flex;align-items:center;gap:8px}.icon-btn-clear{background:transparent;border:none;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;padding:4px;cursor:pointer;border-radius:4px}.icon-btn-clear:hover{background-color:var(--border-soft);color:var(--text-primary)}.info-banner{display:flex;align-items:center;gap:12px;margin:12px 24px;padding:12px 16px;background:var(--primary-lite);color:var(--primary);border-radius:8px;font-size:.85rem;font-weight:500;border:1px solid var(--border-color)}.info-banner svg{flex-shrink:0;opacity:.8}.btn-sm{padding:4px 12px;font-size:.85rem;height:32px}.popup-row{display:flex;align-items:flex-start;gap:16px;padding:16px 24px;border-bottom:1px solid var(--border-soft);cursor:pointer;transition:background-color .2s}.popup-row:hover{background-color:var(--bg-secondary)}.popup-row:hover .row-actions{opacity:1}.popup-row:last-child{border-bottom:none}.row-icon-container{flex-shrink:0;margin-top:2px;color:var(--text-secondary)}.row-content{flex:1;min-width:0}.row-title{font-size:.95rem;font-weight:500;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.row-meta{font-size:.8rem;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.row-actions{opacity:0;transition:opacity .2s;display:flex;align-items:center}.action-btn{background:transparent;border:none;color:var(--text-secondary);padding:6px;border-radius:6px;cursor:pointer;transition:all .2s}.action-btn:hover{background-color:var(--danger-bg);color:var(--danger)}.dialog-footer{padding:16px 24px;border-top:1px solid var(--border-soft);background:var(--bg-primary);display:flex;justify-content:flex-end;gap:12px}.btn{padding:8px 16px;border-radius:8px;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.btn-secondary{background:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-soft)}.btn-secondary:hover{background:#e2e8f0}.btn-primary{background:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover)}.btn-danger{background:var(--danger-bg);color:var(--danger)}.btn-danger:hover{background:#fee2e2}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-primary{color:var(--accent)}.mb-4{margin-bottom:1rem}.select-text{user-select:text;-webkit-user-select:text}.definition-group{margin-bottom:24px}.pos-tag{display:inline-block;font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent);background:#3b82f61a;padding:4px 8px;border-radius:6px;margin-bottom:12px}.def-item{padding-bottom:16px;margin-bottom:16px;border-bottom:1px dashed var(--border-soft)}.def-item:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.def-text{font-size:.95rem;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.def-example{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding-left:12px;border-left:2px solid var(--border-soft)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--text-secondary);text-align:center;font-style:italic}.progress-container{width:100px;height:6px;background:var(--bg-secondary);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:var(--accent);border-radius:3px}.line-clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}:host::ng-deep .p-tabview-nav{background:var(--bg-primary)!important;border-bottom:1px solid var(--border-soft)!important;justify-content:center;padding:0}:host::ng-deep .p-tabview-nav li .p-tabview-nav-link{background:transparent!important;border:none!important;color:var(--text-secondary)!important;font-weight:500;padding:16px 20px!important;box-shadow:none!important;font-size:.95rem}:host::ng-deep .p-tabview-nav li.p-highlight .p-tabview-nav-link{color:var(--accent)!important;border-bottom:2px solid var(--accent)!important}:host::ng-deep .p-tabview-panels{padding:0!important;background:transparent!important}:host::ng-deep .highlight-key{color:var(--danger)!important;font-weight:700;background-color:#ef444426;padding:0 4px;border-radius:3px}\n"] }]
|
|
732
|
-
}], ctorParameters: () => [{ type: i1$3.DomSanitizer }, { type: HttpApiService }, { type:
|
|
738
|
+
args: [{ selector: 'app-epub-common-popup', standalone: false, template: "<!-- Template 1: Single Note View -->\n@if (dialogRef.data.template == 1) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">Note Details</h2>\n <div class=\"header-actions\">\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"popup-content content-padded\">\n <div class=\"inner-html-class text-lg text-primary mb-6\" [innerHTML]=\"htmlString\"></div>\n </div>\n\n <div class=\"dialog-footer\">\n <button class=\"btn btn-secondary\" (click)=\"close()\">\n {{ htmlStaticText.btnText.cancel }}\n </button>\n <button class=\"btn btn-primary\" (click)=\"editNote()\">\n {{ htmlStaticText.btnText.edit }}\n </button>\n <button class=\"btn btn-danger\" (click)=\"deleteAnnotations(1, this.singlenoteDetails.id)\">\n {{ htmlStaticText.btnText.remove }}\n </button>\n </div>\n</div>\n}\n\n<!-- Template 2: Highlights & Notes Tabs -->\n@if (dialogRef.data.template == 2) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16.035 2.977l4.988 4.989-12.022 12.021H4v-4.988L16.035 2.977z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Highlights & Notes\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div class=\"custom-tabs\">\n <div class=\"tab-header\">\n <button class=\"tab-btn\" [class.active]=\"activeTab === 0\" (click)=\"setActiveTab(0)\">Highlights</button>\n <button class=\"tab-btn\" [class.active]=\"activeTab === 1\" (click)=\"setActiveTab(1)\">Notes</button>\n </div>\n\n <div class=\"tab-panels\">\n <!-- Highlights Tab -->\n <div class=\"tab-panel\" *ngIf=\"activeTab === 0\">\n <div *ngIf=\"isLoading; else highlightsContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #highlightsContent>\n <div *ngIf=\"!notesandHighlights?.length; else noteList\" class=\"empty-state\">\n {{ htmlStaticText.htmlText.nohighlightsavailable }}\n </div>\n\n <ng-template #noteList>\n <div *ngFor=\"let note of notesandHighlights\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <div class=\"w-2 h-8 rounded-full\" [style.background-color]=\"note.colorCode\"\n style=\"width: 4px; height: 32px; border-radius: 4px;\"></div>\n </div>\n\n <div class=\"row-content\" (click)=\"gotoLocation(note.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ note.annotatedNotes }}</div>\n <div class=\"row-meta\">\n <span>Page {{ note.pageNumber || 'N/A' }}</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(2, note.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </div>\n\n <!-- Notes Tab -->\n <div class=\"tab-panel\" *ngIf=\"activeTab === 1\">\n <div *ngIf=\"isLoading; else notesContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n <ng-template #notesContent>\n <div *ngIf=\"!notes?.length; else notesList\" class=\"empty-state\">\n No notes available.\n </div>\n\n <ng-template #notesList>\n <div *ngFor=\"let item of notes\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div class=\"row-content\" (click)=\"openNote(item)\">\n <div class=\"row-title line-clamp\"\n [innerHTML]=\"item.annotatedNotes ? item.annotatedNotes : item.customNotes\"></div>\n </div>\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(1, item.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </ng-template>\n </ng-template>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n\n<!-- Template 3: Search -->\n@if (dialogRef.data.template == 3) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Search\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <svg class=\"search-icon\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"2\">\n <path d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <input [(ngModel)]=\"searchKey\" (keyup.enter)=\"updateSearchKey()\" type=\"text\" placeholder=\"Search in book...\"\n class=\"search-input\" autofocus />\n <div class=\"input-actions-wrapper\">\n <button *ngIf=\"searchKey\" class=\"icon-btn-clear\" (click)=\"clearSearch()\" title=\"Clear search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button class=\"btn btn-primary btn-sm\" (click)=\"updateSearchKey()\">\n Search\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"searchCharaSmall\" class=\"info-banner\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\" />\n </svg>\n <span>{{ staticText.validationText.atleastThreeChara }}</span>\n </div>\n\n <div *ngIf=\"isSearchDataAvailable; else searchResults\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #searchResults>\n <div *ngIf=\"searchKey?.length && searchData && !searchData?.length\" class=\"empty-state\">\n <app-no-data-found></app-no-data-found>\n </div>\n\n <div class=\"search-results\">\n <div *ngFor=\"let item of searchData\" class=\"popup-row\" (click)=\"clickSearchItem(item.cfi)\">\n <div class=\"row-content\">\n <div class=\"row-title\" [innerHTML]=\"item.highlightedSentence\"></div>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 4: Bookmarks -->\n@if (dialogRef.data.template == 4) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n Bookmarks\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content\">\n <div *ngIf=\"isLoading; else bookmarkContent\">\n <app-skeleton-loader [count]=\"4\" type=\"list\"></app-skeleton-loader>\n </div>\n\n <ng-template #bookmarkContent>\n <div *ngIf=\"!bookMarkList || bookMarkList.length === 0\" class=\"empty-state\">\n No bookmarks yet.\n </div>\n\n <div *ngIf=\"bookMarkList && bookMarkList.length > 0\">\n <div *ngFor=\"let bookmark of bookMarkList\" class=\"popup-row\">\n <div class=\"row-icon-container\">\n <!-- Filled Bookmark Icon for list -->\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"\n [style.color]=\"bookmark.colorCode || '#3b82f6'\">\n <path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" />\n </svg>\n </div>\n\n <div class=\"row-content\" (click)=\"closePopup(bookmark.cfiLocation)\">\n <div class=\"row-title line-clamp\">{{ bookmark.annotatedNotes || 'Bookmark' }}</div>\n <div class=\"row-meta mt-2\">\n <div class=\"progress-container\">\n <div class=\"progress-fill\" [style.width.%]=\"bookmark.customNotes\"></div>\n </div>\n <span>{{ bookmark.customNotes }}%</span>\n </div>\n </div>\n\n <div class=\"row-actions\">\n <button class=\"action-btn\" (click)=\"deleteAnnotations(4, bookmark.id)\" title=\"Remove\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </ng-template>\n </div>\n</div>\n}\n\n<!-- Template 5: Definitions -->\n@if (dialogRef.data.template == 5) {\n<div class=\"popup-container\">\n <div class=\"popup-header\">\n <h2 class=\"popup-title\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 19.5A2.5 2.5 0 016.5 17H20\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n Definition\n </h2>\n <button class=\"close-btn\" (click)=\"close()\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n\n <div class=\"popup-content content-padded\">\n <h3 class=\"text-xl font-bold text-primary mb-4 select-text\">\n \"{{ dialogRef.data.selectedText }}\"\n </h3>\n\n <div *ngIf=\"isLoading; else defsContent\">\n <app-skeleton-loader [count]=\"3\" type=\"text\"></app-skeleton-loader>\n </div>\n\n <ng-template #defsContent>\n <div *ngIf=\"Definition?.length > 0; else noDefs\">\n <div *ngFor=\"let entry of Definition\" class=\"definition-group\">\n <span class=\"pos-tag\">{{ entry.partOfSpeech }}</span>\n\n <div *ngFor=\"let def of entry.definitions\" class=\"def-item\">\n <p class=\"def-text\">{{ def.definition }}</p>\n <p *ngIf=\"def.example\" class=\"def-example\">\"{{ def.example }}\"</p>\n </div>\n </div>\n </div>\n\n <ng-template #noDefs>\n <div class=\"empty-state\">No definitions found.</div>\n </ng-template>\n </ng-template>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #64748b;--border-soft: #e2e8f0;--accent: #3b82f6;--accent-hover: #2563eb;--danger: #ef4444;--danger-bg: #fef2f2}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-soft: #334155;--accent: #60a5fa;--accent-hover: #3b82f6;--danger: #f87171;--danger-bg: #450a0a}.popup-container{display:flex;flex-direction:column;width:500px;height:600px;max-width:95vw;max-height:85vh;background:var(--bg-primary);color:var(--text-primary);border-radius:16px;overflow:hidden;box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}.popup-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;background:var(--bg-secondary);border-bottom:1px solid var(--border-soft)}.popup-title{font-size:1.15rem;font-weight:600;color:var(--text-primary);display:flex;align-items:center;gap:12px;margin:0}.popup-title svg{color:var(--text-secondary)}.close-btn{background:transparent;border:none;color:var(--text-secondary);padding:8px;border-radius:50%;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.close-btn:hover{background-color:#e2e8f0;color:var(--text-primary)}.popup-content{flex:1;overflow-y:auto;position:relative}.content-padded{padding:24px}.search-container{padding:16px 24px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);position:sticky;top:0;z-index:10}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-wrapper svg.search-icon{position:absolute;left:12px;color:var(--text-secondary);z-index:1}.search-input{width:100%;padding:12px 110px 12px 40px;border-radius:10px;border:1px solid var(--border-soft);font-size:.95rem;background:var(--bg-secondary);color:var(--text-primary);transition:all .2s}.search-input:focus{outline:none;background:var(--bg-primary);border-color:var(--accent);box-shadow:0 0 0 3px #3b82f61a}.input-actions-wrapper{position:absolute;right:8px;display:flex;align-items:center;gap:8px}.icon-btn-clear{background:transparent;border:none;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;padding:4px;cursor:pointer;border-radius:4px}.icon-btn-clear:hover{background-color:var(--border-soft);color:var(--text-primary)}.info-banner{display:flex;align-items:center;gap:12px;margin:12px 24px;padding:12px 16px;background:var(--primary-lite);color:var(--primary);border-radius:8px;font-size:.85rem;font-weight:500;border:1px solid var(--border-color)}.info-banner svg{flex-shrink:0;opacity:.8}.btn-sm{padding:4px 12px;font-size:.85rem;height:32px}.popup-row{display:flex;align-items:flex-start;gap:16px;padding:16px 24px;border-bottom:1px solid var(--border-soft);cursor:pointer;transition:background-color .2s}.popup-row:hover{background-color:var(--bg-secondary)}.popup-row:hover .row-actions{opacity:1}.popup-row:last-child{border-bottom:none}.row-icon-container{flex-shrink:0;margin-top:2px;color:var(--text-secondary)}.row-content{flex:1;min-width:0}.row-title{font-size:.95rem;font-weight:500;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.row-meta{font-size:.8rem;color:var(--text-secondary);display:flex;align-items:center;gap:8px}.row-actions{opacity:0;transition:opacity .2s;display:flex;align-items:center}.action-btn{background:transparent;border:none;color:var(--text-secondary);padding:6px;border-radius:6px;cursor:pointer;transition:all .2s}.action-btn:hover{background-color:var(--danger-bg);color:var(--danger)}.dialog-footer{padding:16px 24px;border-top:1px solid var(--border-soft);background:var(--bg-primary);display:flex;justify-content:flex-end;gap:12px}.btn{padding:8px 16px;border-radius:8px;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid transparent}.btn-secondary{background:var(--bg-secondary);color:var(--text-primary);border-color:var(--border-soft)}.btn-secondary:hover{background:#e2e8f0}.btn-primary{background:var(--accent);color:#fff}.btn-primary:hover{background:var(--accent-hover)}.btn-danger{background:var(--danger-bg);color:var(--danger)}.btn-danger:hover{background:#fee2e2}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-primary{color:var(--accent)}.mb-4{margin-bottom:1rem}.select-text{user-select:text;-webkit-user-select:text}.definition-group{margin-bottom:24px}.pos-tag{display:inline-block;font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent);background:#3b82f61a;padding:4px 8px;border-radius:6px;margin-bottom:12px}.def-item{padding-bottom:16px;margin-bottom:16px;border-bottom:1px dashed var(--border-soft)}.def-item:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.def-text{font-size:.95rem;color:var(--text-primary);line-height:1.5;margin-bottom:4px}.def-example{font-size:.85rem;color:var(--text-secondary);font-style:italic;padding-left:12px;border-left:2px solid var(--border-soft)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;color:var(--text-secondary);text-align:center;font-style:italic}.progress-container{width:100px;height:6px;background:var(--bg-secondary);border-radius:3px;overflow:hidden}.progress-fill{height:100%;background:var(--accent);border-radius:3px}.line-clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.custom-tabs{display:flex;flex-direction:column;height:100%}.tab-header{display:flex;justify-content:center;gap:32px;background:var(--bg-primary);border-bottom:1px solid var(--border-soft);padding:0 24px}.tab-btn{background:transparent;border:none;padding:16px 4px;font-size:.95rem;font-weight:500;color:var(--text-secondary);cursor:pointer;position:relative;transition:all .2s}.tab-btn:after{content:\"\";position:absolute;bottom:-1px;left:0;width:100%;height:2px;background:transparent;transition:all .2s}.tab-btn:hover{color:var(--text-primary)}.tab-btn.active{color:var(--accent)}.tab-btn.active:after{background:var(--accent)}.tab-panels{flex:1;overflow-y:auto}.tab-panel{animation:fade-in .3s ease-out}@keyframes fade-in{0%{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}:host::ng-deep .highlight-key{color:var(--danger)!important;font-weight:700;background-color:#ef444426;padding:0 4px;border-radius:3px}\n"] }]
|
|
739
|
+
}], ctorParameters: () => [{ type: i1$3.DomSanitizer }, { type: HttpApiService }, { type: NotificationService }, { type: CustomDialogService }, { type: CustomDialogRef }, { type: SharedService }, { type: EpubReaderService }, { type: SharedService }] });
|
|
733
740
|
|
|
734
741
|
class ConfirmPopupComponent {
|
|
735
742
|
ref;
|
|
@@ -767,6 +774,85 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
767
774
|
`, styles: [".confirm-popup-container{padding:24px;background:#fff;border-radius:8px;min-width:300px;box-shadow:0 4px 6px -1px #0000001a}.title{margin:0 0 12px;font-size:1.125rem;font-weight:600;color:#111827}.message{margin:0 0 24px;color:#4b5563;font-size:.95rem}.actions{display:flex;justify-content:flex-end;gap:12px}button{padding:8px 16px;border-radius:6px;font-weight:500;cursor:pointer;transition:all .2s;border:none}.btn-cancel{background:#f3f4f6;color:#374151}.btn-cancel:hover{background:#e5e7eb}.btn-confirm{background:#dc2626;color:#fff}.btn-confirm:hover{background:#b91c1c}\n"] }]
|
|
768
775
|
}], ctorParameters: () => [{ type: CustomDialogRef }] });
|
|
769
776
|
|
|
777
|
+
class NotificationToastComponent {
|
|
778
|
+
notificationService;
|
|
779
|
+
toasts = [];
|
|
780
|
+
subscription;
|
|
781
|
+
constructor(notificationService) {
|
|
782
|
+
this.notificationService = notificationService;
|
|
783
|
+
}
|
|
784
|
+
ngOnInit() {
|
|
785
|
+
this.subscription = this.notificationService.notifications$.subscribe(toast => {
|
|
786
|
+
this.toasts.push(toast);
|
|
787
|
+
if (toast.duration !== 0) {
|
|
788
|
+
setTimeout(() => {
|
|
789
|
+
this.removeToast(toast.id);
|
|
790
|
+
}, toast.duration || 3000);
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
removeToast(id) {
|
|
795
|
+
this.toasts = this.toasts.filter(t => t.id !== id);
|
|
796
|
+
}
|
|
797
|
+
ngOnDestroy() {
|
|
798
|
+
if (this.subscription) {
|
|
799
|
+
this.subscription.unsubscribe();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NotificationToastComponent, deps: [{ token: NotificationService }], target: i0.ɵɵFactoryTarget.Component });
|
|
803
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: NotificationToastComponent, isStandalone: true, selector: "epub-notification-toast", ngImport: i0, template: `
|
|
804
|
+
<div class="notification-container">
|
|
805
|
+
<div *ngFor="let toast of toasts"
|
|
806
|
+
class="toast-item"
|
|
807
|
+
[class]="toast.type"
|
|
808
|
+
(click)="removeToast(toast.id)">
|
|
809
|
+
<div class="toast-icon">
|
|
810
|
+
<ng-container [ngSwitch]="toast.type">
|
|
811
|
+
<svg *ngSwitchCase="'success'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6L9 17L4 12"></path></svg>
|
|
812
|
+
<svg *ngSwitchCase="'error'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>
|
|
813
|
+
<svg *ngSwitchCase="'warning'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
|
814
|
+
<svg *ngSwitchCase="'info'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
|
815
|
+
</ng-container>
|
|
816
|
+
</div>
|
|
817
|
+
<div class="toast-content">
|
|
818
|
+
<div class="toast-title" *ngIf="toast.title">{{ toast.title }}</div>
|
|
819
|
+
<div class="toast-message">{{ toast.message }}</div>
|
|
820
|
+
</div>
|
|
821
|
+
<button class="toast-close">
|
|
822
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6L18 18"></path></svg>
|
|
823
|
+
</button>
|
|
824
|
+
</div>
|
|
825
|
+
</div>
|
|
826
|
+
`, isInline: true, styles: [".notification-container{position:fixed;top:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:12px;pointer-events:none}.toast-item{pointer-events:auto;display:flex;align-items:flex-start;gap:12px;min-width:300px;max-width:400px;padding:16px;background:#fff;border-radius:12px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d;border:1px solid rgba(0,0,0,.05);cursor:pointer;animation:toast-in .3s cubic-bezier(.68,-.55,.265,1.55);transition:all .2s ease}.toast-item:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}@keyframes toast-in{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.toast-icon{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center}.toast-icon svg{width:20px;height:20px}.toast-content{flex-grow:1}.toast-title{font-weight:600;font-size:14px;margin-bottom:2px;color:#1f2937}.toast-message{font-size:14px;color:#4b5563;line-height:1.5}.toast-close{flex-shrink:0;background:transparent;border:none;padding:4px;color:#9ca3af;cursor:pointer;opacity:.6;transition:opacity .2s}.toast-close:hover{opacity:1}.success{border-left:4px solid #10b981}.success .toast-icon{color:#10b981}.error{border-left:4px solid #ef4444}.error .toast-icon{color:#ef4444}.warning{border-left:4px solid #f59e0b}.warning .toast-icon{color:#f59e0b}.info{border-left:4px solid #3b82f6}.info .toast-icon{color:#3b82f6}:host-context(.dark-mode) .toast-item{background:#1f2937;border-color:#374151}:host-context(.dark-mode) .toast-title{color:#f9fafb}:host-context(.dark-mode) .toast-message{color:#d1d5db}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }] });
|
|
827
|
+
}
|
|
828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NotificationToastComponent, decorators: [{
|
|
829
|
+
type: Component,
|
|
830
|
+
args: [{ selector: 'epub-notification-toast', standalone: true, imports: [CommonModule], template: `
|
|
831
|
+
<div class="notification-container">
|
|
832
|
+
<div *ngFor="let toast of toasts"
|
|
833
|
+
class="toast-item"
|
|
834
|
+
[class]="toast.type"
|
|
835
|
+
(click)="removeToast(toast.id)">
|
|
836
|
+
<div class="toast-icon">
|
|
837
|
+
<ng-container [ngSwitch]="toast.type">
|
|
838
|
+
<svg *ngSwitchCase="'success'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6L9 17L4 12"></path></svg>
|
|
839
|
+
<svg *ngSwitchCase="'error'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>
|
|
840
|
+
<svg *ngSwitchCase="'warning'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
|
841
|
+
<svg *ngSwitchCase="'info'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>
|
|
842
|
+
</ng-container>
|
|
843
|
+
</div>
|
|
844
|
+
<div class="toast-content">
|
|
845
|
+
<div class="toast-title" *ngIf="toast.title">{{ toast.title }}</div>
|
|
846
|
+
<div class="toast-message">{{ toast.message }}</div>
|
|
847
|
+
</div>
|
|
848
|
+
<button class="toast-close">
|
|
849
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6L18 18"></path></svg>
|
|
850
|
+
</button>
|
|
851
|
+
</div>
|
|
852
|
+
</div>
|
|
853
|
+
`, styles: [".notification-container{position:fixed;top:24px;right:24px;z-index:9999;display:flex;flex-direction:column;gap:12px;pointer-events:none}.toast-item{pointer-events:auto;display:flex;align-items:flex-start;gap:12px;min-width:300px;max-width:400px;padding:16px;background:#fff;border-radius:12px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d;border:1px solid rgba(0,0,0,.05);cursor:pointer;animation:toast-in .3s cubic-bezier(.68,-.55,.265,1.55);transition:all .2s ease}.toast-item:hover{transform:translateY(-2px);box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a}@keyframes toast-in{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.toast-icon{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center}.toast-icon svg{width:20px;height:20px}.toast-content{flex-grow:1}.toast-title{font-weight:600;font-size:14px;margin-bottom:2px;color:#1f2937}.toast-message{font-size:14px;color:#4b5563;line-height:1.5}.toast-close{flex-shrink:0;background:transparent;border:none;padding:4px;color:#9ca3af;cursor:pointer;opacity:.6;transition:opacity .2s}.toast-close:hover{opacity:1}.success{border-left:4px solid #10b981}.success .toast-icon{color:#10b981}.error{border-left:4px solid #ef4444}.error .toast-icon{color:#ef4444}.warning{border-left:4px solid #f59e0b}.warning .toast-icon{color:#f59e0b}.info{border-left:4px solid #3b82f6}.info .toast-icon{color:#3b82f6}:host-context(.dark-mode) .toast-item{background:#1f2937;border-color:#374151}:host-context(.dark-mode) .toast-title{color:#f9fafb}:host-context(.dark-mode) .toast-message{color:#d1d5db}\n"] }]
|
|
854
|
+
}], ctorParameters: () => [{ type: NotificationService }] });
|
|
855
|
+
|
|
770
856
|
class ChapterlistComponent {
|
|
771
857
|
chapterData = [];
|
|
772
858
|
chapterClick = new EventEmitter();
|
|
@@ -808,7 +894,7 @@ class ReaderMainComponent {
|
|
|
808
894
|
cdr;
|
|
809
895
|
route;
|
|
810
896
|
dialog;
|
|
811
|
-
|
|
897
|
+
notificationService;
|
|
812
898
|
location;
|
|
813
899
|
platformId;
|
|
814
900
|
router;
|
|
@@ -888,7 +974,7 @@ class ReaderMainComponent {
|
|
|
888
974
|
event.stopPropagation();
|
|
889
975
|
}
|
|
890
976
|
}
|
|
891
|
-
constructor(ngZone, httpService, sharedService, epubService, cdr, route, dialog,
|
|
977
|
+
constructor(ngZone, httpService, sharedService, epubService, cdr, route, dialog, notificationService, location, platformId, router, overlay) {
|
|
892
978
|
this.ngZone = ngZone;
|
|
893
979
|
this.httpService = httpService;
|
|
894
980
|
this.sharedService = sharedService;
|
|
@@ -896,7 +982,7 @@ class ReaderMainComponent {
|
|
|
896
982
|
this.cdr = cdr;
|
|
897
983
|
this.route = route;
|
|
898
984
|
this.dialog = dialog;
|
|
899
|
-
this.
|
|
985
|
+
this.notificationService = notificationService;
|
|
900
986
|
this.location = location;
|
|
901
987
|
this.platformId = platformId;
|
|
902
988
|
this.router = router;
|
|
@@ -1052,12 +1138,7 @@ class ReaderMainComponent {
|
|
|
1052
1138
|
handleBookLoadError(message) {
|
|
1053
1139
|
this.showBookPageLoader = false;
|
|
1054
1140
|
this.showDwndLoader = false;
|
|
1055
|
-
this.
|
|
1056
|
-
key: 'notifyToast',
|
|
1057
|
-
severity: 'error',
|
|
1058
|
-
summary: 'Error',
|
|
1059
|
-
detail: message,
|
|
1060
|
-
});
|
|
1141
|
+
this.notificationService.error(message);
|
|
1061
1142
|
this.ngZone.run(() => {
|
|
1062
1143
|
this.sharedService.showHide(false);
|
|
1063
1144
|
});
|
|
@@ -1886,12 +1967,7 @@ class ReaderMainComponent {
|
|
|
1886
1967
|
.pipe(takeUntil(this.onDestroy$))
|
|
1887
1968
|
.subscribe({
|
|
1888
1969
|
next: (res) => {
|
|
1889
|
-
this.
|
|
1890
|
-
key: 'notifyToast',
|
|
1891
|
-
severity: 'success', // Use 'warn' for orange color
|
|
1892
|
-
summary: 'Success',
|
|
1893
|
-
detail: res.message,
|
|
1894
|
-
});
|
|
1970
|
+
this.notificationService.success(res.message);
|
|
1895
1971
|
},
|
|
1896
1972
|
error: () => {
|
|
1897
1973
|
this.sharedService.showHide(false);
|
|
@@ -2100,13 +2176,13 @@ class ReaderMainComponent {
|
|
|
2100
2176
|
this.onDestroy$.next();
|
|
2101
2177
|
this.onDestroy$.complete();
|
|
2102
2178
|
}
|
|
2103
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ReaderMainComponent, deps: [{ token: i0.NgZone }, { token: HttpApiService }, { token: SharedService }, { token: EpubReaderService }, { token: i0.ChangeDetectorRef }, { token: i3.ActivatedRoute }, { token: CustomDialogService }, { token:
|
|
2104
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: ReaderMainComponent, isStandalone: false, selector: "epub-flow", inputs: { epubUrl: "epubUrl", epubBlob: "epubBlob", coverPage: "coverPage", enableDarkMode: "enableDarkMode", enableSearch: "enableSearch", enableHighlights: "enableHighlights", enableBookmarks: "enableBookmarks", enableChapterList: "enableChapterList", enableTextSelection: "enableTextSelection", enableFontSize: "enableFontSize", enableNotes: "enableNotes", bookId: "bookId" }, outputs: { underlineRemoveRequest: "underlineRemoveRequest" }, host: { listeners: { "document:keyup": "handleKeyUp($event)", "document:keydown": "onKeyDown($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div id=\"reader-container\" [hidden]=\"showBookPageLoader || showDwndLoader\">\n <div id=\"reader-content\" style=\"overflow: hidden;\">\n <div id=\"reader\"></div>\n </div>\n\n <div id=\"reader-footer\">\n <div class=\"footer-container\">\n <!-- Left: Previous Button -->\n <button class=\"nav-btn prev-btn\" (click)=\"prevClick()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15 18L9 12L15 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Center: Progress Bar -->\n <div class=\"progress-section\">\n <div class=\"progress-label\">Read Progress</div>\n <div class=\"progress-bar-container\">\n <div class=\"progress-track\">\n <div class=\"progress-fill\" [style.width.%]=\"readPercentage.roudedOff\"></div>\n </div>\n <input type=\"range\" class=\"progress-slider\" min=\"0\" max=\"100\" [value]=\"readPercentage.roudedOff\"\n (input)=\"onProgressChange($event)\" />\n <span class=\"progress-text\">{{ readPercentage.roudedOff }}%</span>\n </div>\n </div>\n\n <!-- Right: Menu Toggle & Next Button -->\n <div class=\"right-controls\">\n <!-- Menu Toggle Button (Green) -->\n <div class=\"menu-container relative\">\n <!-- The Menu Popup -->\n @if (isMenuOpen) {\n <div class=\"menu-popup fade-in\">\n <ul class=\"menu-list\">\n <!-- Dark Mode -->\n <!-- Dark Mode -->\n @if (enableDarkMode) {\n <li (click)=\"toggleDarkMode = !toggleDarkMode; darkMode()\">\n <div class=\"menu-item\">\n <span class=\"icon moon-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M13.5 10C12.7 10.3 11.9 10.5 11 10.5C7.4 10.5 4.5 7.6 4.5 4C4.5 3.1 4.7 2.3 5 1.5C2.7 2.5 1 4.8 1 7.5C1 11.1 3.9 14 7.5 14C10.2 14 12.5 12.3 13.5 10Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>{{ toggleDarkMode ? 'Light Mode' : 'Dark Mode' }}</span>\n </div>\n </li>\n }\n\n <!-- Highlights & Notes -->\n <!-- Highlights & Notes -->\n @if (enableHighlights || enableNotes) {\n <li (click)=\"openCommonPopup(1); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon notes-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 4H14M2 8H14M2 12H8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Highlights & Notes</span>\n </div>\n </li>\n }\n\n <!-- Search Book -->\n <!-- Search Book -->\n @if (enableSearch) {\n <li (click)=\"openCommonPopup(2); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon search-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14 14L10.5 10.5M10.5 10.5C11.4 9.6 12 8.4 12 7C12 4.2 9.8 2 7 2C4.2 2 2 4.2 2 7C2 9.8 4.2 12 7 12C8.4 12 9.6 11.4 10.5 10.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Search Book</span>\n </div>\n </li>\n }\n\n <!-- Bookmark List -->\n <!-- Bookmark List -->\n @if (enableBookmarks) {\n <li (click)=\"getBookMarkList(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon bookmark-list-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 1.33H4C3.26 1.33 2.66 1.93 2.66 2.66V13.33C2.66 14.06 3.26 14.66 4 14.66H12C12.73 14.66 13.33 14.06 13.33 13.33V2.66C13.33 1.93 12.73 1.33 12 1.33ZM6 2.66H7.33V6L6.66 5.5L6 6V2.66ZM12 13.33H4V2.66H4.66V8.66L6.66 7.16L8.66 8.66V2.66H12V13.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Bookmark List</span>\n </div>\n </li>\n }\n\n <!-- Chapters List -->\n <!-- Chapters List -->\n @if (enableChapterList) {\n <li (click)=\"showChapterPopup(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon chapter-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 15.33H2.66C1.93 15.33 1.33 14.73 1.33 14V4.66H2.66V14H12V15.33ZM11 8.66H7V10H11V8.66ZM10 0.66H5.33C4.6 0.66 4 1.26 4 2L4 11.33C4 12.06 4.6 12.66 5.33 12.66H12.66C13.4 12.66 14 12.06 14 11.33V4.66L10 0.66ZM12.66 11.33H5.33V2H9.44L12.66 5.22V11.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Chapters List</span>\n </div>\n </li>\n }\n\n <!-- Divider Row for Quick Actions -->\n <!-- Divider Row for Quick Actions -->\n <li class=\"quick-actions-row\">\n @if (enableFontSize) {\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('+')\">\n <span class=\"text-sm font-bold\">A+</span>\n </div>\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('-')\">\n <span class=\"text-sm font-bold\">A-</span>\n </div>\n }\n @if (enableNotes) {\n <div class=\"quick-action-btn\" (click)=\"addNoteToPage(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M3 17.25V21H6.75L17.81 9.94L14.06 6.19L3 17.25ZM20.71 7.04C21.1 6.65 21.1 6.02 20.71 5.63L18.37 3.29C17.98 2.9 17.35 2.9 16.96 3.29L15.13 5.12L18.88 8.87L20.71 7.04Z\"\n fill=\"currentColor\" />\n </svg>\n </div>\n }\n @if (enableBookmarks) {\n <div class=\"quick-action-btn\" (click)=\"addBookMark(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17 3H7C5.9 3 5 3.9 5 5V21L12 18L19 21V5C19 3.9 18.1 3 17 3Z\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n }\n </li>\n </ul>\n </div>\n }\n\n <!-- Selection Menu Inside Footer Hub -->\n @if (freeSample === 'false') {\n @if (showHighlightOverlay) {\n <div class=\"custom-selection-toolbar selection-menu fade-in\">\n @if (enableNotes) {\n <div class=\"menu-item\" (click)=\"addNotes(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Add Notes</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"showhightLightColor = true; showHighlightOverlay = false\" title=\"Highlight\">\n <span class=\"menu-text\">Highlights</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"addUnderline(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Underline</span>\n </div>\n }\n @if (enableNotes || enableHighlights) {\n <!-- Definition often goes with these tools -->\n <div class=\"menu-item border-none\" (click)=\"openCommonPopup(4); showHighlightOverlay = false\">\n <span class=\"menu-text\">Definition</span>\n </div>\n }\n </div>\n }\n\n @if (showhightLightColor) {\n <div class=\"custom-selection-toolbar color-picker fade-in\">\n @for (color of colourCodeList; track color) {\n <div class=\"color-circle\" [style.background]=\"color\"\n (click)=\"addHighlight(color); showhightLightColor = false\"></div>\n }\n <button class=\"toolbar-btn close-colors\" (click)=\"showhightLightColor = false; showHighlightOverlay = true\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 12H5\"></path>\n </svg>\n </button>\n </div>\n }\n }\n\n <!-- The Green Toggle Button -->\n <button class=\"menu-toggle-btn\" (click)=\"toggleAllMenus()\"\n [class.open]=\"isMenuOpen || showHighlightOverlay || showhightLightColor\">\n <!-- X Icon when open, Burger/Menu when closed -->\n @if (isMenuOpen || showHighlightOverlay || showhightLightColor) {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n } @else {\n <!-- Menu Grid Icon -->\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6H20M4 12H20M4 18H20\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n }\n </button>\n </div>\n\n <!-- Next Button -->\n <button class=\"nav-btn next-btn\" (click)=\"nextClick()\" [class.ml-4]=\"true\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 18L15 12L9 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n\n@if (showBookPageLoader) {\n<div class=\"fixed inset-0 z-[45] flex items-center justify-center bg-premium-loader fade-in\">\n <div class=\"text-center\">\n <div class=\"mb-8 relative inline-block\">\n <!-- Decorative Backdrop for Book -->\n <div class=\"absolute inset-0 bg-black/5 blur-2xl rounded-full transform scale-110\"></div>\n\n <!-- Larger, Premium Book Image -->\n <img [src]=\"coverImg ?? ''\" alt=\"Loading\"\n class=\"w-56 h-80 object-cover rounded-xl shadow-premium border-[6px] border-white relative z-10 animate-pulse\" />\n </div>\n\n <!-- Enhanced Loading Text Container -->\n <div class=\"flex flex-col items-center space-y-3\">\n <div class=\"flex items-center space-x-2 text-gray-400\">\n <span class=\"text-base font-medium\">Please wait a moment</span>\n <div class=\"flex space-x-1.5\">\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.15s]\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.3s]\"></div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n@if (showOverlay) {\n<div class=\"screenshot-overlay\"></div>\n}\n\n<!-- Full-screen Preview End Modal -->\n@if (showPreviewModal) {\n<div class=\"fixed inset-0 z-40 bg-white dark:bg-gray-900 flex flex-col items-center justify-center text-center px-4\">\n <h2\n class=\"text-[1.375rem] sm:text-2xl font-medium leading-snug text-center text-gray-800 dark:text-white mb-6 max-w-xs sm:max-w-sm mx-auto\">\n You\u2019ve reached the end of the sample for\n </h2>\n\n <img [src]=\"coverImg ?? ''\" alt=\"Book Cover\" class=\"w-40 h-auto rounded-lg shadow-lg mb-6\" />\n</div>\n}\n\n\n<!-- Custom Chapter List Modal -->\n@if (showChapterList) {\n<div class=\"custom-modal-overlay fade-in\">\n <div class=\"custom-modal-content\">\n <app-chapterlist [chapterData]=\"chaptersData\" (chapterClick)=\"onChapterSelect($event)\"\n (closeDialog)=\"showChapterList = false\">\n </app-chapterlist>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #475569;--border-base: #edf2f7;--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--accent-color: #34C759;--modal-bg: #ffffff;--modal-text: #0f172a}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-base: #2d3748;--shadow-base: 0 10px 15px -3px rgba(0, 0, 0, .5);--accent-color: #32d74b;--modal-bg: rgb(32 33 32);--modal-text: #f9fafb}#reader{width:100%;height:100%}.no-select{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:default}.screenshot-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#fff;z-index:9999}img,[draggable=true]{-webkit-user-drag:none}::ng-deep *{-webkit-user-drag:none}::ng-deep .textLayer span{-webkit-user-drag:none;pointer-events:auto}.fade-in{animation:fadeIn .5s ease-in forwards}.fade-out{animation:fadeOut .5s ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media print{#viewer{display:none!important}body:before{content:\"Printing is disabled.\";font-size:24px;color:red;text-align:center;display:block;margin-top:100px}}.progress-container{position:relative;height:4px}.range-overlay{position:absolute;top:0;left:0;width:100%;z-index:10;background:transparent;cursor:pointer;-webkit-appearance:none;appearance:none;touch-action:none}.range-overlay::-webkit-slider-thumb{-webkit-appearance:none;height:14px;width:14px;margin-top:-5px;border-radius:50%;background:#0ea951;border:2px solid #ffffff;box-shadow:0 1px 3px #0003;transition:background .2s ease,transform .2s ease}.range-overlay::-webkit-slider-thumb:hover{background:#0cb14f;transform:scale(1.1)}.range-overlay::-webkit-slider-thumb:active{background:#0ba046;transform:scale(1.15)}.range-overlay::-webkit-slider-runnable-track{background:transparent;height:4px}.range-overlay::-moz-range-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-moz-range-track{background:transparent;height:4px}.range-overlay::-ms-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-ms-track{background:transparent;height:4px;border-color:transparent;color:transparent}#reader-container:after{content:\"\";position:absolute;top:13%;bottom:10%;left:50%;transform:translate(-50%);width:2px;background:linear-gradient(to bottom,#06030300,#0d080833,#0000);box-shadow:0 0 10px #0000001a;z-index:1}@media (max-width: 767px){#reader-container:after{display:none!important}}@media (max-width: 991px){#reader-container:after{display:none!important}}::ng-deep nav{box-shadow:none!important}::ng-deep .highlightandNotes .ngneat-dialog-content{width:510px!important;padding:24px}::ng-deep .highlightandNotes .ngneat-close-dialog{top:1.2rem}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{background-color:#333;color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-close-dialog{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-\\[\\#272C47\\]{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-black{color:#fff!important}::ng-deep .addandeditNotepopup .ngneat-dialog-content{width:690px!important}::ng-deep .crop-popup .ngneat-dialog-content{width:420px!important}:host,app-notes{background-color:var(--bg-primary);display:flex;width:100%;justify-content:center;transition:background-color .3s ease}#reader-container{width:100%;height:98vh;background-color:var(--bg-primary);padding-top:0;display:flex;flex-direction:column;overflow:hidden;transition:background-color .3s ease}#reader-content{flex:1;overflow:hidden;position:relative}#reader-footer{position:relative;width:60vw;margin:0 auto;padding:10px 38px 20px;background:var(--bg-primary);z-index:50;transition:background-color .3s ease}#reader-footer .footer-container{display:flex;justify-content:space-between;align-items:flex-end;gap:20px}#reader-footer .nav-btn{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;cursor:pointer;transition:background .2s;background:transparent;border:none;color:var(--text-primary)}#reader-footer .nav-btn:hover{background:#f5f5f5}#reader-footer .nav-btn svg{width:20px;height:20px}#reader-footer .progress-section{flex:1;display:flex;flex-direction:column;align-items:center;max-width:600px;margin:0 auto;padding-bottom:5px}#reader-footer .progress-section .progress-label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:#666;margin-bottom:6px}#reader-footer .progress-section .progress-bar-container{position:relative;width:100%;height:14px;display:flex;align-items:center}#reader-footer .progress-section .progress-bar-container .progress-track{flex:1;height:4px;background:#e7ebeb;border-radius:2px;overflow:hidden;position:relative}#reader-footer .progress-section .progress-bar-container .progress-fill{height:100%;background:#34c759;transition:width .2s ease-out;border-radius:2px}#reader-footer .progress-section .progress-bar-container .progress-slider{position:absolute;width:100%;height:100%;opacity:0;cursor:pointer;top:0;left:0;z-index:2}#reader-footer .progress-section .progress-bar-container .progress-text{margin-left:12px;font-size:12px;font-weight:600;min-width:35px;color:var(--text-primary)}#reader-footer .right-controls{display:flex;align-items:center;gap:16px}#reader-footer .menu-toggle-btn{width:48px;height:48px;border-radius:50%;background:#34c759;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);box-shadow:0 4px 10px #34c7594d;border:none}#reader-footer .menu-toggle-btn.open{background:#34c759;transform:rotate(90deg)}#reader-footer .menu-toggle-btn:hover{transform:scale(1.05);background:#2ebd50}#reader-footer .menu-popup{position:absolute;bottom:70px;right:0;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);padding:8px 0;z-index:100;border:1px solid var(--border-base);transform-origin:bottom right}#reader-footer .menu-popup .menu-list{list-style:none;padding:0;margin:0}#reader-footer .menu-popup .menu-list li{padding:0 8px;cursor:pointer}#reader-footer .menu-popup .menu-list .menu-item{display:flex;align-items:center;padding:12px;font-size:14px;font-weight:500;color:var(--text-primary);border-radius:8px;transition:background .1s}#reader-footer .menu-popup .menu-list .menu-item:hover{background:var(--bg-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon{width:32px;display:flex;align-items:center;justify-content:flex-start;color:var(--text-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon svg{width:18px;height:18px}#reader-footer .menu-popup .quick-actions-row{display:flex;justify-content:space-between;padding:12px 16px;margin-top:8px;border-top:1px solid #f0f0f0;gap:8px}#reader-footer .menu-popup .quick-actions-row .quick-action-btn{flex:1;height:40px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:var(--bg-secondary);cursor:pointer;color:var(--text-primary);transition:all .2s}#reader-footer .menu-popup .quick-actions-row .quick-action-btn:hover{background:var(--border-base)}.calibre{padding:0!important}.hightlight-overlay ::ng-deep .p-overlay{top:-232px!important}app-chapterlist ::ng-deep #reader-content{padding:0!important}.custom-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#0006;backdrop-filter:blur(4px);z-index:200;display:flex;align-items:center;justify-content:center}.custom-modal-content{background:var(--modal-bg);color:var(--modal-text);width:90%;max-width:500px;border-radius:12px;box-shadow:var(--shadow-base);overflow:hidden;animation:modalEnter .2s ease-out;transition:background-color .3s ease,color .3s ease}@keyframes modalEnter{0%{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}.animate-bounce{animation:bounce .6s infinite}.fixed{position:fixed}.inset-0{inset:0}.z-40{z-index:40}.z-45{z-index:45}.flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.text-center{text-align:center}.bg-white{background-color:#fff}.bg-white\\/95{background-color:#fffffff2!important}.bg-black\\/5{background-color:#0000000d}.bg-accent-color{background-color:var(--accent-color)}.bg-premium-loader{background:var(--bg-primary)}.blur-2xl{filter:blur(40px)}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1}.relative{position:relative}.absolute{position:absolute}.inline-block{display:inline-block}.z-10{z-index:10}.mb-8{margin-bottom:2rem}.space-y-3>*+*{margin-top:.75rem}.space-x-1\\.5>*+*{margin-left:.375rem}.tracking-tight{letter-spacing:-.025em}.text-gray-800{color:#1f2937}.border-\\[6px\\]{border-width:6px}.backdrop-blur-sm{backdrop-filter:blur(4px)}.w-full{width:100%}.px-4{padding-left:1rem;padding-right:1rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-\\[-1\\.5rem\\]{margin-top:-1.5rem}.ml-1{margin-left:.25rem}.space-x-1>*+*{margin-left:.25rem}.space-x-2>*+*{margin-left:.5rem}.inline-flex{display:inline-flex}.text-gray-700{color:#374151}.text-gray-400{color:#9ca3af}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.w-40{width:10rem}.h-56{height:14rem}.w-56{width:14rem}.h-80{height:20rem}.w-32{width:8rem}.h-44{height:11rem}.object-cover{object-fit:cover}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.shadow-2xl{box-shadow:0 25px 50px -12px #00000040}.shadow-premium{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a,0 0 0 1px #0000000d}.mx-auto{margin-left:auto;margin-right:auto}.border-4{border-width:4px}.border-white{border-color:#fff}.border-gray-50{border-color:#f9fafb}.w-1\\.5{width:.375rem}.h-1\\.5{height:.375rem}.bg-gray-400{background-color:#9ca3af}.rounded-full{border-radius:9999px}.custom-selection-toolbar{position:absolute;bottom:70px;right:0;z-index:100;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border-base);padding:8px 0;transform-origin:bottom right}.custom-selection-toolbar .menu-item{padding:12px 20px;border-bottom:1px solid #f1f5f9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center}.custom-selection-toolbar .menu-item:hover{background:#f8fafc}.custom-selection-toolbar .menu-item:hover .menu-text{color:var(--accent-color)}.custom-selection-toolbar .menu-item.border-none{border-bottom:none}.custom-selection-toolbar .menu-item .menu-text{font-size:15px;font-weight:500;color:#334155}.custom-selection-toolbar.color-picker{width:auto;flex-direction:row;padding:8px 12px;gap:12px;align-items:center}.custom-selection-toolbar.color-picker .color-circle{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:transform .2s ease}.custom-selection-toolbar.color-picker .color-circle:hover{transform:scale(1.2)}.custom-selection-toolbar.color-picker .toolbar-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#f1f5f9;color:#64748b;cursor:pointer;margin-left:4px}.custom-selection-toolbar.color-picker .toolbar-btn:hover{background:#e2e8f0}:host-context(.dark-mode) .custom-selection-toolbar{background:#1e293b;border-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item{border-bottom-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item:hover{background:#0f172a}:host-context(.dark-mode) .custom-selection-toolbar .menu-item .menu-text{color:#f1f5f9}:host-context(.dark-mode) .custom-selection-toolbar.color-picker .toolbar-btn{background:#334155;color:#f1f5f9}\n"], dependencies: [{ kind: "component", type: ChapterlistComponent, selector: "app-chapterlist", inputs: ["chapterData"], outputs: ["chapterClick", "closeDialog"] }] });
|
|
2179
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ReaderMainComponent, deps: [{ token: i0.NgZone }, { token: HttpApiService }, { token: SharedService }, { token: EpubReaderService }, { token: i0.ChangeDetectorRef }, { token: i3.ActivatedRoute }, { token: CustomDialogService }, { token: NotificationService }, { token: i1$2.Location }, { token: PLATFORM_ID }, { token: i3.Router }, { token: i1$1.Overlay }], target: i0.ɵɵFactoryTarget.Component });
|
|
2180
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: ReaderMainComponent, isStandalone: false, selector: "epub-flow", inputs: { epubUrl: "epubUrl", epubBlob: "epubBlob", coverPage: "coverPage", enableDarkMode: "enableDarkMode", enableSearch: "enableSearch", enableHighlights: "enableHighlights", enableBookmarks: "enableBookmarks", enableChapterList: "enableChapterList", enableTextSelection: "enableTextSelection", enableFontSize: "enableFontSize", enableNotes: "enableNotes", bookId: "bookId" }, outputs: { underlineRemoveRequest: "underlineRemoveRequest" }, host: { listeners: { "document:keyup": "handleKeyUp($event)", "document:keydown": "onKeyDown($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div id=\"reader-container\" [hidden]=\"showBookPageLoader || showDwndLoader\">\n <div id=\"reader-content\" style=\"overflow: hidden;\">\n <div id=\"reader\"></div>\n </div>\n\n <div id=\"reader-footer\">\n <div class=\"footer-container\">\n <!-- Left: Previous Button -->\n <button class=\"nav-btn prev-btn\" (click)=\"prevClick()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15 18L9 12L15 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Center: Progress Bar -->\n <div class=\"progress-section\">\n <div class=\"progress-label\">Read Progress</div>\n <div class=\"progress-bar-container\">\n <div class=\"progress-track\">\n <div class=\"progress-fill\" [style.width.%]=\"readPercentage.roudedOff\"></div>\n </div>\n <input type=\"range\" class=\"progress-slider\" min=\"0\" max=\"100\" [value]=\"readPercentage.roudedOff\"\n (input)=\"onProgressChange($event)\" />\n <span class=\"progress-text\">{{ readPercentage.roudedOff }}%</span>\n </div>\n </div>\n\n <!-- Right: Menu Toggle & Next Button -->\n <div class=\"right-controls\">\n <!-- Menu Toggle Button (Green) -->\n <div class=\"menu-container relative\">\n <!-- The Menu Popup -->\n @if (isMenuOpen) {\n <div class=\"menu-popup fade-in\">\n <ul class=\"menu-list\">\n <!-- Dark Mode -->\n <!-- Dark Mode -->\n @if (enableDarkMode) {\n <li (click)=\"toggleDarkMode = !toggleDarkMode; darkMode()\">\n <div class=\"menu-item\">\n <span class=\"icon moon-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M13.5 10C12.7 10.3 11.9 10.5 11 10.5C7.4 10.5 4.5 7.6 4.5 4C4.5 3.1 4.7 2.3 5 1.5C2.7 2.5 1 4.8 1 7.5C1 11.1 3.9 14 7.5 14C10.2 14 12.5 12.3 13.5 10Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>{{ toggleDarkMode ? 'Light Mode' : 'Dark Mode' }}</span>\n </div>\n </li>\n }\n\n <!-- Highlights & Notes -->\n <!-- Highlights & Notes -->\n @if (enableHighlights || enableNotes) {\n <li (click)=\"openCommonPopup(1); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon notes-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 4H14M2 8H14M2 12H8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Highlights & Notes</span>\n </div>\n </li>\n }\n\n <!-- Search Book -->\n <!-- Search Book -->\n @if (enableSearch) {\n <li (click)=\"openCommonPopup(2); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon search-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14 14L10.5 10.5M10.5 10.5C11.4 9.6 12 8.4 12 7C12 4.2 9.8 2 7 2C4.2 2 2 4.2 2 7C2 9.8 4.2 12 7 12C8.4 12 9.6 11.4 10.5 10.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Search Book</span>\n </div>\n </li>\n }\n\n <!-- Bookmark List -->\n <!-- Bookmark List -->\n @if (enableBookmarks) {\n <li (click)=\"getBookMarkList(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon bookmark-list-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 1.33H4C3.26 1.33 2.66 1.93 2.66 2.66V13.33C2.66 14.06 3.26 14.66 4 14.66H12C12.73 14.66 13.33 14.06 13.33 13.33V2.66C13.33 1.93 12.73 1.33 12 1.33ZM6 2.66H7.33V6L6.66 5.5L6 6V2.66ZM12 13.33H4V2.66H4.66V8.66L6.66 7.16L8.66 8.66V2.66H12V13.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Bookmark List</span>\n </div>\n </li>\n }\n\n <!-- Chapters List -->\n <!-- Chapters List -->\n @if (enableChapterList) {\n <li (click)=\"showChapterPopup(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon chapter-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 15.33H2.66C1.93 15.33 1.33 14.73 1.33 14V4.66H2.66V14H12V15.33ZM11 8.66H7V10H11V8.66ZM10 0.66H5.33C4.6 0.66 4 1.26 4 2L4 11.33C4 12.06 4.6 12.66 5.33 12.66H12.66C13.4 12.66 14 12.06 14 11.33V4.66L10 0.66ZM12.66 11.33H5.33V2H9.44L12.66 5.22V11.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Chapters List</span>\n </div>\n </li>\n }\n\n <!-- Divider Row for Quick Actions -->\n <!-- Divider Row for Quick Actions -->\n <li class=\"quick-actions-row\">\n @if (enableFontSize) {\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('+')\">\n <span class=\"text-sm font-bold\">A+</span>\n </div>\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('-')\">\n <span class=\"text-sm font-bold\">A-</span>\n </div>\n }\n @if (enableNotes) {\n <div class=\"quick-action-btn\" (click)=\"addNoteToPage(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M3 17.25V21H6.75L17.81 9.94L14.06 6.19L3 17.25ZM20.71 7.04C21.1 6.65 21.1 6.02 20.71 5.63L18.37 3.29C17.98 2.9 17.35 2.9 16.96 3.29L15.13 5.12L18.88 8.87L20.71 7.04Z\"\n fill=\"currentColor\" />\n </svg>\n </div>\n }\n @if (enableBookmarks) {\n <div class=\"quick-action-btn\" (click)=\"addBookMark(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17 3H7C5.9 3 5 3.9 5 5V21L12 18L19 21V5C19 3.9 18.1 3 17 3Z\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n }\n </li>\n </ul>\n </div>\n }\n\n <!-- Selection Menu Inside Footer Hub -->\n @if (freeSample === 'false') {\n @if (showHighlightOverlay) {\n <div class=\"custom-selection-toolbar selection-menu fade-in\">\n @if (enableNotes) {\n <div class=\"menu-item\" (click)=\"addNotes(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Add Notes</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"showhightLightColor = true; showHighlightOverlay = false\" title=\"Highlight\">\n <span class=\"menu-text\">Highlights</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"addUnderline(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Underline</span>\n </div>\n }\n @if (enableNotes || enableHighlights) {\n <!-- Definition often goes with these tools -->\n <div class=\"menu-item border-none\" (click)=\"openCommonPopup(4); showHighlightOverlay = false\">\n <span class=\"menu-text\">Definition</span>\n </div>\n }\n </div>\n }\n\n @if (showhightLightColor) {\n <div class=\"custom-selection-toolbar color-picker fade-in\">\n @for (color of colourCodeList; track color) {\n <div class=\"color-circle\" [style.background]=\"color\"\n (click)=\"addHighlight(color); showhightLightColor = false\"></div>\n }\n <button class=\"toolbar-btn close-colors\" (click)=\"showhightLightColor = false; showHighlightOverlay = true\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 12H5\"></path>\n </svg>\n </button>\n </div>\n }\n }\n\n <!-- The Green Toggle Button -->\n <button class=\"menu-toggle-btn\" (click)=\"toggleAllMenus()\"\n [class.open]=\"isMenuOpen || showHighlightOverlay || showhightLightColor\">\n <!-- X Icon when open, Burger/Menu when closed -->\n @if (isMenuOpen || showHighlightOverlay || showhightLightColor) {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n } @else {\n <!-- Menu Grid Icon -->\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6H20M4 12H20M4 18H20\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n }\n </button>\n </div>\n\n <!-- Next Button -->\n <button class=\"nav-btn next-btn\" (click)=\"nextClick()\" [class.ml-4]=\"true\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 18L15 12L9 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n\n@if (showBookPageLoader) {\n<div class=\"fixed inset-0 z-[45] flex items-center justify-center bg-premium-loader fade-in\">\n <div class=\"text-center\">\n <div class=\"mb-8 relative inline-block\">\n <!-- Decorative Backdrop for Book -->\n <div class=\"absolute inset-0 bg-black/5 blur-2xl rounded-full transform scale-110\"></div>\n\n <!-- Larger, Premium Book Image -->\n <img [src]=\"coverImg ?? ''\" alt=\"Loading\"\n class=\"w-56 h-80 object-cover rounded-xl shadow-premium border-[6px] border-white relative z-10 animate-pulse\" />\n </div>\n\n <!-- Enhanced Loading Text Container -->\n <div class=\"flex flex-col items-center space-y-3\">\n <div class=\"flex items-center space-x-2 text-gray-400\">\n <span class=\"text-base font-medium\">Please wait a moment</span>\n <div class=\"flex space-x-1.5\">\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.15s]\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.3s]\"></div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n@if (showOverlay) {\n<div class=\"screenshot-overlay\"></div>\n}\n\n<!-- Full-screen Preview End Modal -->\n@if (showPreviewModal) {\n<div class=\"fixed inset-0 z-40 bg-white dark:bg-gray-900 flex flex-col items-center justify-center text-center px-4\">\n <h2\n class=\"text-[1.375rem] sm:text-2xl font-medium leading-snug text-center text-gray-800 dark:text-white mb-6 max-w-xs sm:max-w-sm mx-auto\">\n You\u2019ve reached the end of the sample for\n </h2>\n\n <img [src]=\"coverImg ?? ''\" alt=\"Book Cover\" class=\"w-40 h-auto rounded-lg shadow-lg mb-6\" />\n</div>\n}\n\n\n<!-- Custom Chapter List Modal -->\n@if (showChapterList) {\n<div class=\"custom-modal-overlay fade-in\">\n <div class=\"custom-modal-content\">\n <app-chapterlist [chapterData]=\"chaptersData\" (chapterClick)=\"onChapterSelect($event)\"\n (closeDialog)=\"showChapterList = false\">\n </app-chapterlist>\n </div>\n</div>\n}\n<epub-notification-toast></epub-notification-toast>", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #475569;--border-base: #edf2f7;--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--accent-color: #34C759;--modal-bg: #ffffff;--modal-text: #0f172a}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-base: #2d3748;--shadow-base: 0 10px 15px -3px rgba(0, 0, 0, .5);--accent-color: #32d74b;--modal-bg: rgb(32 33 32);--modal-text: #f9fafb}#reader{width:100%;height:100%}.no-select{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:default}.screenshot-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#fff;z-index:9999}img,[draggable=true]{-webkit-user-drag:none}::ng-deep *{-webkit-user-drag:none}::ng-deep .textLayer span{-webkit-user-drag:none;pointer-events:auto}.fade-in{animation:fadeIn .5s ease-in forwards}.fade-out{animation:fadeOut .5s ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media print{#viewer{display:none!important}body:before{content:\"Printing is disabled.\";font-size:24px;color:red;text-align:center;display:block;margin-top:100px}}.progress-container{position:relative;height:4px}.range-overlay{position:absolute;top:0;left:0;width:100%;z-index:10;background:transparent;cursor:pointer;-webkit-appearance:none;appearance:none;touch-action:none}.range-overlay::-webkit-slider-thumb{-webkit-appearance:none;height:14px;width:14px;margin-top:-5px;border-radius:50%;background:#0ea951;border:2px solid #ffffff;box-shadow:0 1px 3px #0003;transition:background .2s ease,transform .2s ease}.range-overlay::-webkit-slider-thumb:hover{background:#0cb14f;transform:scale(1.1)}.range-overlay::-webkit-slider-thumb:active{background:#0ba046;transform:scale(1.15)}.range-overlay::-webkit-slider-runnable-track{background:transparent;height:4px}.range-overlay::-moz-range-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-moz-range-track{background:transparent;height:4px}.range-overlay::-ms-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-ms-track{background:transparent;height:4px;border-color:transparent;color:transparent}#reader-container:after{content:\"\";position:absolute;top:13%;bottom:10%;left:50%;transform:translate(-50%);width:2px;background:linear-gradient(to bottom,#06030300,#0d080833,#0000);box-shadow:0 0 10px #0000001a;z-index:1}@media (max-width: 767px){#reader-container:after{display:none!important}}@media (max-width: 991px){#reader-container:after{display:none!important}}::ng-deep nav{box-shadow:none!important}::ng-deep .highlightandNotes .ngneat-dialog-content{width:510px!important;padding:24px}::ng-deep .highlightandNotes .ngneat-close-dialog{top:1.2rem}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{background-color:#333;color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-close-dialog{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-\\[\\#272C47\\]{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-black{color:#fff!important}::ng-deep .addandeditNotepopup .ngneat-dialog-content{width:690px!important}::ng-deep .crop-popup .ngneat-dialog-content{width:420px!important}:host,app-notes{background-color:var(--bg-primary);display:flex;width:100%;justify-content:center;transition:background-color .3s ease}#reader-container{width:100%;height:98vh;background-color:var(--bg-primary);padding-top:0;display:flex;flex-direction:column;overflow:hidden;transition:background-color .3s ease}#reader-content{flex:1;overflow:hidden;position:relative}#reader-footer{position:relative;width:60vw;margin:0 auto;padding:10px 38px 20px;background:var(--bg-primary);z-index:50;transition:background-color .3s ease}#reader-footer .footer-container{display:flex;justify-content:space-between;align-items:flex-end;gap:20px}#reader-footer .nav-btn{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;cursor:pointer;transition:background .2s;background:transparent;border:none;color:var(--text-primary)}#reader-footer .nav-btn:hover{background:#f5f5f5}#reader-footer .nav-btn svg{width:20px;height:20px}#reader-footer .progress-section{flex:1;display:flex;flex-direction:column;align-items:center;max-width:600px;margin:0 auto;padding-bottom:5px}#reader-footer .progress-section .progress-label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:#666;margin-bottom:6px}#reader-footer .progress-section .progress-bar-container{position:relative;width:100%;height:14px;display:flex;align-items:center}#reader-footer .progress-section .progress-bar-container .progress-track{flex:1;height:4px;background:#e7ebeb;border-radius:2px;overflow:hidden;position:relative}#reader-footer .progress-section .progress-bar-container .progress-fill{height:100%;background:#34c759;transition:width .2s ease-out;border-radius:2px}#reader-footer .progress-section .progress-bar-container .progress-slider{position:absolute;width:100%;height:100%;opacity:0;cursor:pointer;top:0;left:0;z-index:2}#reader-footer .progress-section .progress-bar-container .progress-text{margin-left:12px;font-size:12px;font-weight:600;min-width:35px;color:var(--text-primary)}#reader-footer .right-controls{display:flex;align-items:center;gap:16px}#reader-footer .menu-toggle-btn{width:48px;height:48px;border-radius:50%;background:#34c759;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);box-shadow:0 4px 10px #34c7594d;border:none}#reader-footer .menu-toggle-btn.open{background:#34c759;transform:rotate(90deg)}#reader-footer .menu-toggle-btn:hover{transform:scale(1.05);background:#2ebd50}#reader-footer .menu-popup{position:absolute;bottom:70px;right:0;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);padding:8px 0;z-index:100;border:1px solid var(--border-base);transform-origin:bottom right}#reader-footer .menu-popup .menu-list{list-style:none;padding:0;margin:0}#reader-footer .menu-popup .menu-list li{padding:0 8px;cursor:pointer}#reader-footer .menu-popup .menu-list .menu-item{display:flex;align-items:center;padding:12px;font-size:14px;font-weight:500;color:var(--text-primary);border-radius:8px;transition:background .1s}#reader-footer .menu-popup .menu-list .menu-item:hover{background:var(--bg-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon{width:32px;display:flex;align-items:center;justify-content:flex-start;color:var(--text-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon svg{width:18px;height:18px}#reader-footer .menu-popup .quick-actions-row{display:flex;justify-content:space-between;padding:12px 16px;margin-top:8px;border-top:1px solid #f0f0f0;gap:8px}#reader-footer .menu-popup .quick-actions-row .quick-action-btn{flex:1;height:40px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:var(--bg-secondary);cursor:pointer;color:var(--text-primary);transition:all .2s}#reader-footer .menu-popup .quick-actions-row .quick-action-btn:hover{background:var(--border-base)}.calibre{padding:0!important}.hightlight-overlay ::ng-deep .p-overlay{top:-232px!important}app-chapterlist ::ng-deep #reader-content{padding:0!important}.custom-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#0006;backdrop-filter:blur(4px);z-index:200;display:flex;align-items:center;justify-content:center}.custom-modal-content{background:var(--modal-bg);color:var(--modal-text);width:90%;max-width:500px;border-radius:12px;box-shadow:var(--shadow-base);overflow:hidden;animation:modalEnter .2s ease-out;transition:background-color .3s ease,color .3s ease}@keyframes modalEnter{0%{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}.animate-bounce{animation:bounce .6s infinite}.fixed{position:fixed}.inset-0{inset:0}.z-40{z-index:40}.z-45{z-index:45}.flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.text-center{text-align:center}.bg-white{background-color:#fff}.bg-white\\/95{background-color:#fffffff2!important}.bg-black\\/5{background-color:#0000000d}.bg-accent-color{background-color:var(--accent-color)}.bg-premium-loader{background:var(--bg-primary)}.blur-2xl{filter:blur(40px)}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1}.relative{position:relative}.absolute{position:absolute}.inline-block{display:inline-block}.z-10{z-index:10}.mb-8{margin-bottom:2rem}.space-y-3>*+*{margin-top:.75rem}.space-x-1\\.5>*+*{margin-left:.375rem}.tracking-tight{letter-spacing:-.025em}.text-gray-800{color:#1f2937}.border-\\[6px\\]{border-width:6px}.backdrop-blur-sm{backdrop-filter:blur(4px)}.w-full{width:100%}.px-4{padding-left:1rem;padding-right:1rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-\\[-1\\.5rem\\]{margin-top:-1.5rem}.ml-1{margin-left:.25rem}.space-x-1>*+*{margin-left:.25rem}.space-x-2>*+*{margin-left:.5rem}.inline-flex{display:inline-flex}.text-gray-700{color:#374151}.text-gray-400{color:#9ca3af}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.w-40{width:10rem}.h-56{height:14rem}.w-56{width:14rem}.h-80{height:20rem}.w-32{width:8rem}.h-44{height:11rem}.object-cover{object-fit:cover}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.shadow-2xl{box-shadow:0 25px 50px -12px #00000040}.shadow-premium{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a,0 0 0 1px #0000000d}.mx-auto{margin-left:auto;margin-right:auto}.border-4{border-width:4px}.border-white{border-color:#fff}.border-gray-50{border-color:#f9fafb}.w-1\\.5{width:.375rem}.h-1\\.5{height:.375rem}.bg-gray-400{background-color:#9ca3af}.rounded-full{border-radius:9999px}.custom-selection-toolbar{position:absolute;bottom:70px;right:0;z-index:100;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border-base);padding:8px 0;transform-origin:bottom right}.custom-selection-toolbar .menu-item{padding:12px 20px;border-bottom:1px solid #f1f5f9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center}.custom-selection-toolbar .menu-item:hover{background:#f8fafc}.custom-selection-toolbar .menu-item:hover .menu-text{color:var(--accent-color)}.custom-selection-toolbar .menu-item.border-none{border-bottom:none}.custom-selection-toolbar .menu-item .menu-text{font-size:15px;font-weight:500;color:#334155}.custom-selection-toolbar.color-picker{width:auto;flex-direction:row;padding:8px 12px;gap:12px;align-items:center}.custom-selection-toolbar.color-picker .color-circle{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:transform .2s ease}.custom-selection-toolbar.color-picker .color-circle:hover{transform:scale(1.2)}.custom-selection-toolbar.color-picker .toolbar-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#f1f5f9;color:#64748b;cursor:pointer;margin-left:4px}.custom-selection-toolbar.color-picker .toolbar-btn:hover{background:#e2e8f0}:host-context(.dark-mode) .custom-selection-toolbar{background:#1e293b;border-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item{border-bottom-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item:hover{background:#0f172a}:host-context(.dark-mode) .custom-selection-toolbar .menu-item .menu-text{color:#f1f5f9}:host-context(.dark-mode) .custom-selection-toolbar.color-picker .toolbar-btn{background:#334155;color:#f1f5f9}\n"], dependencies: [{ kind: "component", type: NotificationToastComponent, selector: "epub-notification-toast" }, { kind: "component", type: ChapterlistComponent, selector: "app-chapterlist", inputs: ["chapterData"], outputs: ["chapterClick", "closeDialog"] }] });
|
|
2105
2181
|
}
|
|
2106
2182
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ReaderMainComponent, decorators: [{
|
|
2107
2183
|
type: Component,
|
|
2108
|
-
args: [{ selector: 'epub-flow', standalone: false, template: "<div id=\"reader-container\" [hidden]=\"showBookPageLoader || showDwndLoader\">\n <div id=\"reader-content\" style=\"overflow: hidden;\">\n <div id=\"reader\"></div>\n </div>\n\n <div id=\"reader-footer\">\n <div class=\"footer-container\">\n <!-- Left: Previous Button -->\n <button class=\"nav-btn prev-btn\" (click)=\"prevClick()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15 18L9 12L15 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Center: Progress Bar -->\n <div class=\"progress-section\">\n <div class=\"progress-label\">Read Progress</div>\n <div class=\"progress-bar-container\">\n <div class=\"progress-track\">\n <div class=\"progress-fill\" [style.width.%]=\"readPercentage.roudedOff\"></div>\n </div>\n <input type=\"range\" class=\"progress-slider\" min=\"0\" max=\"100\" [value]=\"readPercentage.roudedOff\"\n (input)=\"onProgressChange($event)\" />\n <span class=\"progress-text\">{{ readPercentage.roudedOff }}%</span>\n </div>\n </div>\n\n <!-- Right: Menu Toggle & Next Button -->\n <div class=\"right-controls\">\n <!-- Menu Toggle Button (Green) -->\n <div class=\"menu-container relative\">\n <!-- The Menu Popup -->\n @if (isMenuOpen) {\n <div class=\"menu-popup fade-in\">\n <ul class=\"menu-list\">\n <!-- Dark Mode -->\n <!-- Dark Mode -->\n @if (enableDarkMode) {\n <li (click)=\"toggleDarkMode = !toggleDarkMode; darkMode()\">\n <div class=\"menu-item\">\n <span class=\"icon moon-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M13.5 10C12.7 10.3 11.9 10.5 11 10.5C7.4 10.5 4.5 7.6 4.5 4C4.5 3.1 4.7 2.3 5 1.5C2.7 2.5 1 4.8 1 7.5C1 11.1 3.9 14 7.5 14C10.2 14 12.5 12.3 13.5 10Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>{{ toggleDarkMode ? 'Light Mode' : 'Dark Mode' }}</span>\n </div>\n </li>\n }\n\n <!-- Highlights & Notes -->\n <!-- Highlights & Notes -->\n @if (enableHighlights || enableNotes) {\n <li (click)=\"openCommonPopup(1); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon notes-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 4H14M2 8H14M2 12H8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Highlights & Notes</span>\n </div>\n </li>\n }\n\n <!-- Search Book -->\n <!-- Search Book -->\n @if (enableSearch) {\n <li (click)=\"openCommonPopup(2); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon search-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14 14L10.5 10.5M10.5 10.5C11.4 9.6 12 8.4 12 7C12 4.2 9.8 2 7 2C4.2 2 2 4.2 2 7C2 9.8 4.2 12 7 12C8.4 12 9.6 11.4 10.5 10.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Search Book</span>\n </div>\n </li>\n }\n\n <!-- Bookmark List -->\n <!-- Bookmark List -->\n @if (enableBookmarks) {\n <li (click)=\"getBookMarkList(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon bookmark-list-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 1.33H4C3.26 1.33 2.66 1.93 2.66 2.66V13.33C2.66 14.06 3.26 14.66 4 14.66H12C12.73 14.66 13.33 14.06 13.33 13.33V2.66C13.33 1.93 12.73 1.33 12 1.33ZM6 2.66H7.33V6L6.66 5.5L6 6V2.66ZM12 13.33H4V2.66H4.66V8.66L6.66 7.16L8.66 8.66V2.66H12V13.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Bookmark List</span>\n </div>\n </li>\n }\n\n <!-- Chapters List -->\n <!-- Chapters List -->\n @if (enableChapterList) {\n <li (click)=\"showChapterPopup(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon chapter-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 15.33H2.66C1.93 15.33 1.33 14.73 1.33 14V4.66H2.66V14H12V15.33ZM11 8.66H7V10H11V8.66ZM10 0.66H5.33C4.6 0.66 4 1.26 4 2L4 11.33C4 12.06 4.6 12.66 5.33 12.66H12.66C13.4 12.66 14 12.06 14 11.33V4.66L10 0.66ZM12.66 11.33H5.33V2H9.44L12.66 5.22V11.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Chapters List</span>\n </div>\n </li>\n }\n\n <!-- Divider Row for Quick Actions -->\n <!-- Divider Row for Quick Actions -->\n <li class=\"quick-actions-row\">\n @if (enableFontSize) {\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('+')\">\n <span class=\"text-sm font-bold\">A+</span>\n </div>\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('-')\">\n <span class=\"text-sm font-bold\">A-</span>\n </div>\n }\n @if (enableNotes) {\n <div class=\"quick-action-btn\" (click)=\"addNoteToPage(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M3 17.25V21H6.75L17.81 9.94L14.06 6.19L3 17.25ZM20.71 7.04C21.1 6.65 21.1 6.02 20.71 5.63L18.37 3.29C17.98 2.9 17.35 2.9 16.96 3.29L15.13 5.12L18.88 8.87L20.71 7.04Z\"\n fill=\"currentColor\" />\n </svg>\n </div>\n }\n @if (enableBookmarks) {\n <div class=\"quick-action-btn\" (click)=\"addBookMark(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17 3H7C5.9 3 5 3.9 5 5V21L12 18L19 21V5C19 3.9 18.1 3 17 3Z\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n }\n </li>\n </ul>\n </div>\n }\n\n <!-- Selection Menu Inside Footer Hub -->\n @if (freeSample === 'false') {\n @if (showHighlightOverlay) {\n <div class=\"custom-selection-toolbar selection-menu fade-in\">\n @if (enableNotes) {\n <div class=\"menu-item\" (click)=\"addNotes(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Add Notes</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"showhightLightColor = true; showHighlightOverlay = false\" title=\"Highlight\">\n <span class=\"menu-text\">Highlights</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"addUnderline(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Underline</span>\n </div>\n }\n @if (enableNotes || enableHighlights) {\n <!-- Definition often goes with these tools -->\n <div class=\"menu-item border-none\" (click)=\"openCommonPopup(4); showHighlightOverlay = false\">\n <span class=\"menu-text\">Definition</span>\n </div>\n }\n </div>\n }\n\n @if (showhightLightColor) {\n <div class=\"custom-selection-toolbar color-picker fade-in\">\n @for (color of colourCodeList; track color) {\n <div class=\"color-circle\" [style.background]=\"color\"\n (click)=\"addHighlight(color); showhightLightColor = false\"></div>\n }\n <button class=\"toolbar-btn close-colors\" (click)=\"showhightLightColor = false; showHighlightOverlay = true\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 12H5\"></path>\n </svg>\n </button>\n </div>\n }\n }\n\n <!-- The Green Toggle Button -->\n <button class=\"menu-toggle-btn\" (click)=\"toggleAllMenus()\"\n [class.open]=\"isMenuOpen || showHighlightOverlay || showhightLightColor\">\n <!-- X Icon when open, Burger/Menu when closed -->\n @if (isMenuOpen || showHighlightOverlay || showhightLightColor) {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n } @else {\n <!-- Menu Grid Icon -->\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6H20M4 12H20M4 18H20\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n }\n </button>\n </div>\n\n <!-- Next Button -->\n <button class=\"nav-btn next-btn\" (click)=\"nextClick()\" [class.ml-4]=\"true\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 18L15 12L9 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n\n@if (showBookPageLoader) {\n<div class=\"fixed inset-0 z-[45] flex items-center justify-center bg-premium-loader fade-in\">\n <div class=\"text-center\">\n <div class=\"mb-8 relative inline-block\">\n <!-- Decorative Backdrop for Book -->\n <div class=\"absolute inset-0 bg-black/5 blur-2xl rounded-full transform scale-110\"></div>\n\n <!-- Larger, Premium Book Image -->\n <img [src]=\"coverImg ?? ''\" alt=\"Loading\"\n class=\"w-56 h-80 object-cover rounded-xl shadow-premium border-[6px] border-white relative z-10 animate-pulse\" />\n </div>\n\n <!-- Enhanced Loading Text Container -->\n <div class=\"flex flex-col items-center space-y-3\">\n <div class=\"flex items-center space-x-2 text-gray-400\">\n <span class=\"text-base font-medium\">Please wait a moment</span>\n <div class=\"flex space-x-1.5\">\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.15s]\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.3s]\"></div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n@if (showOverlay) {\n<div class=\"screenshot-overlay\"></div>\n}\n\n<!-- Full-screen Preview End Modal -->\n@if (showPreviewModal) {\n<div class=\"fixed inset-0 z-40 bg-white dark:bg-gray-900 flex flex-col items-center justify-center text-center px-4\">\n <h2\n class=\"text-[1.375rem] sm:text-2xl font-medium leading-snug text-center text-gray-800 dark:text-white mb-6 max-w-xs sm:max-w-sm mx-auto\">\n You\u2019ve reached the end of the sample for\n </h2>\n\n <img [src]=\"coverImg ?? ''\" alt=\"Book Cover\" class=\"w-40 h-auto rounded-lg shadow-lg mb-6\" />\n</div>\n}\n\n\n<!-- Custom Chapter List Modal -->\n@if (showChapterList) {\n<div class=\"custom-modal-overlay fade-in\">\n <div class=\"custom-modal-content\">\n <app-chapterlist [chapterData]=\"chaptersData\" (chapterClick)=\"onChapterSelect($event)\"\n (closeDialog)=\"showChapterList = false\">\n </app-chapterlist>\n </div>\n</div>\n}", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #475569;--border-base: #edf2f7;--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--accent-color: #34C759;--modal-bg: #ffffff;--modal-text: #0f172a}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-base: #2d3748;--shadow-base: 0 10px 15px -3px rgba(0, 0, 0, .5);--accent-color: #32d74b;--modal-bg: rgb(32 33 32);--modal-text: #f9fafb}#reader{width:100%;height:100%}.no-select{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:default}.screenshot-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#fff;z-index:9999}img,[draggable=true]{-webkit-user-drag:none}::ng-deep *{-webkit-user-drag:none}::ng-deep .textLayer span{-webkit-user-drag:none;pointer-events:auto}.fade-in{animation:fadeIn .5s ease-in forwards}.fade-out{animation:fadeOut .5s ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media print{#viewer{display:none!important}body:before{content:\"Printing is disabled.\";font-size:24px;color:red;text-align:center;display:block;margin-top:100px}}.progress-container{position:relative;height:4px}.range-overlay{position:absolute;top:0;left:0;width:100%;z-index:10;background:transparent;cursor:pointer;-webkit-appearance:none;appearance:none;touch-action:none}.range-overlay::-webkit-slider-thumb{-webkit-appearance:none;height:14px;width:14px;margin-top:-5px;border-radius:50%;background:#0ea951;border:2px solid #ffffff;box-shadow:0 1px 3px #0003;transition:background .2s ease,transform .2s ease}.range-overlay::-webkit-slider-thumb:hover{background:#0cb14f;transform:scale(1.1)}.range-overlay::-webkit-slider-thumb:active{background:#0ba046;transform:scale(1.15)}.range-overlay::-webkit-slider-runnable-track{background:transparent;height:4px}.range-overlay::-moz-range-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-moz-range-track{background:transparent;height:4px}.range-overlay::-ms-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-ms-track{background:transparent;height:4px;border-color:transparent;color:transparent}#reader-container:after{content:\"\";position:absolute;top:13%;bottom:10%;left:50%;transform:translate(-50%);width:2px;background:linear-gradient(to bottom,#06030300,#0d080833,#0000);box-shadow:0 0 10px #0000001a;z-index:1}@media (max-width: 767px){#reader-container:after{display:none!important}}@media (max-width: 991px){#reader-container:after{display:none!important}}::ng-deep nav{box-shadow:none!important}::ng-deep .highlightandNotes .ngneat-dialog-content{width:510px!important;padding:24px}::ng-deep .highlightandNotes .ngneat-close-dialog{top:1.2rem}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{background-color:#333;color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-close-dialog{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-\\[\\#272C47\\]{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-black{color:#fff!important}::ng-deep .addandeditNotepopup .ngneat-dialog-content{width:690px!important}::ng-deep .crop-popup .ngneat-dialog-content{width:420px!important}:host,app-notes{background-color:var(--bg-primary);display:flex;width:100%;justify-content:center;transition:background-color .3s ease}#reader-container{width:100%;height:98vh;background-color:var(--bg-primary);padding-top:0;display:flex;flex-direction:column;overflow:hidden;transition:background-color .3s ease}#reader-content{flex:1;overflow:hidden;position:relative}#reader-footer{position:relative;width:60vw;margin:0 auto;padding:10px 38px 20px;background:var(--bg-primary);z-index:50;transition:background-color .3s ease}#reader-footer .footer-container{display:flex;justify-content:space-between;align-items:flex-end;gap:20px}#reader-footer .nav-btn{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;cursor:pointer;transition:background .2s;background:transparent;border:none;color:var(--text-primary)}#reader-footer .nav-btn:hover{background:#f5f5f5}#reader-footer .nav-btn svg{width:20px;height:20px}#reader-footer .progress-section{flex:1;display:flex;flex-direction:column;align-items:center;max-width:600px;margin:0 auto;padding-bottom:5px}#reader-footer .progress-section .progress-label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:#666;margin-bottom:6px}#reader-footer .progress-section .progress-bar-container{position:relative;width:100%;height:14px;display:flex;align-items:center}#reader-footer .progress-section .progress-bar-container .progress-track{flex:1;height:4px;background:#e7ebeb;border-radius:2px;overflow:hidden;position:relative}#reader-footer .progress-section .progress-bar-container .progress-fill{height:100%;background:#34c759;transition:width .2s ease-out;border-radius:2px}#reader-footer .progress-section .progress-bar-container .progress-slider{position:absolute;width:100%;height:100%;opacity:0;cursor:pointer;top:0;left:0;z-index:2}#reader-footer .progress-section .progress-bar-container .progress-text{margin-left:12px;font-size:12px;font-weight:600;min-width:35px;color:var(--text-primary)}#reader-footer .right-controls{display:flex;align-items:center;gap:16px}#reader-footer .menu-toggle-btn{width:48px;height:48px;border-radius:50%;background:#34c759;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);box-shadow:0 4px 10px #34c7594d;border:none}#reader-footer .menu-toggle-btn.open{background:#34c759;transform:rotate(90deg)}#reader-footer .menu-toggle-btn:hover{transform:scale(1.05);background:#2ebd50}#reader-footer .menu-popup{position:absolute;bottom:70px;right:0;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);padding:8px 0;z-index:100;border:1px solid var(--border-base);transform-origin:bottom right}#reader-footer .menu-popup .menu-list{list-style:none;padding:0;margin:0}#reader-footer .menu-popup .menu-list li{padding:0 8px;cursor:pointer}#reader-footer .menu-popup .menu-list .menu-item{display:flex;align-items:center;padding:12px;font-size:14px;font-weight:500;color:var(--text-primary);border-radius:8px;transition:background .1s}#reader-footer .menu-popup .menu-list .menu-item:hover{background:var(--bg-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon{width:32px;display:flex;align-items:center;justify-content:flex-start;color:var(--text-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon svg{width:18px;height:18px}#reader-footer .menu-popup .quick-actions-row{display:flex;justify-content:space-between;padding:12px 16px;margin-top:8px;border-top:1px solid #f0f0f0;gap:8px}#reader-footer .menu-popup .quick-actions-row .quick-action-btn{flex:1;height:40px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:var(--bg-secondary);cursor:pointer;color:var(--text-primary);transition:all .2s}#reader-footer .menu-popup .quick-actions-row .quick-action-btn:hover{background:var(--border-base)}.calibre{padding:0!important}.hightlight-overlay ::ng-deep .p-overlay{top:-232px!important}app-chapterlist ::ng-deep #reader-content{padding:0!important}.custom-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#0006;backdrop-filter:blur(4px);z-index:200;display:flex;align-items:center;justify-content:center}.custom-modal-content{background:var(--modal-bg);color:var(--modal-text);width:90%;max-width:500px;border-radius:12px;box-shadow:var(--shadow-base);overflow:hidden;animation:modalEnter .2s ease-out;transition:background-color .3s ease,color .3s ease}@keyframes modalEnter{0%{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}.animate-bounce{animation:bounce .6s infinite}.fixed{position:fixed}.inset-0{inset:0}.z-40{z-index:40}.z-45{z-index:45}.flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.text-center{text-align:center}.bg-white{background-color:#fff}.bg-white\\/95{background-color:#fffffff2!important}.bg-black\\/5{background-color:#0000000d}.bg-accent-color{background-color:var(--accent-color)}.bg-premium-loader{background:var(--bg-primary)}.blur-2xl{filter:blur(40px)}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1}.relative{position:relative}.absolute{position:absolute}.inline-block{display:inline-block}.z-10{z-index:10}.mb-8{margin-bottom:2rem}.space-y-3>*+*{margin-top:.75rem}.space-x-1\\.5>*+*{margin-left:.375rem}.tracking-tight{letter-spacing:-.025em}.text-gray-800{color:#1f2937}.border-\\[6px\\]{border-width:6px}.backdrop-blur-sm{backdrop-filter:blur(4px)}.w-full{width:100%}.px-4{padding-left:1rem;padding-right:1rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-\\[-1\\.5rem\\]{margin-top:-1.5rem}.ml-1{margin-left:.25rem}.space-x-1>*+*{margin-left:.25rem}.space-x-2>*+*{margin-left:.5rem}.inline-flex{display:inline-flex}.text-gray-700{color:#374151}.text-gray-400{color:#9ca3af}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.w-40{width:10rem}.h-56{height:14rem}.w-56{width:14rem}.h-80{height:20rem}.w-32{width:8rem}.h-44{height:11rem}.object-cover{object-fit:cover}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.shadow-2xl{box-shadow:0 25px 50px -12px #00000040}.shadow-premium{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a,0 0 0 1px #0000000d}.mx-auto{margin-left:auto;margin-right:auto}.border-4{border-width:4px}.border-white{border-color:#fff}.border-gray-50{border-color:#f9fafb}.w-1\\.5{width:.375rem}.h-1\\.5{height:.375rem}.bg-gray-400{background-color:#9ca3af}.rounded-full{border-radius:9999px}.custom-selection-toolbar{position:absolute;bottom:70px;right:0;z-index:100;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border-base);padding:8px 0;transform-origin:bottom right}.custom-selection-toolbar .menu-item{padding:12px 20px;border-bottom:1px solid #f1f5f9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center}.custom-selection-toolbar .menu-item:hover{background:#f8fafc}.custom-selection-toolbar .menu-item:hover .menu-text{color:var(--accent-color)}.custom-selection-toolbar .menu-item.border-none{border-bottom:none}.custom-selection-toolbar .menu-item .menu-text{font-size:15px;font-weight:500;color:#334155}.custom-selection-toolbar.color-picker{width:auto;flex-direction:row;padding:8px 12px;gap:12px;align-items:center}.custom-selection-toolbar.color-picker .color-circle{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:transform .2s ease}.custom-selection-toolbar.color-picker .color-circle:hover{transform:scale(1.2)}.custom-selection-toolbar.color-picker .toolbar-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#f1f5f9;color:#64748b;cursor:pointer;margin-left:4px}.custom-selection-toolbar.color-picker .toolbar-btn:hover{background:#e2e8f0}:host-context(.dark-mode) .custom-selection-toolbar{background:#1e293b;border-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item{border-bottom-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item:hover{background:#0f172a}:host-context(.dark-mode) .custom-selection-toolbar .menu-item .menu-text{color:#f1f5f9}:host-context(.dark-mode) .custom-selection-toolbar.color-picker .toolbar-btn{background:#334155;color:#f1f5f9}\n"] }]
|
|
2109
|
-
}], ctorParameters: () => [{ type: i0.NgZone }, { type: HttpApiService }, { type: SharedService }, { type: EpubReaderService }, { type: i0.ChangeDetectorRef }, { type: i3.ActivatedRoute }, { type: CustomDialogService }, { type:
|
|
2184
|
+
args: [{ selector: 'epub-flow', standalone: false, template: "<div id=\"reader-container\" [hidden]=\"showBookPageLoader || showDwndLoader\">\n <div id=\"reader-content\" style=\"overflow: hidden;\">\n <div id=\"reader\"></div>\n </div>\n\n <div id=\"reader-footer\">\n <div class=\"footer-container\">\n <!-- Left: Previous Button -->\n <button class=\"nav-btn prev-btn\" (click)=\"prevClick()\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M15 18L9 12L15 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Center: Progress Bar -->\n <div class=\"progress-section\">\n <div class=\"progress-label\">Read Progress</div>\n <div class=\"progress-bar-container\">\n <div class=\"progress-track\">\n <div class=\"progress-fill\" [style.width.%]=\"readPercentage.roudedOff\"></div>\n </div>\n <input type=\"range\" class=\"progress-slider\" min=\"0\" max=\"100\" [value]=\"readPercentage.roudedOff\"\n (input)=\"onProgressChange($event)\" />\n <span class=\"progress-text\">{{ readPercentage.roudedOff }}%</span>\n </div>\n </div>\n\n <!-- Right: Menu Toggle & Next Button -->\n <div class=\"right-controls\">\n <!-- Menu Toggle Button (Green) -->\n <div class=\"menu-container relative\">\n <!-- The Menu Popup -->\n @if (isMenuOpen) {\n <div class=\"menu-popup fade-in\">\n <ul class=\"menu-list\">\n <!-- Dark Mode -->\n <!-- Dark Mode -->\n @if (enableDarkMode) {\n <li (click)=\"toggleDarkMode = !toggleDarkMode; darkMode()\">\n <div class=\"menu-item\">\n <span class=\"icon moon-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M13.5 10C12.7 10.3 11.9 10.5 11 10.5C7.4 10.5 4.5 7.6 4.5 4C4.5 3.1 4.7 2.3 5 1.5C2.7 2.5 1 4.8 1 7.5C1 11.1 3.9 14 7.5 14C10.2 14 12.5 12.3 13.5 10Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>{{ toggleDarkMode ? 'Light Mode' : 'Dark Mode' }}</span>\n </div>\n </li>\n }\n\n <!-- Highlights & Notes -->\n <!-- Highlights & Notes -->\n @if (enableHighlights || enableNotes) {\n <li (click)=\"openCommonPopup(1); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon notes-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 4H14M2 8H14M2 12H8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Highlights & Notes</span>\n </div>\n </li>\n }\n\n <!-- Search Book -->\n <!-- Search Book -->\n @if (enableSearch) {\n <li (click)=\"openCommonPopup(2); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon search-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14 14L10.5 10.5M10.5 10.5C11.4 9.6 12 8.4 12 7C12 4.2 9.8 2 7 2C4.2 2 2 4.2 2 7C2 9.8 4.2 12 7 12C8.4 12 9.6 11.4 10.5 10.5Z\"\n stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span>Search Book</span>\n </div>\n </li>\n }\n\n <!-- Bookmark List -->\n <!-- Bookmark List -->\n @if (enableBookmarks) {\n <li (click)=\"getBookMarkList(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon bookmark-list-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 1.33H4C3.26 1.33 2.66 1.93 2.66 2.66V13.33C2.66 14.06 3.26 14.66 4 14.66H12C12.73 14.66 13.33 14.06 13.33 13.33V2.66C13.33 1.93 12.73 1.33 12 1.33ZM6 2.66H7.33V6L6.66 5.5L6 6V2.66ZM12 13.33H4V2.66H4.66V8.66L6.66 7.16L8.66 8.66V2.66H12V13.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Bookmark List</span>\n </div>\n </li>\n }\n\n <!-- Chapters List -->\n <!-- Chapters List -->\n @if (enableChapterList) {\n <li (click)=\"showChapterPopup(); isMenuOpen = false\">\n <div class=\"menu-item\">\n <span class=\"icon chapter-icon\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 15.33H2.66C1.93 15.33 1.33 14.73 1.33 14V4.66H2.66V14H12V15.33ZM11 8.66H7V10H11V8.66ZM10 0.66H5.33C4.6 0.66 4 1.26 4 2L4 11.33C4 12.06 4.6 12.66 5.33 12.66H12.66C13.4 12.66 14 12.06 14 11.33V4.66L10 0.66ZM12.66 11.33H5.33V2H9.44L12.66 5.22V11.33Z\"\n fill=\"currentColor\" />\n </svg>\n </span>\n <span>Chapters List</span>\n </div>\n </li>\n }\n\n <!-- Divider Row for Quick Actions -->\n <!-- Divider Row for Quick Actions -->\n <li class=\"quick-actions-row\">\n @if (enableFontSize) {\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('+')\">\n <span class=\"text-sm font-bold\">A+</span>\n </div>\n <div class=\"quick-action-btn\" (click)=\"changeFontSize('-')\">\n <span class=\"text-sm font-bold\">A-</span>\n </div>\n }\n @if (enableNotes) {\n <div class=\"quick-action-btn\" (click)=\"addNoteToPage(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M3 17.25V21H6.75L17.81 9.94L14.06 6.19L3 17.25ZM20.71 7.04C21.1 6.65 21.1 6.02 20.71 5.63L18.37 3.29C17.98 2.9 17.35 2.9 16.96 3.29L15.13 5.12L18.88 8.87L20.71 7.04Z\"\n fill=\"currentColor\" />\n </svg>\n </div>\n }\n @if (enableBookmarks) {\n <div class=\"quick-action-btn\" (click)=\"addBookMark(); isMenuOpen = false\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M17 3H7C5.9 3 5 3.9 5 5V21L12 18L19 21V5C19 3.9 18.1 3 17 3Z\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n }\n </li>\n </ul>\n </div>\n }\n\n <!-- Selection Menu Inside Footer Hub -->\n @if (freeSample === 'false') {\n @if (showHighlightOverlay) {\n <div class=\"custom-selection-toolbar selection-menu fade-in\">\n @if (enableNotes) {\n <div class=\"menu-item\" (click)=\"addNotes(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Add Notes</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"showhightLightColor = true; showHighlightOverlay = false\" title=\"Highlight\">\n <span class=\"menu-text\">Highlights</span>\n </div>\n }\n @if (enableHighlights) {\n <div class=\"menu-item\" (click)=\"addUnderline(); showHighlightOverlay = false\">\n <span class=\"menu-text\">Underline</span>\n </div>\n }\n @if (enableNotes || enableHighlights) {\n <!-- Definition often goes with these tools -->\n <div class=\"menu-item border-none\" (click)=\"openCommonPopup(4); showHighlightOverlay = false\">\n <span class=\"menu-text\">Definition</span>\n </div>\n }\n </div>\n }\n\n @if (showhightLightColor) {\n <div class=\"custom-selection-toolbar color-picker fade-in\">\n @for (color of colourCodeList; track color) {\n <div class=\"color-circle\" [style.background]=\"color\"\n (click)=\"addHighlight(color); showhightLightColor = false\"></div>\n }\n <button class=\"toolbar-btn close-colors\" (click)=\"showhightLightColor = false; showHighlightOverlay = true\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M19 12H5\"></path>\n </svg>\n </button>\n </div>\n }\n }\n\n <!-- The Green Toggle Button -->\n <button class=\"menu-toggle-btn\" (click)=\"toggleAllMenus()\"\n [class.open]=\"isMenuOpen || showHighlightOverlay || showhightLightColor\">\n <!-- X Icon when open, Burger/Menu when closed -->\n @if (isMenuOpen || showHighlightOverlay || showhightLightColor) {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n } @else {\n <!-- Menu Grid Icon -->\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6H20M4 12H20M4 18H20\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n }\n </button>\n </div>\n\n <!-- Next Button -->\n <button class=\"nav-btn next-btn\" (click)=\"nextClick()\" [class.ml-4]=\"true\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9 18L15 12L9 6\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n\n\n@if (showBookPageLoader) {\n<div class=\"fixed inset-0 z-[45] flex items-center justify-center bg-premium-loader fade-in\">\n <div class=\"text-center\">\n <div class=\"mb-8 relative inline-block\">\n <!-- Decorative Backdrop for Book -->\n <div class=\"absolute inset-0 bg-black/5 blur-2xl rounded-full transform scale-110\"></div>\n\n <!-- Larger, Premium Book Image -->\n <img [src]=\"coverImg ?? ''\" alt=\"Loading\"\n class=\"w-56 h-80 object-cover rounded-xl shadow-premium border-[6px] border-white relative z-10 animate-pulse\" />\n </div>\n\n <!-- Enhanced Loading Text Container -->\n <div class=\"flex flex-col items-center space-y-3\">\n <div class=\"flex items-center space-x-2 text-gray-400\">\n <span class=\"text-base font-medium\">Please wait a moment</span>\n <div class=\"flex space-x-1.5\">\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.15s]\"></div>\n <div class=\"w-1.5 h-1.5 bg-accent-color rounded-full animate-bounce [animation-delay:-0.3s]\"></div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n@if (showOverlay) {\n<div class=\"screenshot-overlay\"></div>\n}\n\n<!-- Full-screen Preview End Modal -->\n@if (showPreviewModal) {\n<div class=\"fixed inset-0 z-40 bg-white dark:bg-gray-900 flex flex-col items-center justify-center text-center px-4\">\n <h2\n class=\"text-[1.375rem] sm:text-2xl font-medium leading-snug text-center text-gray-800 dark:text-white mb-6 max-w-xs sm:max-w-sm mx-auto\">\n You\u2019ve reached the end of the sample for\n </h2>\n\n <img [src]=\"coverImg ?? ''\" alt=\"Book Cover\" class=\"w-40 h-auto rounded-lg shadow-lg mb-6\" />\n</div>\n}\n\n\n<!-- Custom Chapter List Modal -->\n@if (showChapterList) {\n<div class=\"custom-modal-overlay fade-in\">\n <div class=\"custom-modal-content\">\n <app-chapterlist [chapterData]=\"chaptersData\" (chapterClick)=\"onChapterSelect($event)\"\n (closeDialog)=\"showChapterList = false\">\n </app-chapterlist>\n </div>\n</div>\n}\n<epub-notification-toast></epub-notification-toast>", styles: [":host{--bg-primary: #ffffff;--bg-secondary: #f8fafc;--text-primary: #0f172a;--text-secondary: #475569;--border-base: #edf2f7;--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--accent-color: #34C759;--modal-bg: #ffffff;--modal-text: #0f172a}:host-context(.dark-mode){--bg-primary: rgb(32 33 32);--bg-secondary: rgb(42 43 42);--text-primary: #f8fafc;--text-secondary: #94a3b8;--border-base: #2d3748;--shadow-base: 0 10px 15px -3px rgba(0, 0, 0, .5);--accent-color: #32d74b;--modal-bg: rgb(32 33 32);--modal-text: #f9fafb}#reader{width:100%;height:100%}.no-select{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:default}.screenshot-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#fff;z-index:9999}img,[draggable=true]{-webkit-user-drag:none}::ng-deep *{-webkit-user-drag:none}::ng-deep .textLayer span{-webkit-user-drag:none;pointer-events:auto}.fade-in{animation:fadeIn .5s ease-in forwards}.fade-out{animation:fadeOut .5s ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@media print{#viewer{display:none!important}body:before{content:\"Printing is disabled.\";font-size:24px;color:red;text-align:center;display:block;margin-top:100px}}.progress-container{position:relative;height:4px}.range-overlay{position:absolute;top:0;left:0;width:100%;z-index:10;background:transparent;cursor:pointer;-webkit-appearance:none;appearance:none;touch-action:none}.range-overlay::-webkit-slider-thumb{-webkit-appearance:none;height:14px;width:14px;margin-top:-5px;border-radius:50%;background:#0ea951;border:2px solid #ffffff;box-shadow:0 1px 3px #0003;transition:background .2s ease,transform .2s ease}.range-overlay::-webkit-slider-thumb:hover{background:#0cb14f;transform:scale(1.1)}.range-overlay::-webkit-slider-thumb:active{background:#0ba046;transform:scale(1.15)}.range-overlay::-webkit-slider-runnable-track{background:transparent;height:4px}.range-overlay::-moz-range-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-moz-range-track{background:transparent;height:4px}.range-overlay::-ms-thumb{height:16px;width:16px;border-radius:50%;background:#0ea951;border:2px solid white}.range-overlay::-ms-track{background:transparent;height:4px;border-color:transparent;color:transparent}#reader-container:after{content:\"\";position:absolute;top:13%;bottom:10%;left:50%;transform:translate(-50%);width:2px;background:linear-gradient(to bottom,#06030300,#0d080833,#0000);box-shadow:0 0 10px #0000001a;z-index:1}@media (max-width: 767px){#reader-container:after{display:none!important}}@media (max-width: 991px){#reader-container:after{display:none!important}}::ng-deep nav{box-shadow:none!important}::ng-deep .highlightandNotes .ngneat-dialog-content{width:510px!important;padding:24px}::ng-deep .highlightandNotes .ngneat-close-dialog{top:1.2rem}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{background-color:#333;color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-close-dialog{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .ngneat-dialog-content{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-\\[\\#272C47\\]{color:#fff!important}::ng-deep .highlightandNotes.dark-mode .text-black{color:#fff!important}::ng-deep .addandeditNotepopup .ngneat-dialog-content{width:690px!important}::ng-deep .crop-popup .ngneat-dialog-content{width:420px!important}:host,app-notes{background-color:var(--bg-primary);display:flex;width:100%;justify-content:center;transition:background-color .3s ease}#reader-container{width:100%;height:98vh;background-color:var(--bg-primary);padding-top:0;display:flex;flex-direction:column;overflow:hidden;transition:background-color .3s ease}#reader-content{flex:1;overflow:hidden;position:relative}#reader-footer{position:relative;width:60vw;margin:0 auto;padding:10px 38px 20px;background:var(--bg-primary);z-index:50;transition:background-color .3s ease}#reader-footer .footer-container{display:flex;justify-content:space-between;align-items:flex-end;gap:20px}#reader-footer .nav-btn{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;cursor:pointer;transition:background .2s;background:transparent;border:none;color:var(--text-primary)}#reader-footer .nav-btn:hover{background:#f5f5f5}#reader-footer .nav-btn svg{width:20px;height:20px}#reader-footer .progress-section{flex:1;display:flex;flex-direction:column;align-items:center;max-width:600px;margin:0 auto;padding-bottom:5px}#reader-footer .progress-section .progress-label{font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.5px;color:#666;margin-bottom:6px}#reader-footer .progress-section .progress-bar-container{position:relative;width:100%;height:14px;display:flex;align-items:center}#reader-footer .progress-section .progress-bar-container .progress-track{flex:1;height:4px;background:#e7ebeb;border-radius:2px;overflow:hidden;position:relative}#reader-footer .progress-section .progress-bar-container .progress-fill{height:100%;background:#34c759;transition:width .2s ease-out;border-radius:2px}#reader-footer .progress-section .progress-bar-container .progress-slider{position:absolute;width:100%;height:100%;opacity:0;cursor:pointer;top:0;left:0;z-index:2}#reader-footer .progress-section .progress-bar-container .progress-text{margin-left:12px;font-size:12px;font-weight:600;min-width:35px;color:var(--text-primary)}#reader-footer .right-controls{display:flex;align-items:center;gap:16px}#reader-footer .menu-toggle-btn{width:48px;height:48px;border-radius:50%;background:#34c759;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);box-shadow:0 4px 10px #34c7594d;border:none}#reader-footer .menu-toggle-btn.open{background:#34c759;transform:rotate(90deg)}#reader-footer .menu-toggle-btn:hover{transform:scale(1.05);background:#2ebd50}#reader-footer .menu-popup{position:absolute;bottom:70px;right:0;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);padding:8px 0;z-index:100;border:1px solid var(--border-base);transform-origin:bottom right}#reader-footer .menu-popup .menu-list{list-style:none;padding:0;margin:0}#reader-footer .menu-popup .menu-list li{padding:0 8px;cursor:pointer}#reader-footer .menu-popup .menu-list .menu-item{display:flex;align-items:center;padding:12px;font-size:14px;font-weight:500;color:var(--text-primary);border-radius:8px;transition:background .1s}#reader-footer .menu-popup .menu-list .menu-item:hover{background:var(--bg-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon{width:32px;display:flex;align-items:center;justify-content:flex-start;color:var(--text-secondary)}#reader-footer .menu-popup .menu-list .menu-item .icon svg{width:18px;height:18px}#reader-footer .menu-popup .quick-actions-row{display:flex;justify-content:space-between;padding:12px 16px;margin-top:8px;border-top:1px solid #f0f0f0;gap:8px}#reader-footer .menu-popup .quick-actions-row .quick-action-btn{flex:1;height:40px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:var(--bg-secondary);cursor:pointer;color:var(--text-primary);transition:all .2s}#reader-footer .menu-popup .quick-actions-row .quick-action-btn:hover{background:var(--border-base)}.calibre{padding:0!important}.hightlight-overlay ::ng-deep .p-overlay{top:-232px!important}app-chapterlist ::ng-deep #reader-content{padding:0!important}.custom-modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:#0006;backdrop-filter:blur(4px);z-index:200;display:flex;align-items:center;justify-content:center}.custom-modal-content{background:var(--modal-bg);color:var(--modal-text);width:90%;max-width:500px;border-radius:12px;box-shadow:var(--shadow-base);overflow:hidden;animation:modalEnter .2s ease-out;transition:background-color .3s ease,color .3s ease}@keyframes modalEnter{0%{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(-4px)}}.animate-bounce{animation:bounce .6s infinite}.fixed{position:fixed}.inset-0{inset:0}.z-40{z-index:40}.z-45{z-index:45}.flex{display:flex}.items-center{align-items:center}.justify-center{justify-content:center}.text-center{text-align:center}.bg-white{background-color:#fff}.bg-white\\/95{background-color:#fffffff2!important}.bg-black\\/5{background-color:#0000000d}.bg-accent-color{background-color:var(--accent-color)}.bg-premium-loader{background:var(--bg-primary)}.blur-2xl{filter:blur(40px)}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1}.relative{position:relative}.absolute{position:absolute}.inline-block{display:inline-block}.z-10{z-index:10}.mb-8{margin-bottom:2rem}.space-y-3>*+*{margin-top:.75rem}.space-x-1\\.5>*+*{margin-left:.375rem}.tracking-tight{letter-spacing:-.025em}.text-gray-800{color:#1f2937}.border-\\[6px\\]{border-width:6px}.backdrop-blur-sm{backdrop-filter:blur(4px)}.w-full{width:100%}.px-4{padding-left:1rem;padding-right:1rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-\\[-1\\.5rem\\]{margin-top:-1.5rem}.ml-1{margin-left:.25rem}.space-x-1>*+*{margin-left:.25rem}.space-x-2>*+*{margin-left:.5rem}.inline-flex{display:inline-flex}.text-gray-700{color:#374151}.text-gray-400{color:#9ca3af}.text-lg{font-size:1.125rem}.text-xl{font-size:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.w-40{width:10rem}.h-56{height:14rem}.w-56{width:14rem}.h-80{height:20rem}.w-32{width:8rem}.h-44{height:11rem}.object-cover{object-fit:cover}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.shadow-2xl{box-shadow:0 25px 50px -12px #00000040}.shadow-premium{box-shadow:0 20px 25px -5px #0000001a,0 10px 10px -5px #0000000a,0 0 0 1px #0000000d}.mx-auto{margin-left:auto;margin-right:auto}.border-4{border-width:4px}.border-white{border-color:#fff}.border-gray-50{border-color:#f9fafb}.w-1\\.5{width:.375rem}.h-1\\.5{height:.375rem}.bg-gray-400{background-color:#9ca3af}.rounded-full{border-radius:9999px}.custom-selection-toolbar{position:absolute;bottom:70px;right:0;z-index:100;width:280px;background:var(--bg-primary);border-radius:16px;box-shadow:var(--shadow-base);display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--border-base);padding:8px 0;transform-origin:bottom right}.custom-selection-toolbar .menu-item{padding:12px 20px;border-bottom:1px solid #f1f5f9;cursor:pointer;transition:all .2s ease;display:flex;align-items:center}.custom-selection-toolbar .menu-item:hover{background:#f8fafc}.custom-selection-toolbar .menu-item:hover .menu-text{color:var(--accent-color)}.custom-selection-toolbar .menu-item.border-none{border-bottom:none}.custom-selection-toolbar .menu-item .menu-text{font-size:15px;font-weight:500;color:#334155}.custom-selection-toolbar.color-picker{width:auto;flex-direction:row;padding:8px 12px;gap:12px;align-items:center}.custom-selection-toolbar.color-picker .color-circle{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:transform .2s ease}.custom-selection-toolbar.color-picker .color-circle:hover{transform:scale(1.2)}.custom-selection-toolbar.color-picker .toolbar-btn{display:flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;border:none;background:#f1f5f9;color:#64748b;cursor:pointer;margin-left:4px}.custom-selection-toolbar.color-picker .toolbar-btn:hover{background:#e2e8f0}:host-context(.dark-mode) .custom-selection-toolbar{background:#1e293b;border-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item{border-bottom-color:#334155}:host-context(.dark-mode) .custom-selection-toolbar .menu-item:hover{background:#0f172a}:host-context(.dark-mode) .custom-selection-toolbar .menu-item .menu-text{color:#f1f5f9}:host-context(.dark-mode) .custom-selection-toolbar.color-picker .toolbar-btn{background:#334155;color:#f1f5f9}\n"] }]
|
|
2185
|
+
}], ctorParameters: () => [{ type: i0.NgZone }, { type: HttpApiService }, { type: SharedService }, { type: EpubReaderService }, { type: i0.ChangeDetectorRef }, { type: i3.ActivatedRoute }, { type: CustomDialogService }, { type: NotificationService }, { type: i1$2.Location }, { type: Object, decorators: [{
|
|
2110
2186
|
type: Inject,
|
|
2111
2187
|
args: [PLATFORM_ID]
|
|
2112
2188
|
}] }, { type: i3.Router }, { type: i1$1.Overlay }], propDecorators: { epubUrl: [{
|
|
@@ -2146,7 +2222,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
2146
2222
|
class EpubLoaderComponent {
|
|
2147
2223
|
loadPercentage = input(null);
|
|
2148
2224
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2149
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: EpubLoaderComponent, isStandalone: false, selector: "app-epub-loader", inputs: { loadPercentage: { classPropertyName: "loadPercentage", publicName: "loadPercentage", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"page-loader\">\n <div class=\"flex flex-col w-full loader-container\">\n <div class=\"text-black text-2xl font-bold mb-2\">Reader Loading</div>\n <p-progressBar\n [value]=\"loadPercentage()\"\n class=\"reader-progress w-full\"\n />\n <div class=\"text-percentage text-base font-normal inline-flex m-auto mt-3\">\n {{ loadPercentage() ? loadPercentage() : '0' }}\n </div>\n </div>\n</div>\n", styles: [".page-loader{position:fixed;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;top:0;background:#fff;z-index:99}.page-loader .loader-container{max-width:80%}@media (min-width: 768px){.page-loader .loader-container{max-width:410px}}\n"]
|
|
2225
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: EpubLoaderComponent, isStandalone: false, selector: "app-epub-loader", inputs: { loadPercentage: { classPropertyName: "loadPercentage", publicName: "loadPercentage", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"page-loader\">\n <div class=\"flex flex-col w-full loader-container\">\n <div class=\"text-black text-2xl font-bold mb-2\">Reader Loading</div>\n <p-progressBar\n [value]=\"loadPercentage()\"\n class=\"reader-progress w-full\"\n />\n <div class=\"text-percentage text-base font-normal inline-flex m-auto mt-3\">\n {{ loadPercentage() ? loadPercentage() : '0' }}\n </div>\n </div>\n</div>\n", styles: [".page-loader{position:fixed;left:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;top:0;background:#fff;z-index:99}.page-loader .loader-container{max-width:80%}@media (min-width: 768px){.page-loader .loader-container{max-width:410px}}\n"] });
|
|
2150
2226
|
}
|
|
2151
2227
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubLoaderComponent, decorators: [{
|
|
2152
2228
|
type: Component,
|
|
@@ -2173,18 +2249,17 @@ class EpubReaderModule {
|
|
|
2173
2249
|
EpubLoaderComponent], imports: [CommonModule, i3.RouterModule, NgxEditorModule,
|
|
2174
2250
|
FormsModule,
|
|
2175
2251
|
ReactiveFormsModule,
|
|
2176
|
-
|
|
2177
|
-
ProgressBarModule,
|
|
2178
|
-
TableModule,
|
|
2179
|
-
ButtonModule,
|
|
2252
|
+
ReactiveFormsModule,
|
|
2180
2253
|
NoDataFoundComponent,
|
|
2181
2254
|
HttpClientModule,
|
|
2182
|
-
SkeletonLoaderComponent
|
|
2255
|
+
SkeletonLoaderComponent,
|
|
2256
|
+
NotificationToastComponent], exports: [ReaderMainComponent,
|
|
2183
2257
|
AddNotesComponent,
|
|
2184
2258
|
EpubCommonPopupComponent,
|
|
2185
2259
|
ChapterlistComponent,
|
|
2186
2260
|
EpubLoaderComponent,
|
|
2187
|
-
SkeletonLoaderComponent
|
|
2261
|
+
SkeletonLoaderComponent,
|
|
2262
|
+
NotificationToastComponent] });
|
|
2188
2263
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubReaderModule, providers: [
|
|
2189
2264
|
CustomDialogService,
|
|
2190
2265
|
EpubReaderService
|
|
@@ -2193,13 +2268,11 @@ class EpubReaderModule {
|
|
|
2193
2268
|
NgxEditorModule,
|
|
2194
2269
|
FormsModule,
|
|
2195
2270
|
ReactiveFormsModule,
|
|
2196
|
-
|
|
2197
|
-
ProgressBarModule,
|
|
2198
|
-
TableModule,
|
|
2199
|
-
ButtonModule,
|
|
2271
|
+
ReactiveFormsModule,
|
|
2200
2272
|
NoDataFoundComponent,
|
|
2201
2273
|
HttpClientModule,
|
|
2202
|
-
SkeletonLoaderComponent
|
|
2274
|
+
SkeletonLoaderComponent,
|
|
2275
|
+
NotificationToastComponent] });
|
|
2203
2276
|
}
|
|
2204
2277
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: EpubReaderModule, decorators: [{
|
|
2205
2278
|
type: NgModule,
|
|
@@ -2217,13 +2290,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
2217
2290
|
NgxEditorModule,
|
|
2218
2291
|
FormsModule,
|
|
2219
2292
|
ReactiveFormsModule,
|
|
2220
|
-
|
|
2221
|
-
ProgressBarModule,
|
|
2222
|
-
TableModule,
|
|
2223
|
-
ButtonModule,
|
|
2293
|
+
ReactiveFormsModule,
|
|
2224
2294
|
NoDataFoundComponent,
|
|
2225
2295
|
HttpClientModule,
|
|
2226
2296
|
SkeletonLoaderComponent,
|
|
2297
|
+
NotificationToastComponent,
|
|
2227
2298
|
],
|
|
2228
2299
|
providers: [
|
|
2229
2300
|
CustomDialogService,
|
|
@@ -2235,7 +2306,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
2235
2306
|
EpubCommonPopupComponent,
|
|
2236
2307
|
ChapterlistComponent,
|
|
2237
2308
|
EpubLoaderComponent,
|
|
2238
|
-
SkeletonLoaderComponent
|
|
2309
|
+
SkeletonLoaderComponent,
|
|
2310
|
+
NotificationToastComponent
|
|
2239
2311
|
],
|
|
2240
2312
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
2241
2313
|
}]
|
|
@@ -2247,5 +2319,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
2247
2319
|
* Generated bundle index. Do not edit.
|
|
2248
2320
|
*/
|
|
2249
2321
|
|
|
2250
|
-
export { AddNotesComponent, ChapterlistComponent, EpubCommonPopupComponent, EpubLoaderComponent, EpubReaderModule, EpubReaderService, ReaderMainComponent, SkeletonLoaderComponent };
|
|
2322
|
+
export { AddNotesComponent, ChapterlistComponent, EpubCommonPopupComponent, EpubLoaderComponent, EpubReaderModule, EpubReaderService, NotificationService, NotificationToastComponent, ReaderMainComponent, SkeletonLoaderComponent };
|
|
2251
2323
|
//# sourceMappingURL=epub-flow.mjs.map
|