Rating Overhaul (#2159)

* Switched Ratings to a float system. Allow rating something as 0%. Allow half step ratings. Added new css variable: --rating-star-color. By default, N/A will show for series that have no ratings. N/A ratings are not included in overall rating calculations.

* Show extended entity properties on desktop for list view cards.

* Refactored the code for series metadata detail to use a re-usable component to reduce the copy/paste for the Genres tags like sections.

* List Item will show extended properties about a chapter/volume, like weblinks on Desktop viewports.

* Refactored even further so all of series detail uses the same component code. Tweaked the spacing on the series detail area.

List items will now show Characters and Tags which are helpful for more Hentai related content.

* Fixed a bug with removing something from "OnDeckRemoval" table when something was read.
This commit is contained in:
Joe Milazzo 2023-07-25 11:57:07 -05:00 committed by GitHub
parent f5ad821cd9
commit 734e299f7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 2760 additions and 405 deletions

View file

@ -36,6 +36,7 @@
"ngx-extended-pdf-viewer": "^16.2.16",
"ngx-file-drop": "^16.0.0",
"ngx-slider-v2": "^16.0.2",
"ngx-stars": "^1.6.5",
"ngx-toastr": "^17.0.2",
"rxjs": "^7.8.0",
"screenfull": "^6.0.2",
@ -10564,6 +10565,18 @@
"@angular/forms": "^16.0.0"
}
},
"node_modules/ngx-stars": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/ngx-stars/-/ngx-stars-1.6.5.tgz",
"integrity": "sha512-ZJ2R1XgIkBj5TsHSP8tl3QvbRBCi1awLO03Aod7ffDNG1i785ODw9gYlOAvsIrUmnY9ha1h21tTs5pBWXqA+5Q==",
"dependencies": {
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": ">=2.0.0",
"@angular/core": ">=2.0.0"
}
},
"node_modules/ngx-toastr": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-17.0.2.tgz",

View file

@ -40,6 +40,7 @@
"ngx-extended-pdf-viewer": "^16.2.16",
"ngx-file-drop": "^16.0.0",
"ngx-slider-v2": "^16.0.2",
"ngx-stars": "^1.6.5",
"ngx-toastr": "^17.0.2",
"rxjs": "^7.8.0",
"screenfull": "^6.0.2",

View file

@ -27,6 +27,7 @@ export interface Series {
* User's rating (0-5)
*/
userRating: number;
hasUserRated: boolean;
libraryId: number;
/**
* DateTime the entity was created

View file

@ -9,16 +9,16 @@
<div class="offcanvas-body pb-3">
<div class="d-flex">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="vertical" style="max-width: 135px;">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="vertical" style="max-width: 135px;">
<li [ngbNavItem]="tabs[TabID.General]">
<a ngbNavLink>General</a>
<ng-template ngbNavContent>
<div class="container-fluid" style="overflow: auto">
<div class="row g-0">
<div class="d-none d-md-block col-md-2 col-lg-1">
<div class="d-none d-md-block col-md-2 col-lg-1">
<app-image class="me-2" width="74px" [imageUrl]="coverImageUrl"></app-image>
</div>
</div>
<div class="col-md-10 col-lg-11">
<ng-container *ngIf="summary.length > 0; else noSummary">
<app-read-more [text]="summary" [maxLength]="250"></app-read-more>
@ -28,8 +28,8 @@
</ng-template>
</div>
</div>
<app-entity-info-cards [entity]="data"></app-entity-info-cards>
<app-entity-info-cards [entity]="data" [libraryId]="libraryId"></app-entity-info-cards>
<!-- 2 rows to show some tags-->
@ -41,7 +41,7 @@
<app-badge-expander [items]="chapterMetadata.writers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge [person]="item"></app-person-badge>
</ng-template>
</ng-template>
</app-badge-expander>
</ng-container>
</div>
@ -51,7 +51,7 @@
<app-badge-expander [items]="chapterMetadata.genres">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge>{{item.title}}</app-tag-badge>
</ng-template>
</ng-template>
</app-badge-expander>
</ng-container>
</div>
@ -63,7 +63,7 @@
<app-badge-expander [items]="chapterMetadata.publishers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge [person]="item"></app-person-badge>
</ng-template>
</ng-template>
</app-badge-expander>
</ng-container>
</div>
@ -73,7 +73,7 @@
<app-badge-expander [items]="chapterMetadata.tags">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge>{{item.title}}</app-tag-badge>
</ng-template>
</ng-template>
</app-badge-expander>
</ng-container>
</div>
@ -98,7 +98,7 @@
<li [ngbNavItem]="tabs[TabID.Cover]" [disabled]="(isAdmin$ | async) === false">
<a ngbNavLink>{{tabs[TabID.Cover].title}}</a>
<ng-template ngbNavContent>
<app-cover-image-chooser [(imageUrls)]="imageUrls"
<app-cover-image-chooser [(imageUrls)]="imageUrls"
[showReset]="chapter.coverImageLocked"
[showApplyButton]="true"
(applyCover)="applyCoverImage($event)"
@ -121,7 +121,7 @@
<h5 class="mt-0 mb-1">
<span >
<span>
<app-card-actionables (actionHandler)="performAction($event, chapter)" [actions]="chapterActions"
<app-card-actionables (actionHandler)="performAction($event, chapter)" [actions]="chapterActions"
[labelBy]="utilityService.formatChapterName(libraryType, true, true) + formatChapterNumber(chapter)"></app-card-actionables>
<ng-container *ngIf="chapter.number !== '0'; else specialHeader">
{{utilityService.formatChapterName(libraryType, true, false) }} {{formatChapterNumber(chapter)}}
@ -143,7 +143,7 @@
Pages: {{file.pages | number:''}}
</div>
<div class="col" *ngIf="data.hasOwnProperty('created')">
Added:
Added:
<!-- TODO: This data.created can be removed after v0.5.5 release -->
<ng-container *ngIf="file.created === '0001-01-01T00:00:00'; else fileDate">
{{data.created | date: 'short' | defaultDate}}
@ -166,4 +166,4 @@
</ul>
<div [ngbNavOutlet]="nav" class="tab-content {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'mt-3' : 'ms-4 flex-fill'}}"></div>
</div>
</div>
</div>

View file

@ -1,107 +1,121 @@
<div class="row g-0 mt-4 mb-3">
<ng-container *ngIf="chapter !== undefined && chapter.releaseDate && (chapter.releaseDate | date: 'shortDate') !== '1/1/01'">
<div class="col-auto mb-2">
<app-icon-and-title label="Release Date" [clickable]="false" fontClasses="fa-regular fa-calendar" title="Release">
{{chapter.releaseDate | date:'shortDate' | defaultDate}}
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container *ngIf="chapter.ageRating !== AgeRating.Unknown">
<div class="col-auto mb-2">
<app-icon-and-title label="Age Rating" [clickable]="false" fontClasses="fas fa-eye" title="Age Rating">
{{chapter.ageRating | ageRating | async}}
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<div class="mt-4 mb-3">
<div class="row g-0" *ngIf="chapterMetadata ">
<!-- Tags and Characters are used a lot of Hentai and Doujinshi type content, so showing in list item has value add on first glance -->
<app-metadata-detail [tags]="chapterMetadata.tags" [libraryId]="libraryId" [queryParam]="FilterQueryParam.Tags" heading="Tags">
<ng-template #titleTemplate let-item>{{item.title}}</ng-template>
</app-metadata-detail>
<ng-container *ngIf="totalPages > 0">
<div class="col-auto mb-2">
<app-icon-and-title label="Length" [clickable]="false" fontClasses="fa-regular fa-file-lines" title="Pages">
{{totalPages | compactNumber}} Pages
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<app-metadata-detail [tags]="chapterMetadata.characters" [libraryId]="libraryId" [queryParam]="FilterQueryParam.Character" heading="Characters">
<ng-template #titleTemplate let-item>{{item.title}}</ng-template>
</app-metadata-detail>
</div>
<ng-container *ngIf="chapter.files[0].format === MangaFormat.EPUB && totalWordCount > 0">
<div class="col-auto mb-2">
<app-icon-and-title label="Length" [clickable]="false" fontClasses="fa-solid fa-book-open">
{{totalWordCount | compactNumber}} Words
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<div class="row g-0">
<ng-container *ngIf="chapter !== undefined && chapter.releaseDate && (chapter.releaseDate | date: 'shortDate') !== '1/1/01'">
<div class="col-auto mb-2">
<app-icon-and-title label="Release Date" [clickable]="false" fontClasses="fa-regular fa-calendar" title="Release">
{{chapter.releaseDate | date:'shortDate' | defaultDate}}
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container *ngIf="chapter.files[0].format === MangaFormat.EPUB && totalWordCount > 0 || chapter.files[0].format !== MangaFormat.EPUB">
<div class="col-auto mb-2">
<app-icon-and-title label="Read Time" [clickable]="false" fontClasses="fa-regular fa-clock">
<ng-container *ngIf="readingTime.maxHours === 0 || readingTime.minHours === 0; else normalReadTime">&lt;1 Hour</ng-container>
<ng-template #normalReadTime>
{{readingTime.minHours}}{{readingTime.maxHours !== readingTime.minHours ? ('-' + readingTime.maxHours) : ''}} Hour{{readingTime.minHours > 1 ? 's' : ''}}
</ng-template>
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="chapter.ageRating !== AgeRating.Unknown">
<div class="col-auto mb-2">
<app-icon-and-title label="Age Rating" [clickable]="false" fontClasses="fas fa-eye" title="Age Rating">
{{chapter.ageRating | ageRating | async}}
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container *ngIf="showExtendedProperties && chapter.created && chapter.created !== '' && (chapter.created | date: 'shortDate') !== '1/1/01'">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Date Added" [clickable]="false" fontClasses="fa-solid fa-file-import" title="Date Added">
{{chapter.created | date:'short' | defaultDate}}
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="totalPages > 0">
<div class="col-auto mb-2">
<app-icon-and-title label="Length" [clickable]="false" fontClasses="fa-regular fa-file-lines" title="Pages">
{{totalPages | compactNumber}} Pages
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container *ngIf="showExtendedProperties && size > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Size" [clickable]="false" fontClasses="fa-solid fa-scale-unbalanced" title="ID">
{{size | bytes}}
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="chapter.files[0].format === MangaFormat.EPUB && totalWordCount > 0">
<div class="col-auto mb-2">
<app-icon-and-title label="Length" [clickable]="false" fontClasses="fa-solid fa-book-open">
{{totalWordCount | compactNumber}} Words
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container *ngIf="showExtendedProperties">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="ID" [clickable]="false" fontClasses="fa-solid fa-fingerprint" title="ID">
{{entity.id}}
</app-icon-and-title>
</div>
<ng-container *ngIf="WebLinks.length > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Links" [clickable]="false" fontClasses="fa-solid fa-link" title="Links">
<a class="me-1" [href]="link | safeHtml" *ngFor="let link of WebLinks" target="_blank" rel="noopener noreferrer" [title]="link">
<img width="24" height="24" #img class="lazyload img-placeholder"
src="data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
[attr.data-src]="imageService.getWebLinkImage(link)"
(error)="imageService.updateErroredWebLinkImage($event)"
aria-hidden="true" alt="">
</a>
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="chapter.files[0].format === MangaFormat.EPUB && totalWordCount > 0 || chapter.files[0].format !== MangaFormat.EPUB">
<div class="col-auto mb-2">
<app-icon-and-title label="Read Time" [clickable]="false" fontClasses="fa-regular fa-clock">
<ng-container *ngIf="readingTime.maxHours === 0 || readingTime.minHours === 0; else normalReadTime">&lt;1 Hour</ng-container>
<ng-template #normalReadTime>
{{readingTime.minHours}}{{readingTime.maxHours !== readingTime.minHours ? ('-' + readingTime.maxHours) : ''}} Hour{{readingTime.minHours > 1 ? 's' : ''}}
</ng-template>
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="chapter.isbn.length > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="ISBN" [clickable]="false" fontClasses="fa-solid fa-barcode" title="ISBN">
{{chapter.isbn}}
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="(chapter.lastReadingProgress | date: 'shortDate') !== '1/1/01'">
<ng-container *ngIf="showExtendedProperties && chapter.created && chapter.created !== '' && (chapter.created | date: 'shortDate') !== '1/1/01'">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Last Read" [clickable]="false" fontClasses="fa-regular fa-clock" [ngbTooltip]="chapter.lastReadingProgress | date: 'medium'">
{{chapter.lastReadingProgress | date: 'shortDate'}}
</app-icon-and-title>
<app-icon-and-title label="Date Added" [clickable]="false" fontClasses="fa-solid fa-file-import" title="Date Added">
{{chapter.created | date:'short' | defaultDate}}
</app-icon-and-title>
</div>
</ng-container>
</ng-container>
</ng-container>
<ng-container *ngIf="showExtendedProperties && size > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Size" [clickable]="false" fontClasses="fa-solid fa-scale-unbalanced" title="ID">
{{size | bytes}}
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="showExtendedProperties">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="ID" [clickable]="false" fontClasses="fa-solid fa-fingerprint" title="ID">
{{entity.id}}
</app-icon-and-title>
</div>
<ng-container *ngIf="WebLinks.length > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Links" [clickable]="false" fontClasses="fa-solid fa-link" title="Links">
<a class="me-1" [href]="link | safeHtml" *ngFor="let link of WebLinks" target="_blank" rel="noopener noreferrer" [title]="link">
<img width="24" height="24" #img class="lazyload img-placeholder"
src="data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
[attr.data-src]="imageService.getWebLinkImage(link)"
(error)="imageService.updateErroredWebLinkImage($event)"
aria-hidden="true" alt="">
</a>
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="chapter.isbn.length > 0">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="ISBN" [clickable]="false" fontClasses="fa-solid fa-barcode" title="ISBN">
{{chapter.isbn}}
</app-icon-and-title>
</div>
</ng-container>
<ng-container *ngIf="(chapter.lastReadingProgress | date: 'shortDate') !== '1/1/01'">
<div class="vr d-none d-lg-block m-2"></div>
<div class="col-auto">
<app-icon-and-title label="Last Read" [clickable]="false" fontClasses="fa-regular fa-clock" [ngbTooltip]="chapter.lastReadingProgress | date: 'medium'">
{{chapter.lastReadingProgress | date: 'shortDate'}}
</app-icon-and-title>
</div>
</ng-container>
</ng-container>
</div>
</div>

View file

@ -24,11 +24,13 @@ import {BytesPipe} from "../../pipe/bytes.pipe";
import {CompactNumberPipe} from "../../pipe/compact-number.pipe";
import {AgeRatingPipe} from "../../pipe/age-rating.pipe";
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
import {MetadataDetailComponent} from "../../series-detail/_components/metadata-detail/metadata-detail.component";
import {FilterQueryParam} from "../../shared/_services/filter-utilities.service";
@Component({
selector: 'app-entity-info-cards',
standalone: true,
imports: [CommonModule, IconAndTitleComponent, SafeHtmlPipe, DefaultDatePipe, BytesPipe, CompactNumberPipe, AgeRatingPipe, NgbTooltip],
imports: [CommonModule, IconAndTitleComponent, SafeHtmlPipe, DefaultDatePipe, BytesPipe, CompactNumberPipe, AgeRatingPipe, NgbTooltip, MetadataDetailComponent],
templateUrl: './entity-info-cards.component.html',
styleUrls: ['./entity-info-cards.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
@ -36,6 +38,7 @@ import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
export class EntityInfoCardsComponent implements OnInit {
@Input({required: true}) entity!: Volume | Chapter;
@Input({required: true}) libraryId!: number;
/**
* This will pull extra information
*/
@ -75,8 +78,6 @@ export class EntityInfoCardsComponent implements OnInit {
return this.chapter.webLinks.split(',');
}
constructor(private utilityService: UtilityService, private seriesService: SeriesService, private readonly cdRef: ChangeDetectorRef) {}
ngOnInit(): void {
@ -127,8 +128,5 @@ export class EntityInfoCardsComponent implements OnInit {
this.cdRef.markForCheck();
}
getTimezone(timezone: string): string {
const localDate = new Date(timezone);
return localDate.toLocaleString('en-US', { timeZoneName: 'short' }).split(' ')[3];
}
protected readonly FilterQueryParam = FilterQueryParam;
}

View file

@ -22,7 +22,7 @@
<span class="d-none d-sm-inline-block">Read</span>
</button>
</h5>
<!-- This isn't perfect, but it might work. TODO: Polish this-->
<h6 class="text-muted" [ngClass]="{'subtitle-with-actionables' : actions.length > 0}" *ngIf="Title !== '' && showTitle">{{Title}}</h6>
<ng-container *ngIf="summary.length > 0">
<div class="mt-2 ps-2">
@ -30,7 +30,7 @@
</div>
</ng-container>
<div class="ps-2 d-none d-md-inline-block">
<app-entity-info-cards [entity]="entity" [showExtendedProperties]="false"></app-entity-info-cards>
<app-entity-info-cards [entity]="entity" [libraryId]="libraryId" [includeMetadata]="ShowExtended" [showExtendedProperties]="ShowExtended"></app-entity-info-cards>
</div>
</div>
</div>

View file

@ -5,15 +5,14 @@ import {
EventEmitter,
inject,
Input,
OnDestroy,
OnInit,
Output
} from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { map, Observable, Subject, takeUntil } from 'rxjs';
import { map, Observable } from 'rxjs';
import { Download } from 'src/app/shared/_models/download';
import { DownloadEvent, DownloadService } from 'src/app/shared/_services/download.service';
import { UtilityService } from 'src/app/shared/_services/utility.service';
import {Breakpoint, UtilityService} from 'src/app/shared/_services/utility.service';
import { Chapter } from 'src/app/_models/chapter';
import { LibraryType } from 'src/app/_models/library';
import { RelationKind } from 'src/app/_models/series-detail/relation-kind';
@ -42,6 +41,7 @@ export class ListItemComponent implements OnInit {
* Volume or Chapter to render
*/
@Input({required: true}) entity!: Volume | Chapter;
@Input({required: true}) libraryId!: number;
/**
* Image to show
*/
@ -103,8 +103,14 @@ export class ListItemComponent implements OnInit {
return '';
}
get ShowExtended() {
return this.utilityService.getActiveBreakpoint() === Breakpoint.Desktop;
}
constructor(private utilityService: UtilityService, private downloadService: DownloadService,
protected readonly Breakpoint = Breakpoint;
constructor(public utilityService: UtilityService, private downloadService: DownloadService,
private toastr: ToastrService, private readonly cdRef: ChangeDetectorRef) { }
ngOnInit(): void {

View file

@ -3,9 +3,10 @@
popoverTitle="Your Rating + Overall" popoverClass="md-popover">
<span class="badge rounded-pill me-1">
<img class="me-1" ngSrc="assets/images/logo-32.png" width="24" height="24" alt="">
{{userRating * 20}}
<ng-container *ngIf="overallRating > 0; else noOverallRating"> + {{overallRating}}%</ng-container>
<ng-template #noOverallRating>%</ng-template>
<ng-container *ngIf="hasUserRated; else notYetRated">{{userRating * 20}}</ng-container>
<ng-template #notYetRated>N/A</ng-template>
<ng-container *ngIf="overallRating > 0"> + {{overallRating}}</ng-container>
<ng-container *ngIf="hasUserRated || overallRating > 0">%</ng-container>
</span>
</div>
@ -22,11 +23,9 @@
</div>
<ng-template #popContent>
<ngb-rating class="rating-star" [(rate)]="userRating" (rateChange)="updateRating($event)" [resettable]="false">
<ng-template let-fill="fill" let-index="index">
<span class="star" [class.filled]="(index < userRating) && userRating > 0">&#9733;</span>
</ng-template>
</ngb-rating> {{userRating * 20}}%
<ngx-stars [initialStars]="userRating" (ratingOutput)="updateRating($event)"
[maxStars]="5" [color]="starColor"></ngx-stars>
{{userRating * 20}}%
</ng-template>
<ng-template #externalPopContent let-rating="rating">

View file

@ -19,4 +19,19 @@
}
}
.rating-star {
i {
position: relative;
display: inline-block;
padding-right: 0.1rem;
color: #d3d3d3;
}
.filled {
color: var(--primary-color);
}
}
::ng-deep .star {
background-color: var(--primary-color);
}

View file

@ -16,11 +16,13 @@ import {LoadingComponent} from "../../../shared/loading/loading.component";
import {AccountService} from "../../../_services/account.service";
import {LibraryType} from "../../../_models/library";
import {ProviderNamePipe} from "../../../pipe/provider-name.pipe";
import {NgxStarsModule} from "ngx-stars";
import {ThemeService} from "../../../_services/theme.service";
@Component({
selector: 'app-external-rating',
standalone: true,
imports: [CommonModule, ProviderImagePipe, NgOptimizedImage, NgbRating, NgbPopover, LoadingComponent, ProviderNamePipe],
imports: [CommonModule, ProviderImagePipe, NgOptimizedImage, NgbRating, NgbPopover, LoadingComponent, ProviderNamePipe, NgxStarsModule],
templateUrl: './external-rating.component.html',
styleUrls: ['./external-rating.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
@ -29,15 +31,19 @@ import {ProviderNamePipe} from "../../../pipe/provider-name.pipe";
export class ExternalRatingComponent implements OnInit {
@Input({required: true}) seriesId!: number;
@Input({required: true}) userRating!: number;
@Input({required: true}) hasUserRated!: boolean;
@Input({required: true}) libraryType!: LibraryType;
private readonly cdRef = inject(ChangeDetectorRef);
private readonly seriesService = inject(SeriesService);
private readonly accountService = inject(AccountService);
private readonly themeService = inject(ThemeService);
ratings: Array<Rating> = [];
isLoading: boolean = false;
overallRating: number = -1;
starColor = this.themeService.getCssVariable('--rating-star-color');
ngOnInit() {
@ -58,9 +64,11 @@ export class ExternalRatingComponent implements OnInit {
});
}
updateRating(rating: any) {
updateRating(rating: number) {
this.seriesService.updateRating(this.seriesId, rating).subscribe(() => {
this.userRating = rating;
this.hasUserRated = true;
this.cdRef.markForCheck();
});
}
}

View file

@ -0,0 +1,21 @@
<div class="row g-0 mb-1" *ngIf="tags.length > 0">
<div class="col-md-4">
<h5>{{heading}}</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="tags">
<ng-template #badgeExpanderItem let-item let-position="idx">
<ng-container *ngIf="itemTemplate; else useTitle">
<span (click)="goTo(queryParam, item.id)">
<ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item, idx: position }"></ng-container>
</span>
</ng-container>
<ng-template #useTitle>
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(queryParam, item.id)" [selectionMode]="TagBadgeCursor.Clickable">
<ng-container [ngTemplateOutlet]="titleTemplate" [ngTemplateOutletContext]="{ $implicit: item, idx: position }"></ng-container>
</app-tag-badge>
</ng-template>
</ng-template>
</app-badge-expander>
</div>
</div>

View file

@ -0,0 +1,37 @@
import {ChangeDetectionStrategy, Component, ContentChild, inject, Input, TemplateRef} from '@angular/core';
import {CommonModule} from '@angular/common';
import {A11yClickDirective} from "../../../shared/a11y-click.directive";
import {BadgeExpanderComponent} from "../../../shared/badge-expander/badge-expander.component";
import {TagBadgeComponent, TagBadgeCursor} from "../../../shared/tag-badge/tag-badge.component";
import {FilterQueryParam} from "../../../shared/_services/filter-utilities.service";
import {Router} from "@angular/router";
@Component({
selector: 'app-metadata-detail',
standalone: true,
imports: [CommonModule, A11yClickDirective, BadgeExpanderComponent, TagBadgeComponent],
templateUrl: './metadata-detail.component.html',
styleUrls: ['./metadata-detail.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MetadataDetailComponent {
@Input({required: true}) tags: Array<any> = [];
@Input({required: true}) libraryId!: number;
@Input({required: true}) heading!: string;
@Input() queryParam: FilterQueryParam = FilterQueryParam.None;
@ContentChild('titleTemplate') titleTemplate!: TemplateRef<any>;
@ContentChild('itemTemplate') itemTemplate?: TemplateRef<any>;
private readonly router = inject(Router);
protected readonly TagBadgeCursor = TagBadgeCursor;
goTo(queryParamName: FilterQueryParam, filter: any) {
if (queryParamName === FilterQueryParam.None) return;
let params: any = {};
params[queryParamName] = filter;
params[FilterQueryParam.Page] = 1;
this.router.navigate(['library', this.libraryId], {queryParams: params});
}
}

View file

@ -174,7 +174,7 @@
<ng-template #storylineListLayout>
<ng-container *ngFor="let item of scroll.viewPortItems; let idx = index; trackBy: trackByStoryLineIdentity">
<ng-container *ngIf="!item.isChapter; else chapterListItem">
<app-list-item [imageUrl]="imageService.getVolumeCoverImage(item.volume.id)"
<app-list-item [imageUrl]="imageService.getVolumeCoverImage(item.volume.id)" [libraryId]="libraryId"
[seriesName]="series.name" [entity]="item.volume" *ngIf="item.volume.number !== 0"
[actions]="volumeActions" [libraryType]="libraryType" imageWidth="130px" imageHeight=""
[pagesRead]="item.volume.pagesRead" [totalPages]="item.volume.pages" (read)="openVolume(item.volume)"
@ -185,7 +185,7 @@
</app-list-item>
</ng-container>
<ng-template #chapterListItem>
<app-list-item [imageUrl]="imageService.getChapterCoverImage(item.chapter.id)"
<app-list-item [imageUrl]="imageService.getChapterCoverImage(item.chapter.id)" [libraryId]="libraryId"
[seriesName]="series.name" [entity]="item.chapter" *ngIf="!item.chapter.isSpecial"
[actions]="chapterActions" [libraryType]="libraryType" imageWidth="130px" imageHeight=""
[pagesRead]="item.chapter.pagesRead" [totalPages]="item.chapter.pages" (read)="openChapter(item.chapter)"
@ -219,7 +219,7 @@
</ng-container>
<ng-template #volumeListLayout>
<ng-container *ngFor="let volume of scroll.viewPortItems; let idx = index; trackBy: trackByVolumeIdentity">
<app-list-item [imageUrl]="imageService.getVolumeCoverImage(volume.id)"
<app-list-item [imageUrl]="imageService.getVolumeCoverImage(volume.id)" [libraryId]="libraryId"
[seriesName]="series.name" [entity]="volume"
[actions]="volumeActions" [libraryType]="libraryType" imageWidth="130px" imageHeight=""
[pagesRead]="volume.pagesRead" [totalPages]="volume.pages" (read)="openVolume(volume)"
@ -256,7 +256,7 @@
</ng-container>
<ng-template #chapterListLayout>
<div *ngFor="let chapter of scroll.viewPortItems; let idx = index; trackBy: trackByChapterIdentity">
<app-list-item [imageUrl]="imageService.getChapterCoverImage(chapter.id)"
<app-list-item [imageUrl]="imageService.getChapterCoverImage(chapter.id)" [libraryId]="libraryId"
[seriesName]="series.name" [entity]="chapter" *ngIf="!chapter.isSpecial"
[actions]="chapterActions" [libraryType]="libraryType" imageWidth="130px" imageHeight=""
[pagesRead]="chapter.pagesRead" [totalPages]="chapter.pages" (read)="openChapter(chapter)"
@ -290,7 +290,7 @@
</ng-container>
<ng-template #specialListLayout>
<ng-container *ngFor="let chapter of scroll.viewPortItems; let idx = index; trackBy: trackByChapterIdentity">
<app-list-item [imageUrl]="imageService.getChapterCoverImage(chapter.id)"
<app-list-item [imageUrl]="imageService.getChapterCoverImage(chapter.id)" [libraryId]="libraryId"
[seriesName]="series.name" [entity]="chapter"
[actions]="chapterActions" [libraryType]="libraryType" imageWidth="130px" imageHeight=""
[pagesRead]="chapter.pagesRead" [totalPages]="chapter.pages" (read)="openChapter(chapter)"

View file

@ -2,219 +2,121 @@
<app-read-more [text]="seriesSummary" [maxLength]="250"></app-read-more>
</div>
<div class="row g-0 mt-2 mb-2">
<div class="col-md-4">
<h5>Ratings</h5>
</div>
<div class="col-md-8">
<app-external-rating [seriesId]="series.id" [userRating]="series.userRating" [libraryType]="libraryType"></app-external-rating>
</div>
</div>
<app-metadata-detail [tags]="['']" [libraryId]="series.libraryId" heading="Ratings">
<ng-template #itemTemplate let-item>
<app-external-rating [seriesId]="series.id" [userRating]="series.userRating" [hasUserRated]="series.hasUserRated" [libraryType]="libraryType"></app-external-rating>
</ng-template>
</app-metadata-detail>
<ng-container *ngIf="WebLinks as links">
<div class="row g-0 mt-2 mb-2" *ngIf="links.length > 0">
<div class="col-md-4">
<h5>Links</h5>
</div>
<div class="col-md-8">
<a class="col me-1" [href]="link | safeHtml" target="_blank" rel="noopener noreferrer" *ngFor="let link of links" [title]="link">
<img width="24" height="24" class="lazyload img-placeholder"
[src]="imageService.errorWebLinkImage"
[attr.data-src]="imageService.getWebLinkImage(link)"
(error)="imageService.updateErroredWebLinkImage($event)"
aria-hidden="true" alt="">
</a>
</div>
</div>
<app-metadata-detail [tags]="links" [libraryId]="series.libraryId" heading="Links">
<ng-template #itemTemplate let-item>
<a class="col me-1" [href]="link | safeHtml" target="_blank" rel="noopener noreferrer" *ngFor="let link of links" [title]="link">
<img width="24" height="24" class="lazyload img-placeholder"
[src]="imageService.errorWebLinkImage"
[attr.data-src]="imageService.getWebLinkImage(link)"
(error)="imageService.updateErroredWebLinkImage($event)"
aria-hidden="true" alt="">
</a>
</ng-template>
</app-metadata-detail>
</ng-container>
<div class="row g-0" *ngIf="seriesMetadata.genres && seriesMetadata.genres.length > 0">
<div class="col-md-4">
<h5>Genres</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.genres">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Genres, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<div class="row g-0" *ngIf="seriesMetadata.tags && seriesMetadata.tags.length > 0">
<div class="col-md-4">
<h5>Tags</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.tags">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Tags, item.id)" [selectionMode]="TagBadgeCursor.Clickable">{{item.title}}</app-tag-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.collectionTags && seriesMetadata.collectionTags.length > 0">
<div class="col-md-4">
<h5>Collections</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.collectionTags">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="navigate('collections', item.id)" [selectionMode]="TagBadgeCursor.Clickable">
{{item.title}}
</app-tag-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<div class="row g-0 mt-1" *ngIf="readingLists && readingLists.length > 0">
<div class="col-md-4">
<h5>Reading Lists</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="readingLists">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="navigate('lists', item.id)" [selectionMode]="TagBadgeCursor.Clickable">
<app-metadata-detail [tags]="seriesMetadata.genres" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Genres" heading="Genres">
<ng-template #titleTemplate let-item>{{item.title}}</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="seriesMetadata.tags" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Tags" heading="Tags">
<ng-template #titleTemplate let-item>{{item.title}}</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="seriesMetadata.collectionTags" [libraryId]="series.libraryId" heading="Collections">
<ng-template #itemTemplate let-item>
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="navigate('collections', item.id)" [selectionMode]="TagBadgeCursor.Clickable">
{{item.title}}
</app-tag-badge>
</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="readingLists" [libraryId]="series.libraryId" heading="Reading Lists">
<ng-template #itemTemplate let-item>
<app-tag-badge a11y-click="13,32" class="col-auto" (click)="navigate('lists', item.id)" [selectionMode]="TagBadgeCursor.Clickable">
<span *ngIf="item.promoted">
<i class="fa fa-angle-double-up" aria-hidden="true"></i>&nbsp;
<span class="visually-hidden">(promoted)</span>
</span>
{{item.title}}
</app-tag-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.writers && seriesMetadata.writers.length > 0">
<div class="col-md-4">
<h5>Writers/Authors</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.writers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Writers, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
{{item.title}}
</app-tag-badge>
</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="seriesMetadata.writers" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Writers" heading="Writers/Authors">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed" id="extended-series-metadata">
<div class="row g-0 mt-1" *ngIf="seriesMetadata.coverArtists && seriesMetadata.coverArtists.length > 0">
<div class="col-md-4">
<h5>Cover Artists</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.coverArtists">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.CoverArtists, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.coverArtists" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.CoverArtists" heading="Cover Artists">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.characters && seriesMetadata.characters.length > 0">
<div class="col-md-4">
<h5>Characters</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.characters">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Character, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.characters" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Character" heading="Characters">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.colorists && seriesMetadata.colorists.length > 0">
<div class="col-md-4">
<h5>Colorists</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.colorists">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Colorist, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.colorists" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Colorist" heading="Colorists">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.editors && seriesMetadata.editors.length > 0">
<div class="col-md-4">
<h5>Editors</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.editors">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Editor, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.editors" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Editor" heading="Editors">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.inkers && seriesMetadata.inkers.length > 0">
<div class="col-md-4">
<h5>Inkers</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.inkers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Inker, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.inkers" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Inker" heading="Inkers">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.letterers && seriesMetadata.letterers.length > 0">
<div class="col-md-4">
<h5>Letterers</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.letterers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Letterer, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.translators && seriesMetadata.translators.length > 0">
<div class="col-md-4">
<h5>Translators</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.translators">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Translator, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.letterers" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Letterer" heading="Letterers">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.pencillers && seriesMetadata.pencillers.length > 0">
<div class="col-md-4">
<h5>Pencillers</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.pencillers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Penciller, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
<app-metadata-detail [tags]="seriesMetadata.translators" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Translator" heading="Translators">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="seriesMetadata.pencillers" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Penciller" heading="Pencillers">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="seriesMetadata.publishers" [libraryId]="series.libraryId" [queryParam]="FilterQueryParam.Publisher" heading="Publishers">
<ng-template #itemTemplate let-item>
<app-person-badge a11y-click="13,32" class="col-auto" [person]="item"></app-person-badge>
</ng-template>
</app-metadata-detail>
<div class="row g-0 mt-1" *ngIf="seriesMetadata.publishers && seriesMetadata.publishers.length > 0">
<div class="col-md-4">
<h5>Publishers</h5>
</div>
<div class="col-md-8">
<app-badge-expander [items]="seriesMetadata.publishers">
<ng-template #badgeExpanderItem let-item let-position="idx">
<app-person-badge a11y-click="13,32" class="col-auto" (click)="goTo(FilterQueryParam.Publisher, item.id)" [person]="item"></app-person-badge>
</ng-template>
</app-badge-expander>
</div>
</div>
</div>
<div class="row g-0">
@ -226,5 +128,4 @@
</a>
</div>
<!-- This first row will have random information about the series-->
<app-series-info-cards [series]="series" [seriesMetadata]="seriesMetadata" (goTo)="handleGoTo($event)" [hasReadingProgress]="hasReadingProgress"></app-series-info-cards>

View file

@ -19,12 +19,15 @@ import {PersonBadgeComponent} from "../../../shared/person-badge/person-badge.co
import {NgbCollapse} from "@ng-bootstrap/ng-bootstrap";
import {SeriesInfoCardsComponent} from "../../../cards/series-info-cards/series-info-cards.component";
import {LibraryType} from "../../../_models/library";
import {MetadataDetailComponent} from "../metadata-detail/metadata-detail.component";
@Component({
selector: 'app-series-metadata-detail',
standalone: true,
imports: [CommonModule, TagBadgeComponent, BadgeExpanderComponent, SafeHtmlPipe, ExternalRatingComponent, ReadMoreComponent, A11yClickDirective, PersonBadgeComponent, NgbCollapse, SeriesInfoCardsComponent],
imports: [CommonModule, TagBadgeComponent, BadgeExpanderComponent, SafeHtmlPipe, ExternalRatingComponent,
ReadMoreComponent, A11yClickDirective, PersonBadgeComponent, NgbCollapse, SeriesInfoCardsComponent,
MetadataDetailComponent],
templateUrl: './series-metadata-detail.component.html',
styleUrls: ['./series-metadata-detail.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
@ -78,9 +81,7 @@ export class SeriesMetadataDetailComponent implements OnChanges {
this.seriesMetadata.translators.length > 0;
if (this.seriesMetadata !== null) {
this.seriesSummary = (this.seriesMetadata.summary === null ? '' : this.seriesMetadata.summary).replace(/\n/g, '<br>');
}
this.seriesSummary = (this.seriesMetadata?.summary === null ? '' : this.seriesMetadata.summary).replace(/\n/g, '<br>');
this.cdRef.markForCheck();
}

View file

@ -34,7 +34,11 @@ export enum FilterQueryParam {
/**
* This is a pagination control
*/
Page = 'page'
Page = 'page',
/**
* Special case for the UI. Does not trigger filtering
*/
None = 'none'
}
@Injectable({
@ -46,19 +50,19 @@ export class FilterUtilitiesService {
/**
* Updates the window location with a custom url based on filter and pagination objects
* @param pagination
* @param filter
* @param pagination
* @param filter
*/
updateUrlFromFilter(pagination: Pagination, filter: SeriesFilter | undefined) {
const params = '?page=' + pagination.currentPage;
const url = this.urlFromFilter(window.location.href.split('?')[0] + params, filter);
window.history.replaceState(window.location.href, '', this.replacePaginationOnUrl(url, pagination));
}
/**
* Patches the page query param in the window location.
* @param pagination
* Patches the page query param in the window location.
* @param pagination
*/
updateUrlFromPagination(pagination: Pagination) {
window.history.replaceState(window.location.href, '', this.replacePaginationOnUrl(window.location.href, pagination));
@ -127,7 +131,7 @@ export class FilterUtilitiesService {
if (filter.seriesNameQuery !== '') {
params += `&${FilterQueryParam.Name}=${encodeURIComponent(filter.seriesNameQuery)}`;
}
return currentUrl + params;
}
@ -262,7 +266,7 @@ export class FilterUtilitiesService {
anyChanged = true;
}
// Rating, seriesName,
// Rating, seriesName,
const rating = snapshot.queryParamMap.get(FilterQueryParam.Rating);
if (rating !== undefined && rating !== null && parseInt(rating, 10) > 0) {
filter.rating = parseInt(rating, 10);
@ -301,7 +305,7 @@ export class FilterUtilitiesService {
filter.seriesNameQuery = decodeURIComponent(searchNameQuery);
anyChanged = true;
}
return [filter, false]; // anyChanged. Testing out if having a filter active but keep drawer closed by default works better
}

View file

@ -252,4 +252,7 @@
--review-spoiler-bg-color: var(--primary-color);
--review-spoiler-text-color: var(--body-text-color);
/** Rating Star Color **/
--rating-star-color: var(--primary-color);
}