Kavita/UI/Web/src/app/series-detail/series-detail.component.html
Robbie Davis 3293e5b424
Comic enhancements (#645)
* Adding multiple cases for comic naming conventions

* Changing "Chapter" to "Issue" for comic libraries

* Fixed an issue where the Parse method was using filename with extension to run regex matching, while it should be running on name without extension.

* Refactored to use Getter

* Cleaned up file to use conditional labelling rather than conditional html fragments

* Refactored code to properly check against library type for a given readinglist item

* Cleaned up series detail

* Conditionally remove special tags during parse

* Setup ParseInfoTests for ComicParserTests and also added unit tests from other comic issues created.

* Added more regex cases for naming patterns reported to be common with comics. Some cases added without regex.

* Pushing up changes

Fixed issue with cleanTitleTest.
Tried some patterns for "Cyberpunk 2077" but reverted

* Updated some cases and some spacing on Parser. Cyberpunk 2077 is not implemented as long as there is a # before issue number.

* Fixed the case for Special parsing on TPB. Fixed a piece of code that got deleted that prevented specials from rendering on volumes tab.

* Potential fix for parsing Cyberpunk 2077

- Added a ComicsSeriesSpecialCasesRegex and passed any filename that contains "Cyberpunk 2077" over to it so we can parse it separately. This could be used for any other potential problem series.

* Revert "Potential fix for parsing Cyberpunk 2077"

This reverts commit a14417e640.

* Added more tests

* Refactored all places in Kavita to use Book, Issue, or Chapter depending on the Library type. Updated Volumes/Chapters to remove Volumes to make it cleaner.

* Removed some leftover test code

Co-authored-by: Joseph Milazzo <joseph.v.milazzo@gmail.com>
2021-10-07 07:49:13 -07:00

140 lines
No EOL
8.8 KiB
HTML

<div class="container-fluid" *ngIf="series !== undefined" style="padding-top: 10px">
<div class="row mb-3">
<div class="col-md-2 col-xs-4 col-sm-6">
<img class="poster lazyload" [src]="imageSerivce.placeholderImage" [attr.data-src]="seriesImage"
(error)="imageSerivce.updateErroredImage($event)" aria-hidden="true">
</div>
<div class="col-md-10 col-xs-8 col-sm-6">
<div class="row no-gutters">
<h2>
{{series?.name}}
</h2>
</div>
<div class="row no-gutters">
<div>
<button class="btn btn-primary" (click)="read()" [disabled]="isLoading">
<span>
<i class="fa {{showBook ? 'fa-book-open' : 'fa-book'}}"></i>
</span>
<span class="read-btn--text">&nbsp;{{(hasReadingProgress) ? 'Continue' : 'Read'}}</span>
</button>
</div>
<div class="ml-2" *ngIf="isAdmin">
<button class="btn btn-secondary" (click)="openEditSeriesModal()" title="Edit Series information">
<span>
<i class="fa fa-pen" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="ml-2" *ngIf="isAdmin || hasDownloadingRole">
<button class="btn btn-secondary" (click)="downloadSeries()" title="Download Series" [disabled]="downloadInProgress">
<ng-container *ngIf="downloadInProgress; else notDownloading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<span class="sr-only">Downloading...</span>
</ng-container>
<ng-template #notDownloading>
<i class="fa fa-arrow-alt-circle-down" aria-hidden="true"></i>
</ng-template>
</button>
</div>
<div class="ml-2">
<div class="card-actions">
<app-card-actionables [disabled]="actionInProgress" (actionHandler)="performAction($event)" [actions]="seriesActions" [labelBy]="series.name" iconClass="fa-ellipsis-h" btnClass="btn-secondary"></app-card-actionables>
</div>
</div>
<div class="ml-2">
<ngb-rating class="rating-star" [(rate)]="series!.userRating" (rateChange)="updateRating($event)" (click)="promptToReview()"></ngb-rating>
<button *ngIf="series?.userRating || series.userRating" class="btn btn-sm btn-icon" (click)="openReviewModal(true)" placement="top" ngbTooltip="Edit Review" attr.aria-label="Edit Review"><i class="fa fa-pen" aria-hidden="true"></i></button>
</div>
</div>
<div class="row no-gutters">
<app-read-more class="user-review {{userReview ? 'mt-1' : ''}}" [text]="series?.userReview || ''" [maxLength]="250"></app-read-more>
</div>
<div class="row no-gutters {{series?.userReview ? '' : 'mt-2'}}">
<app-read-more [text]="seriesSummary" [maxLength]="250"></app-read-more>
</div>
<div *ngIf="seriesMetadata" class="mt-2">
<div class="row no-gutters" *ngIf="seriesMetadata.genres && seriesMetadata.genres.length > 0">
<div class="col-md-4">
<h5>Genres</h5>
</div>
<div class="col-md-8">
<app-tag-badge *ngFor="let genre of seriesMetadata.genres" [selectionMode]="TagBadgeCursor.Clickable">{{genre}}</app-tag-badge>
</div>
</div>
<div class="row no-gutters mt-1" *ngIf="seriesMetadata.tags && seriesMetadata.tags.length > 0">
<div class="col-md-4">
<h5>Collections</h5>
</div>
<div class="col-md-8">
<app-tag-badge *ngFor="let tag of seriesMetadata.tags" a11y-click="13,32" class="clickable" routerLink="/collections/{{tag.id}}" [selectionMode]="TagBadgeCursor.Clickable">
{{tag.title}}
</app-tag-badge>
</div>
</div>
<div class="row no-gutters mt-1" *ngIf="seriesMetadata.persons && seriesMetadata.persons.length > 0">
<div class="col-md-4">
<h5>People</h5>
</div>
<div class="col-md-8">
<app-person-badge *ngFor="let person of seriesMetadata.persons">
<div name>{{person.name}}</div>
<div role>{{person.role}}</div>
</app-person-badge>
</div>
</div>
<div class="row no-gutters mt-1" *ngIf="series.format != MangaFormat.UNKNOWN">
<div class="col-md-4">
<h5>Type</h5>
</div>
<div class="col-md-8">
<app-tag-badge [selectionMode]="TagBadgeCursor.NotAllowed"><app-series-format [format]="series.format">{{utilityService.mangaFormat(series.format)}}</app-series-format></app-tag-badge>
</div>
</div>
</div>
</div>
</div>
<div>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<ul ngbNav #nav="ngbNav" [(activeId)]="activeTabId" class="nav-tabs nav-pills" [destroyOnHide]="false">
<li [ngbNavItem]="1" *ngIf="hasSpecials">
<a ngbNavLink>Specials</a>
<ng-template ngbNavContent>
<div class="row no-gutters">
<div *ngFor="let chapter of specials; let idx = index; trackBy: trackByChapterIdentity">
<app-card-item class="col-auto" *ngIf="chapter.isSpecial" [entity]="chapter" [title]="chapter.title || chapter.range" (click)="openChapter(chapter)"
[imageUrl]="imageService.getChapterCoverImage(chapter.id)"
[read]="chapter.pagesRead" [total]="chapter.pages" [actions]="chapterActions" (selection)="bulkSelectionService.handleCardSelection('special', idx, chapters.length, $event)" [selected]="bulkSelectionService.isCardSelected('special', idx)" [allowSelection]="true"></app-card-item>
</div>
</div>
</ng-template>
</li>
<li [ngbNavItem]="2" *ngIf="hasNonSpecialVolumeChapters">
<a ngbNavLink>{{utilityService.formatChapterName(libraryType) + 's'}}</a>
<ng-template ngbNavContent>
<div class="row no-gutters">
<div *ngFor="let volume of volumes; let idx = index; trackBy: trackByVolumeIdentity">
<app-card-item class="col-auto" *ngIf="volume.number != 0" [entity]="volume" [title]="'Volume ' + volume.name" (click)="openVolume(volume)"
[imageUrl]="imageService.getVolumeCoverImage(volume.id) + '&offset=' + coverImageOffset"
[read]="volume.pagesRead" [total]="volume.pages" [actions]="volumeActions" (selection)="bulkSelectionService.handleCardSelection('volume', idx, volumes.length, $event)" [selected]="bulkSelectionService.isCardSelected('volume', idx)" [allowSelection]="true"></app-card-item>
</div>
<div *ngFor="let chapter of chapters; let idx = index; trackBy: trackByChapterIdentity">
<app-card-item class="col-auto" *ngIf="!chapter.isSpecial" [entity]="chapter" [title]="utilityService.formatChapterName(libraryType, true, true) + chapter.range" (click)="openChapter(chapter)"
[imageUrl]="imageService.getChapterCoverImage(chapter.id) + '&offset=' + coverImageOffset"
[read]="chapter.pagesRead" [total]="chapter.pages" [actions]="chapterActions" (selection)="bulkSelectionService.handleCardSelection('chapter', idx, chapters.length, $event)" [selected]="bulkSelectionService.isCardSelected('chapter', idx)" [allowSelection]="true"></app-card-item>
</div>
</div>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="nav"></div>
</div>
<div class="mx-auto" *ngIf="isLoading" style="width: 200px;">
<div class="spinner-border text-secondary loading" role="status">
<span class="invisible">Loading...</span>
</div>
</div>
</div>