From b0b0c18d73715e4a26958c18b6c89968066c2986 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Sun, 1 Jun 2025 09:10:05 -0500 Subject: [PATCH] Fixed tooltips being slightly opaque. Refactored Amelia's attempt at clearing up the section code and added some new controls to make paging easier. Book/Manga reader go to page is now using a custom styled prompt instead of the basic window.prompt. This code contains goToSection() that is not implemented. --- .../book-reader/book-reader.component.html | 53 +++++++++------- .../book-reader/book-reader.component.scss | 6 +- .../book-reader/book-reader.component.ts | 60 +++++++++++++++---- .../table-of-contents.component.ts | 3 +- .../manga-reader/manga-reader.component.ts | 26 +++++--- .../confirm-dialog/_models/confirm-config.ts | 4 +- .../confirm-dialog.component.html | 14 ++++- .../confirm-dialog.component.ts | 17 ++++-- UI/Web/src/app/shared/confirm.service.ts | 48 ++++++++++++--- UI/Web/src/assets/langs/en.json | 16 +++-- UI/Web/src/styles.scss | 1 + UI/Web/src/theme/components/_buttons.scss | 6 +- UI/Web/src/theme/components/_tooltip.scss | 4 ++ UI/Web/src/theme/themes/dark.scss | 1 - 14 files changed, 186 insertions(+), 73 deletions(-) create mode 100644 UI/Web/src/theme/components/_tooltip.scss diff --git a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.html b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.html index cc61b8e5c..22cd086e7 100644 --- a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.html +++ b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.html @@ -20,37 +20,44 @@
- -
-
- {{t('page-label')}} -
-
- -
{{vp[0]}}
-
- -
-
{{vp[1]}}
- -
-
-
-
{{t('pagination-header')}}
- -
{{pageNum}}
-
+ + +
{{pageNum}}
+
+
{{maxPages - 1}}
- +
+ + + @if (layoutMode !== BookPageLayoutMode.Default) { + @let vp = getVirtualPage(); +
+
+ {{t('section-label')}} +
+
+ +
{{vp[0]}}
+
+ + +
+
{{vp[1]}}
+ +
+
+ }
diff --git a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.scss b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.scss index dcfa9ddcd..8f45302c3 100644 --- a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.scss +++ b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.scss @@ -277,9 +277,9 @@ $action-bar-height: 38px; } .virt-pagination-cont { - padding-bottom: 5px; - margin-bottom: 5px; - box-shadow: var(--drawer-pagination-horizontal-rule); + padding-bottom: 5px; + margin-bottom: 5px; + box-shadow: var(--drawer-pagination-horizontal-rule); } .bottom-bar { diff --git a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts index 6abd619f8..05763e74a 100644 --- a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts +++ b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts @@ -63,6 +63,7 @@ import { PersonalToCEvent } from "../personal-table-of-contents/personal-table-of-contents.component"; import {translate, TranslocoDirective} from "@jsverse/transloco"; +import {ConfirmService} from "../../../shared/confirm.service"; enum TabID { @@ -133,6 +134,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { private readonly utilityService = inject(UtilityService); private readonly libraryService = inject(LibraryService); private readonly themeService = inject(ThemeService); + private readonly confirmService = inject(ConfirmService); private readonly cdRef = inject(ChangeDetectorRef); protected readonly BookPageLayoutMode = BookPageLayoutMode; @@ -730,7 +732,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } @HostListener('window:keydown', ['$event']) - handleKeyPress(event: KeyboardEvent) { + async handleKeyPress(event: KeyboardEvent) { const activeElement = document.activeElement as HTMLElement; const isInputFocused = activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'; if (isInputFocused) return; @@ -748,7 +750,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { event.stopPropagation(); event.preventDefault(); } else if (event.key === KEY_CODES.G) { - this.goToPage(); + await this.goToPage(); } else if (event.key === KEY_CODES.F) { this.toggleFullscreen() } @@ -905,37 +907,69 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } - promptForPage() { - const question = translate('book-reader.go-to-page-prompt', {totalPages: this.maxPages - 1}); - const goToPageNum = window.prompt(question, ''); + async promptForPage() { + const promptConfig = {...this.confirmService.defaultPrompt}; + promptConfig.header = translate('book-reader.go-to-page'); + promptConfig.content = translate('book-reader.go-to-page-prompt', {totalPages: this.maxPages - 1}); + + const goToPageNum = await this.confirmService.prompt(undefined, promptConfig); + if (goToPageNum === null || goToPageNum.trim().length === 0) { return null; } return goToPageNum; } - goToPage(pageNum?: number) { + async promptForSection() { + const [_, totalVirtualPages, _2] = this.getVirtualPage(); + const promptConfig = {...this.confirmService.defaultPrompt}; + promptConfig.header = translate('book-reader.go-to-section'); + promptConfig.content = translate('book-reader.go-to-section-prompt', {totalSections: totalVirtualPages}); + + const goToPageNum = await this.confirmService.prompt(undefined, promptConfig); + if (goToPageNum === null || goToPageNum.trim().length === 0 || !/^[0-9]+$/.test(goToPageNum)) { return null; } + + return Math.min(Math.max(parseInt(goToPageNum, 10), 0), totalVirtualPages - 1) + ''; + } + + async goToPage(pageNum?: number) { let page = pageNum; if (pageNum === null || pageNum === undefined) { - const goToPageNum = this.promptForPage(); + const goToPageNum = await this.promptForPage(); if (goToPageNum === null) { return; } + page = parseInt(goToPageNum.trim(), 10); } if (page === undefined || this.pageNum === page) { return; } - if (page > this.maxPages) { - page = this.maxPages; + if (page > this.maxPages - 1) { + page = this.maxPages - 1; } else if (page < 0) { page = 0; } - if (!(page === 0 || page === this.maxPages - 1)) { - page -= 1; - } - this.pageNum = page; this.loadPage(); } + async loadSection(sectionNum?: number) { + let section = sectionNum; + if (sectionNum === null || sectionNum === undefined) { + const goToPageNum = await this.promptForSection(); + if (goToPageNum === null) { return; } + section = parseInt(goToPageNum.trim(), 10); + } + + if (section === undefined || this.pageNum === section) { return; } + + if (section > this.maxPages - 1) { + section = this.maxPages - 1; + } else if (section < 0) { + section = 0; + } + + // HACK + } + diff --git a/UI/Web/src/app/book-reader/_components/table-of-contents/table-of-contents.component.ts b/UI/Web/src/app/book-reader/_components/table-of-contents/table-of-contents.component.ts index 1fccdefbe..ce3a180ed 100644 --- a/UI/Web/src/app/book-reader/_components/table-of-contents/table-of-contents.component.ts +++ b/UI/Web/src/app/book-reader/_components/table-of-contents/table-of-contents.component.ts @@ -31,9 +31,8 @@ export class TableOfContentsComponent implements OnChanges { @Output() loadChapter: EventEmitter<{pageNum: number, part: string}> = new EventEmitter(); ngOnChanges(changes: SimpleChanges) { - console.log('Current Page: ', this.pageNum, this.currentPageAnchor); + //console.log('Current Page: ', this.pageNum, this.currentPageAnchor); this.cdRef.markForCheck(); - } cleanIdSelector(id: string) { diff --git a/UI/Web/src/app/manga-reader/_components/manga-reader/manga-reader.component.ts b/UI/Web/src/app/manga-reader/_components/manga-reader/manga-reader.component.ts index 595ae6079..a7bbe2d90 100644 --- a/UI/Web/src/app/manga-reader/_components/manga-reader/manga-reader.component.ts +++ b/UI/Web/src/app/manga-reader/_components/manga-reader/manga-reader.component.ts @@ -70,6 +70,7 @@ import {LoadingComponent} from '../../../shared/loading/loading.component'; import {translate, TranslocoDirective} from "@jsverse/transloco"; import {shareReplay} from "rxjs/operators"; import {DblClickDirective} from "../../../_directives/dbl-click.directive"; +import {ConfirmService} from "../../../shared/confirm.service"; const PREFETCH_PAGES = 10; @@ -150,9 +151,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy { private readonly modalService = inject(NgbModal); private readonly cdRef = inject(ChangeDetectorRef); private readonly toastr = inject(ToastrService); - public readonly readerService = inject(ReaderService); - public readonly utilityService = inject(UtilityService); - public readonly mangaReaderService = inject(MangaReaderService); + private readonly confirmService = inject(ConfirmService); + protected readonly readerService = inject(ReaderService); + protected readonly utilityService = inject(UtilityService); + protected readonly mangaReaderService = inject(MangaReaderService); + protected readonly KeyDirection = KeyDirection; protected readonly ReaderMode = ReaderMode; @@ -647,7 +650,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy { } @HostListener('window:keyup', ['$event']) - handleKeyPress(event: KeyboardEvent) { + async handleKeyPress(event: KeyboardEvent) { switch (this.readerMode) { case ReaderMode.LeftRight: if (event.key === KEY_CODES.RIGHT_ARROW) { @@ -682,7 +685,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy { } else if (event.key === KEY_CODES.SPACE) { this.toggleMenu(); } else if (event.key === KEY_CODES.G) { - const goToPageNum = this.promptForPage(); + const goToPageNum = await this.promptForPage(); if (goToPageNum === null) { return; } this.goToPage(parseInt(goToPageNum.trim(), 10)); } else if (event.key === KEY_CODES.B) { @@ -1593,9 +1596,16 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy { } // This is menu only code - promptForPage() { - const question = translate('book-reader.go-to-page-prompt', {totalPages: this.maxPages}); - const goToPageNum = window.prompt(question, ''); + async promptForPage() { + // const question = translate('book-reader.go-to-page-prompt', {totalPages: this.maxPages}); + // const goToPageNum = window.prompt(question, ''); + + const promptConfig = {...this.confirmService.defaultPrompt}; + promptConfig.header = translate('book-reader.go-to-page'); + promptConfig.content = translate('book-reader.go-to-page-prompt', {totalPages: this.maxPages}); + + const goToPageNum = await this.confirmService.prompt(undefined, promptConfig); + if (goToPageNum === null || goToPageNum.trim().length === 0) { return null; } return goToPageNum; } diff --git a/UI/Web/src/app/shared/confirm-dialog/_models/confirm-config.ts b/UI/Web/src/app/shared/confirm-dialog/_models/confirm-config.ts index 481c9b48c..7cfd257e2 100644 --- a/UI/Web/src/app/shared/confirm-dialog/_models/confirm-config.ts +++ b/UI/Web/src/app/shared/confirm-dialog/_models/confirm-config.ts @@ -1,7 +1,7 @@ -import { ConfirmButton } from './confirm-button'; +import {ConfirmButton} from './confirm-button'; export class ConfirmConfig { - _type: 'confirm' | 'alert' | 'info' = 'confirm'; + _type: 'confirm' | 'alert' | 'info' | 'prompt' = 'confirm'; header: string = 'Confirm'; content: string = ''; buttons: Array = []; diff --git a/UI/Web/src/app/shared/confirm-dialog/confirm-dialog.component.html b/UI/Web/src/app/shared/confirm-dialog/confirm-dialog.component.html index 21b741cd3..213c80ceb 100644 --- a/UI/Web/src/app/shared/confirm-dialog/confirm-dialog.component.html +++ b/UI/Web/src/app/shared/confirm-dialog/confirm-dialog.component.html @@ -5,8 +5,18 @@ }
- + + @if (config._type === 'prompt') { + + } @else { + + } +