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')}}
{{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": {