diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index d670fec12..d3837e637 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -21,8 +21,6 @@ "@fortawesome/fontawesome-free": "^6.4.2", "@iharbeck/ngx-virtual-scroller": "^16.0.0", "@iplab/ngx-file-upload": "^16.0.2", - "@lithiumjs/angular": "^7.3.0", - "@lithiumjs/ngx-virtual-scroll": "^0.3.0", "@microsoft/signalr": "^7.0.12", "@ng-bootstrap/ng-bootstrap": "^15.1.2", "@ngneat/transloco": "^6.0.0", @@ -3716,33 +3714,6 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, - "node_modules/@lithiumjs/angular": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@lithiumjs/angular/-/angular-7.3.0.tgz", - "integrity": "sha512-81nXyT9I2J+VpeFEDtOvfP4imlrLueoqFYBZR8PCrlY9cjDzgFAZBq7mCOLxOhi0xL5wF9hM0iDqlmI9LDct1Q==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/core": ">=11.0.0 <17.0.0", - "rxjs": ">=7.x.x", - "typescript": ">=4.1.0" - } - }, - "node_modules/@lithiumjs/ngx-virtual-scroll": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@lithiumjs/ngx-virtual-scroll/-/ngx-virtual-scroll-0.3.0.tgz", - "integrity": "sha512-fYZR1S66c4ATg6mDVwJaZxsZ8rT/jcJ07b95x5sZVV7gtiDv7DDUCiMa4mtvj71fqMzcoeRe99G0FivVUwvZ0Q==", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "8.x.x - 16.x.x", - "@angular/core": "8.x.x - 16.x.x", - "@lithiumjs/angular": ">=7.0.0", - "rxjs": "6.x.x - 7.x.x" - } - }, "node_modules/@microsoft/signalr": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.12.tgz", diff --git a/UI/Web/package.json b/UI/Web/package.json index 0beadfc29..157beae6a 100644 --- a/UI/Web/package.json +++ b/UI/Web/package.json @@ -26,8 +26,6 @@ "@fortawesome/fontawesome-free": "^6.4.2", "@iharbeck/ngx-virtual-scroller": "^16.0.0", "@iplab/ngx-file-upload": "^16.0.2", - "@lithiumjs/angular": "^7.3.0", - "@lithiumjs/ngx-virtual-scroll": "^0.3.0", "@microsoft/signalr": "^7.0.12", "@ng-bootstrap/ng-bootstrap": "^15.1.2", "@ngneat/transloco": "^6.0.0", diff --git a/UI/Web/src/app/_models/library.ts b/UI/Web/src/app/_models/library.ts index 5687038ba..d721231a9 100644 --- a/UI/Web/src/app/_models/library.ts +++ b/UI/Web/src/app/_models/library.ts @@ -10,7 +10,7 @@ export interface Library { lastScanned: string; type: LibraryType; folders: string[]; - coverImage?: string; + coverImage?: string | null; folderWatching: boolean; includeInDashboard: boolean; includeInRecommended: boolean; diff --git a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html index 0501e7804..dda773cb3 100644 --- a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html +++ b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html @@ -24,7 +24,7 @@

- +
- diff --git a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts index 7f81149d8..92c81c474 100644 --- a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts +++ b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts @@ -39,6 +39,9 @@ import {TranslocoDirective} from "@ngneat/transloco"; import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component"; import {SeriesFilterV2} from "../../_models/metadata/v2/series-filter-v2"; + +const ANIMATION_TIME_MS = 0; + @Component({ selector: 'app-card-detail-layout', standalone: true, @@ -49,6 +52,13 @@ import {SeriesFilterV2} from "../../_models/metadata/v2/series-filter-v2"; }) export class CardDetailLayoutComponent implements OnInit, OnChanges { + private readonly filterUtilityService = inject(FilterUtilitiesService); + protected readonly utilityService = inject(UtilityService); + private readonly cdRef = inject(ChangeDetectorRef); + private readonly jumpbarService = inject(JumpbarService); + private readonly router = inject(Router); + private readonly scrollService = inject(ScrollService); + @Input() header: string = ''; @Input() isLoading: boolean = false; @Input() items: any[] = []; @@ -89,7 +99,6 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { @ViewChild(VirtualScrollerComponent) private virtualScroller!: VirtualScrollerComponent; - private readonly filterUtilityService = inject(FilterUtilitiesService); filter: SeriesFilterV2 = this.filterUtilityService.createSeriesV2Filter(); libraries: Array> = []; @@ -97,15 +106,9 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { hasResumedJumpKey: boolean = false; bufferAmount: number = 1; + protected readonly Breakpoint = Breakpoint; - get Breakpoint() { - return Breakpoint; - } - - constructor(public utilityService: UtilityService, - @Inject(DOCUMENT) private document: Document, private cdRef: ChangeDetectorRef, - private jumpbarService: JumpbarService, private router: Router, private scrollService: ScrollService) { - } + constructor(@Inject(DOCUMENT) private document: Document) {} @HostListener('window:resize', ['$event']) @HostListener('window:orientationchange', ['$event']) @@ -136,6 +139,8 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { this.virtualScroller.refresh(); }); } + + } @@ -143,6 +148,8 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { this.jumpBarKeysToRender = [...this.jumpBarKeys]; this.resizeJumpBar(); + // TODO: I wish I had signals so I can tap into when isLoading is false and trigger the scroll code + // Don't resume jump key when there is a custom sort order, as it won't work if (!this.hasCustomSort()) { if (!this.hasResumedJumpKey && this.jumpBarKeysToRender.length > 0) { @@ -154,14 +161,15 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { this.hasResumedJumpKey = true; setTimeout(() => this.scrollTo(keys[0]), 100); } - } else { - // I will come back and refactor this to work - // const scrollPosition = this.jumpbarService.getResumePosition(this.router.url); - // console.log('scroll position: ', scrollPosition); - // if (scrollPosition > 0) { - // setTimeout(() => this.virtualScroller.scrollToIndex(scrollPosition, true, 0, 1000), 100); - // } } + // else { + // // I will come back and refactor this to work + // // const scrollPosition = this.jumpbarService.getResumePosition(this.router.url); + // // console.log('scroll position: ', scrollPosition); + // // if (scrollPosition > 0) { + // // setTimeout(() => this.virtualScroller.scrollToIndex(scrollPosition, true, 0, 1000), 100); + // // } + // } } hasCustomSort() { @@ -192,10 +200,11 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges { targetIndex += this.jumpBarKeys[i].size; } - this.virtualScroller.scrollToIndex(targetIndex, true, 0, 1000); + this.virtualScroller.scrollToIndex(targetIndex, true, 0, ANIMATION_TIME_MS); this.jumpbarService.saveResumeKey(this.router.url, jumpKey.key); // TODO: This doesn't work, we need the offset from virtual scroller this.jumpbarService.saveScrollOffset(this.router.url, this.scrollService.scrollPosition); + this.cdRef.markForCheck(); } diff --git a/UI/Web/src/app/collections/_components/collection-detail/collection-detail.component.ts b/UI/Web/src/app/collections/_components/collection-detail/collection-detail.component.ts index c8b2d8d47..af026d3e6 100644 --- a/UI/Web/src/app/collections/_components/collection-detail/collection-detail.component.ts +++ b/UI/Web/src/app/collections/_components/collection-detail/collection-detail.component.ts @@ -243,7 +243,6 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked { this.pagination = series.pagination; this.jumpbarKeys = this.jumpbarService.getJumpKeys(this.series, (series: Series) => series.name); this.isLoading = false; - window.scrollTo(0, 0); this.cdRef.markForCheck(); }); } diff --git a/UI/Web/src/app/library-detail/library-detail.component.ts b/UI/Web/src/app/library-detail/library-detail.component.ts index 1e70eb032..a3c7b1b5e 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.ts +++ b/UI/Web/src/app/library-detail/library-detail.component.ts @@ -281,10 +281,8 @@ export class LibraryDetailComponent implements OnInit { this.pagination = series.pagination; this.loadingSeries = false; this.cdRef.markForCheck(); - window.scrollTo(0, 0); }); } trackByIdentity = (index: number, item: Series) => `${item.id}_${item.name}_${item.localizedName}_${item.pagesRead}`; - protected readonly undefined = undefined; } diff --git a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts index 83b9e72d9..7060291a8 100644 --- a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts +++ b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts @@ -18,7 +18,6 @@ import {BulkSelectionService} from "../../../cards/bulk-selection.service"; import {SeriesCardComponent} from "../../../cards/series-card/series-card.component"; import {FormsModule} from "@angular/forms"; import {takeUntilDestroyed} from "@angular/core/rxjs-interop"; -import {NgxVirtualScrollModule} from "@lithiumjs/ngx-virtual-scroll"; export interface IndexUpdateEvent { fromPosition: number; @@ -39,8 +38,7 @@ export interface ItemRemoveEvent { changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgIf, VirtualScrollerModule, NgFor, NgTemplateOutlet, CdkDropList, CdkDrag, - CdkDragHandle, TranslocoDirective, NgClass, SeriesCardComponent, FormsModule, - NgxVirtualScrollModule, NgxVirtualScrollModule] + CdkDragHandle, TranslocoDirective, NgClass, SeriesCardComponent, FormsModule] }) export class DraggableOrderedListComponent { diff --git a/UI/Web/src/app/reading-list/_components/reading-lists/reading-lists.component.ts b/UI/Web/src/app/reading-list/_components/reading-lists/reading-lists.component.ts index c5dec74f2..b71b45435 100644 --- a/UI/Web/src/app/reading-list/_components/reading-lists/reading-lists.component.ts +++ b/UI/Web/src/app/reading-list/_components/reading-lists/reading-lists.component.ts @@ -115,7 +115,6 @@ export class ReadingListsComponent implements OnInit { this.loadingLists = false; this.actions = {}; this.lists.forEach(l => this.actions[l.id] = this.getActions(l)); - window.scrollTo(0, 0); this.cdRef.markForCheck(); }); } diff --git a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts index f095c4d93..5e2720227 100644 --- a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts +++ b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts @@ -777,8 +777,8 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked { const modalRef = this.modalService.open(EditSeriesModalComponent, { size: 'xl' }); modalRef.componentInstance.series = this.series; modalRef.closed.subscribe((closeResult: {success: boolean, series: Series, coverImageUpdate: boolean}) => { - window.scrollTo(0, 0); if (closeResult.success) { + window.scrollTo(0, 0); this.loadSeries(this.seriesId); } diff --git a/UI/Web/src/app/shared/_services/download.service.ts b/UI/Web/src/app/shared/_services/download.service.ts index f4ecf664d..79ad52964 100644 --- a/UI/Web/src/app/shared/_services/download.service.ts +++ b/UI/Web/src/app/shared/_services/download.service.ts @@ -271,13 +271,20 @@ export class DownloadService { } private save(blob: Blob, filename: string) { - const saveLink = document.createElement( 'a' ); - if (saveLink.href) { - URL.revokeObjectURL(saveLink.href); - } - saveLink.href = URL.createObjectURL(blob); + const saveLink = document.createElement('a'); + saveLink.style.display = 'none'; + document.body.appendChild(saveLink); + + const url = URL.createObjectURL(blob); + saveLink.href = url; saveLink.download = filename; - saveLink.dispatchEvent( new MouseEvent( 'click' ) ); + + // Trigger the click event + saveLink.click(); + + // Cleanup + URL.revokeObjectURL(url); + document.body.removeChild(saveLink); } } diff --git a/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.html b/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.html index 8434381e4..7915b9e16 100644 --- a/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.html +++ b/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.html @@ -80,7 +80,7 @@

{{t('cover-description-extra')}}

diff --git a/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.ts b/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.ts index e555da793..e9969dc33 100644 --- a/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.ts +++ b/UI/Web/src/app/sidenav/_modals/library-settings-modal/library-settings-modal.component.ts @@ -55,9 +55,10 @@ enum StepID { }) export class LibrarySettingsModalComponent implements OnInit { - @Input({required: true}) library!: Library; private readonly destroyRef = inject(DestroyRef); + @Input({required: true}) library!: Library; + active = TabID.General; imageUrls: Array = []; @@ -81,8 +82,8 @@ export class LibrarySettingsModalComponent implements OnInit { isAddLibrary = false; setupStep = StepID.General; - get Breakpoint() { return Breakpoint; } - get TabID() { return TabID; } + protected readonly Breakpoint = Breakpoint; + protected readonly TabID = TabID; constructor(public utilityService: UtilityService, private uploadService: UploadService, private modalService: NgbModal, private settingService: SettingsService, public modal: NgbActiveModal, private confirmService: ConfirmService, diff --git a/UI/Web/src/app/want-to-read/_components/want-to-read/want-to-read.component.ts b/UI/Web/src/app/want-to-read/_components/want-to-read/want-to-read.component.ts index 54d03e49e..3e6cfc091 100644 --- a/UI/Web/src/app/want-to-read/_components/want-to-read/want-to-read.component.ts +++ b/UI/Web/src/app/want-to-read/_components/want-to-read/want-to-read.component.ts @@ -176,7 +176,6 @@ export class WantToReadComponent implements OnInit, AfterContentChecked { this.pagination = paginatedList.pagination; this.jumpbarKeys = this.jumpbarService.getJumpKeys(this.series, (series: Series) => series.name); this.isLoading = false; - window.scrollTo(0, 0); this.cdRef.markForCheck(); }); } diff --git a/UI/Web/src/assets/langs/en.json b/UI/Web/src/assets/langs/en.json index 154a2eb6f..2b37050fe 100644 --- a/UI/Web/src/assets/langs/en.json +++ b/UI/Web/src/assets/langs/en.json @@ -892,7 +892,8 @@ }, "card-detail-layout": { - "total-items": "{{count}} total items" + "total-items": "{{count}} total items", + "jumpkey-count": "{{count}} Series" }, "card-item": {