Library Recomendations (#1236)

* Updated cover regex for finding cover images in archives to ignore back_cover or back-cover

* Fixed an issue where Tags wouldn't save due to not pulling them from the DB.

* Refactored All series to it's own lazy loaded module

* Modularized Dashboard and library detail. Had to change main dashboard page to be libraries. Subject to change.

* Refactored login component into registration module

* Series Detail module created

* Refactored nav stuff into it's own module, not lazy loaded, but self contained.

* Refactored theme component into a dev only module so we don't incur load for temp testing modules

* Finished off modularization code. Only missing thing is to re-introduce some dashboard functionality for library view.

* Implemented a basic recommendation page for library detail
This commit is contained in:
Joseph Milazzo 2022-04-29 17:27:01 -05:00 committed by GitHub
parent 743a3ba935
commit f237aa7ab7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 1077 additions and 501 deletions

View file

@ -0,0 +1,184 @@
import { DOCUMENT } from '@angular/common';
import { Component, HostListener, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ScrollService } from 'src/app/_services/scroll.service';
import { FilterQueryParam } from '../../shared/_services/filter-utilities.service';
import { CollectionTag } from '../../_models/collection-tag';
import { Library } from '../../_models/library';
import { PersonRole } from '../../_models/person';
import { ReadingList } from '../../_models/reading-list';
import { SearchResult } from '../../_models/search-result';
import { SearchResultGroup } from '../../_models/search/search-result-group';
import { AccountService } from '../../_services/account.service';
import { ImageService } from '../../_services/image.service';
import { LibraryService } from '../../_services/library.service';
import { NavService } from '../../_services/nav.service';
@Component({
selector: 'app-nav-header',
templateUrl: './nav-header.component.html',
styleUrls: ['./nav-header.component.scss']
})
export class NavHeaderComponent implements OnInit, OnDestroy {
@ViewChild('search') searchViewRef!: any;
isLoading = false;
debounceTime = 300;
imageStyles = {width: '24px', 'margin-top': '5px'};
searchResults: SearchResultGroup = new SearchResultGroup();
searchTerm = '';
customFilter: (items: SearchResult[], query: string) => SearchResult[] = (items: SearchResult[], query: string) => {
const normalizedQuery = query.trim().toLowerCase();
const matches = items.filter(item => {
const normalizedSeriesName = item.name.toLowerCase().trim();
const normalizedOriginalName = item.originalName.toLowerCase().trim();
const normalizedLocalizedName = item.localizedName.toLowerCase().trim();
return normalizedSeriesName.indexOf(normalizedQuery) >= 0 || normalizedOriginalName.indexOf(normalizedQuery) >= 0 || normalizedLocalizedName.indexOf(normalizedQuery) >= 0;
});
return matches;
};
backToTopNeeded = false;
searchFocused: boolean = false;
private readonly onDestroy = new Subject<void>();
constructor(public accountService: AccountService, private router: Router, public navService: NavService,
private libraryService: LibraryService, public imageService: ImageService, @Inject(DOCUMENT) private document: Document,
private scrollService: ScrollService) { }
ngOnInit(): void {}
@HostListener('body:scroll', [])
checkBackToTopNeeded() {
const offset = this.scrollService.scrollPosition;
if (offset > 100) {
this.backToTopNeeded = true;
} else if (offset < 40) {
this.backToTopNeeded = false;
}
}
ngOnDestroy() {
this.onDestroy.next();
this.onDestroy.complete();
}
logout() {
this.accountService.logout();
this.navService.hideNavBar();
this.navService.hideSideNav();
this.router.navigateByUrl('/login');
}
moveFocus() {
this.document.getElementById('content')?.focus();
}
onChangeSearch(val: string) {
this.isLoading = true;
this.searchTerm = val.trim();
this.libraryService.search(val.trim()).pipe(takeUntil(this.onDestroy)).subscribe(results => {
this.searchResults = results;
this.isLoading = false;
}, err => {
this.searchResults.reset();
this.isLoading = false;
this.searchTerm = '';
});
}
goTo(queryParamName: string, filter: any) {
let params: any = {};
params[queryParamName] = filter;
params[FilterQueryParam.Page] = 1;
this.clearSearch();
this.router.navigate(['all-series'], {queryParams: params});
}
goToPerson(role: PersonRole, filter: any) {
this.clearSearch();
switch(role) {
case PersonRole.Writer:
this.goTo(FilterQueryParam.Writers, filter);
break;
case PersonRole.Artist:
this.goTo(FilterQueryParam.Artists, filter);
break;
case PersonRole.Character:
this.goTo(FilterQueryParam.Character, filter);
break;
case PersonRole.Colorist:
this.goTo(FilterQueryParam.Colorist, filter);
break;
case PersonRole.Editor:
this.goTo(FilterQueryParam.Editor, filter);
break;
case PersonRole.Inker:
this.goTo(FilterQueryParam.Inker, filter);
break;
case PersonRole.CoverArtist:
this.goTo(FilterQueryParam.CoverArtists, filter);
break;
case PersonRole.Letterer:
this.goTo(FilterQueryParam.Letterer, filter);
break;
case PersonRole.Penciller:
this.goTo(FilterQueryParam.Penciller, filter);
break;
case PersonRole.Publisher:
this.goTo(FilterQueryParam.Publisher, filter);
break;
case PersonRole.Translator:
this.goTo(FilterQueryParam.Translator, filter);
break;
}
}
clearSearch() {
this.searchViewRef.clear();
this.searchTerm = '';
this.searchResults = new SearchResultGroup();
}
clickSeriesSearchResult(item: SearchResult) {
this.clearSearch();
const libraryId = item.libraryId;
const seriesId = item.seriesId;
this.router.navigate(['library', libraryId, 'series', seriesId]);
}
clickLibraryResult(item: Library) {
this.router.navigate(['library', item.id]);
}
clickCollectionSearchResult(item: CollectionTag) {
this.clearSearch();
this.router.navigate(['collections', item.id]);
}
clickReadingListSearchResult(item: ReadingList) {
this.clearSearch();
this.router.navigate(['lists', item.id]);
}
scrollToTop() {
this.scrollService.scrollTo(0, this.document.body);
}
focusUpdate(searchFocused: boolean) {
this.searchFocused = searchFocused
return searchFocused;
}
hideSideNav() {
this.navService.toggleSideNav();
}
}