More Bugfixes from Side Nav (#1162)

* Fixed a bug where the bottom of the page could be cut off

* Adjusted all the headings to h2, which looks better

* Refactored GetSeriesDetail to actually map the names inside the code so the UI just displays.

* Put in some basic improvements to OPDS by using Series Detail type layout, but this only reduces one click.

* Fixed a bug where offset from scrollbar fix causes readers to be cutoff.
This commit is contained in:
Joseph Milazzo 2022-03-17 20:27:39 -05:00 committed by GitHub
parent 5220d2b300
commit bff49c0e7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 114 additions and 54 deletions

View File

@ -202,7 +202,7 @@ public class SeriesServiceTests
Assert.NotEmpty(detail.Volumes); Assert.NotEmpty(detail.Volumes);
Assert.Equal(2, detail.Volumes.Count()); // Volume 0 shouldn't be sent in Volumes Assert.Equal(2, detail.Volumes.Count()); // Volume 0 shouldn't be sent in Volumes
Assert.All(detail.Volumes, dto => Assert.Contains(dto.Name, new[] {"2", "3"})); Assert.All(detail.Volumes, dto => Assert.Contains(dto.Name, new[] {"Volume 2", "Volume 3"})); // Volumes get names mapped
} }
[Fact] [Fact]

View File

@ -28,6 +28,7 @@ public class OpdsController : BaseApiController
private readonly IDirectoryService _directoryService; private readonly IDirectoryService _directoryService;
private readonly ICacheService _cacheService; private readonly ICacheService _cacheService;
private readonly IReaderService _readerService; private readonly IReaderService _readerService;
private readonly ISeriesService _seriesService;
private readonly XmlSerializer _xmlSerializer; private readonly XmlSerializer _xmlSerializer;
@ -61,13 +62,14 @@ public class OpdsController : BaseApiController
public OpdsController(IUnitOfWork unitOfWork, IDownloadService downloadService, public OpdsController(IUnitOfWork unitOfWork, IDownloadService downloadService,
IDirectoryService directoryService, ICacheService cacheService, IDirectoryService directoryService, ICacheService cacheService,
IReaderService readerService) IReaderService readerService, ISeriesService seriesService)
{ {
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_downloadService = downloadService; _downloadService = downloadService;
_directoryService = directoryService; _directoryService = directoryService;
_cacheService = cacheService; _cacheService = cacheService;
_readerService = readerService; _readerService = readerService;
_seriesService = seriesService;
_xmlSerializer = new XmlSerializer(typeof(Feed)); _xmlSerializer = new XmlSerializer(typeof(Feed));
_xmlOpenSearchSerializer = new XmlSerializer(typeof(OpenSearchDescription)); _xmlOpenSearchSerializer = new XmlSerializer(typeof(OpenSearchDescription));
@ -314,16 +316,17 @@ public class OpdsController : BaseApiController
var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList(); var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList();
foreach (var item in items) foreach (var item in items)
{ {
feed.Entries.Add(new FeedEntry() feed.Entries.Add(CreateChapter(apiKey, $"{item.SeriesName} Chapter {item.ChapterNumber}", item.ChapterId, item.VolumeId, item.SeriesId));
{ // new FeedEntry()
Id = item.ChapterId.ToString(), // {
Title = $"{item.SeriesName} Chapter {item.ChapterNumber}", // Id = item.ChapterId.ToString(),
Links = new List<FeedLink>() // Title = $"{item.SeriesName} Chapter {item.ChapterNumber}",
{ // Links = new List<FeedLink>()
CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), // {
CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") // CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"),
} // CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}")
}); // }
// }
} }
return CreateXmlResult(SerializeXml(feed)); return CreateXmlResult(SerializeXml(feed));
@ -521,15 +524,30 @@ public class OpdsController : BaseApiController
return BadRequest("OPDS is not enabled on this server"); return BadRequest("OPDS is not enabled on this server");
var userId = await GetUser(apiKey); var userId = await GetUser(apiKey);
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
var volumes = await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId);
var feed = CreateFeed(series.Name + " - Volumes", $"{apiKey}/series/{series.Id}", apiKey); var feed = CreateFeed(series.Name + " - Storyline", $"{apiKey}/series/{series.Id}", apiKey);
SetFeedId(feed, $"series-{series.Id}"); SetFeedId(feed, $"series-{series.Id}");
feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}")); feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}"));
foreach (var volumeDto in volumes)
// NOTE: I want to try and use ReaderService to get SeriesDetails.
var seriesDetail = await _seriesService.GetSeriesDetail(seriesId, userId);
foreach (var volume in seriesDetail.Volumes)
{ {
feed.Entries.Add(CreateVolume(volumeDto, seriesId, apiKey)); feed.Entries.Add(CreateVolume(volume, seriesId, apiKey)); // We might want to emulate a volume but make this a chapter
} }
foreach (var storylineChapter in seriesDetail.StorylineChapters.Where(c => !c.IsSpecial))
{
feed.Entries.Add(CreateChapter(apiKey, storylineChapter.Title, storylineChapter.Id, storylineChapter.VolumeId, seriesId));
}
foreach (var special in seriesDetail.Specials)
{
feed.Entries.Add(CreateChapter(apiKey, special.Title, special.Id, special.VolumeId, seriesId));
}
return CreateXmlResult(SerializeXml(feed)); return CreateXmlResult(SerializeXml(feed));
} }
@ -698,6 +716,23 @@ public class OpdsController : BaseApiController
}; };
} }
private static FeedEntry CreateChapter(string apiKey, string title, int chapterId, int volumeId, int seriesId)
{
return new FeedEntry()
{
Id = chapterId.ToString(),
Title = title,
Links = new List<FeedLink>()
{
CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation,
Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}"),
CreateLink(FeedLinkRelation.Image, FeedLinkType.Image,
$"/api/image/chapter-cover?chapterId={chapterId}")
}
};
}
private FeedEntry CreateChapter(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, SeriesDto series, Volume volume, ChapterDto chapter, string apiKey) private FeedEntry CreateChapter(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, SeriesDto series, Volume volume, ChapterDto chapter, string apiKey)
{ {
var fileSize = var fileSize =

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -14,7 +13,6 @@ using API.Entities.Enums;
using API.Helpers; using API.Helpers;
using API.SignalR; using API.SignalR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
namespace API.Services; namespace API.Services;
@ -460,22 +458,40 @@ public class SeriesService : ISeriesService
{ {
volume.Name += $" - {firstChapter.TitleName}"; volume.Name += $" - {firstChapter.TitleName}";
} }
processedVolumes.Add(volume); processedVolumes.Add(volume);
} }
} }
else else
{ {
processedVolumes = volumes.Where(v => v.Number > 0).ToList(); processedVolumes = volumes.Where(v => v.Number > 0).ToList();
processedVolumes.ForEach(v => v.Name = $"Volume {v.Name}");
} }
var specials = new List<ChapterDto>(); var specials = new List<ChapterDto>();
foreach (var chapter in chapters.Where(c => c.IsSpecial)) foreach (var chapter in chapters)
{ {
chapter.Title = Parser.Parser.CleanSpecialTitle(chapter.Title); if (chapter.IsSpecial)
specials.Add(chapter); {
chapter.Title = Parser.Parser.CleanSpecialTitle(chapter.Title);
specials.Add(chapter);
}
else
{
var title = libraryType switch
{
LibraryType.Book => $"Book {chapter.Title}",
LibraryType.Comic => $"Issue #{chapter.Title}",
LibraryType.Manga => $"Chapter {chapter.Title}",
_ => "Chapter "
};
chapter.Title = title;
}
} }
// Don't show chapter 0 (aka single volume chapters) in the Chapters tab or books that are just single numbers (they show as volumes) // Don't show chapter 0 (aka single volume chapters) in the Chapters tab or books that are just single numbers (they show as volumes)
IEnumerable<ChapterDto> retChapters; IEnumerable<ChapterDto> retChapters;
if (libraryType == LibraryType.Book) if (libraryType == LibraryType.Book)
@ -497,7 +513,7 @@ public class SeriesService : ISeriesService
Volumes = processedVolumes, Volumes = processedVolumes,
StorylineChapters = volumes StorylineChapters = volumes
.Where(v => v.Number == 0) .Where(v => v.Number == 0)
.SelectMany(v => v.Chapters) .SelectMany(v => v.Chapters.Where(c => !c.IsSpecial))
.OrderBy(c => float.Parse(c.Number), new ChapterSortComparer()) .OrderBy(c => float.Parse(c.Number), new ChapterSortComparer())
}; };

View File

@ -1,4 +1,5 @@
import { Injectable } from '@angular/core'; import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, Renderer2, RendererFactory2 } from '@angular/core';
import { ReplaySubject, take } from 'rxjs'; import { ReplaySubject, take } from 'rxjs';
@Injectable({ @Injectable({
@ -25,7 +26,10 @@ export class NavService {
*/ */
sideNavVisibility$ = this.sideNavVisibilitySource.asObservable(); sideNavVisibility$ = this.sideNavVisibilitySource.asObservable();
constructor() { private renderer: Renderer2;
constructor(@Inject(DOCUMENT) private document: Document, rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
this.showNavBar(); this.showNavBar();
const sideNavState = (localStorage.getItem(this.localStorageSideNavKey) === 'true') || false; const sideNavState = (localStorage.getItem(this.localStorageSideNavKey) === 'true') || false;
this.sideNavCollapseSource.next(sideNavState); this.sideNavCollapseSource.next(sideNavState);
@ -36,6 +40,7 @@ export class NavService {
* Shows the top nav bar. This should be visible on all pages except the reader. * Shows the top nav bar. This should be visible on all pages except the reader.
*/ */
showNavBar() { showNavBar() {
this.renderer.setStyle(this.document.querySelector('body'), 'margin-top', '56px');
this.navbarVisibleSource.next(true); this.navbarVisibleSource.next(true);
} }
@ -43,6 +48,7 @@ export class NavService {
* Hides the top nav bar. * Hides the top nav bar.
*/ */
hideNavBar() { hideNavBar() {
this.renderer.setStyle(this.document.querySelector('body'), 'margin-top', '0px');
this.navbarVisibleSource.next(false); this.navbarVisibleSource.next(false);
} }

View File

@ -1,7 +1,7 @@
<app-side-nav-companion-bar> <app-side-nav-companion-bar>
<h1 title> <h2 title>
Admin Dashboard Admin Dashboard
</h1> </h2>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<div class="container-fluid"> <div class="container-fluid">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-tabs"> <ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-tabs">

View File

@ -1,8 +1,8 @@
<app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)"> <app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)">
<h1 title> <h2 title>
<app-card-actionables [actions]="actions"></app-card-actionables> <app-card-actionables [actions]="actions"></app-card-actionables>
All Series All Series
</h1> </h2>
<h6 subtitle style="margin-left:40px;">{{pagination?.totalItems}} Series</h6> <h6 subtitle style="margin-left:40px;">{{pagination?.totalItems}} Series</h6>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations> <app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>

View File

@ -2,12 +2,15 @@
<div [ngClass]="{'closed' : !(navService?.sideNavCollapsed$ | async), 'content-wrapper': navService.sideNavVisibility$ | async}"> <div [ngClass]="{'closed' : !(navService?.sideNavCollapsed$ | async), 'content-wrapper': navService.sideNavVisibility$ | async}">
<a id="content"></a> <a id="content"></a>
<app-side-nav *ngIf="navService.sideNavVisibility$ | async"></app-side-nav> <app-side-nav *ngIf="navService.sideNavVisibility$ | async"></app-side-nav>
<div class="container-fluid" style="padding-top: 10px; padding-bottom: 10px;" *ngIf="navService.sideNavVisibility$ | async else noSideNav"> <div class="container-fluid">
<div class="companion-bar" [ngClass]="{'companion-bar-content': (navService?.sideNavCollapsed$ | async)}"> <div style="padding-top: 10px; padding-bottom: 65px;" *ngIf="navService.sideNavVisibility$ | async else noSideNav">
<router-outlet></router-outlet> <div class="companion-bar" [ngClass]="{'companion-bar-content': (navService?.sideNavCollapsed$ | async)}">
<router-outlet></router-outlet>
</div>
</div> </div>
<ng-template #noSideNav>
<router-outlet></router-outlet>
</ng-template>
</div> </div>
<ng-template #noSideNav>
<router-outlet></router-outlet>
</ng-template>
</div> </div>

View File

@ -1,8 +1,8 @@
<app-side-nav-companion-bar [hasFilter]="false" (filterOpen)="filterOpen.emit($event)"> <app-side-nav-companion-bar [hasFilter]="false" (filterOpen)="filterOpen.emit($event)">
<h1 title> <h2 title>
<app-card-actionables [actions]="collectionTagActions"></app-card-actionables> <app-card-actionables [actions]="collectionTagActions"></app-card-actionables>
Collections Collections
</h1> </h2>
<h6 subtitle style="margin-left:40px;">{{collections.length}} Items</h6> <h6 subtitle style="margin-left:40px;">{{collections.length}} Items</h6>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<app-card-detail-layout <app-card-detail-layout

View File

@ -1,8 +1,8 @@
<app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)"> <app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)">
<h1 title> <h2 title>
<app-card-actionables [actions]="actions"></app-card-actionables> <app-card-actionables [actions]="actions"></app-card-actionables>
{{libraryName}} {{libraryName}}
</h1> </h2>
<h6 subtitle style="margin-left:40px;">{{pagination?.totalItems}} Series</h6> <h6 subtitle style="margin-left:40px;">{{pagination?.totalItems}} Series</h6>
<div main> <div main>
<!-- TODO: Implement Tabs here for Recommended and Library view --> <!-- TODO: Implement Tabs here for Recommended and Library view -->

View File

@ -1,7 +1,7 @@
<app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)"> <app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)">
<h1 title> <h2 title>
On Deck On Deck
</h1> </h2>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations> <app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<app-card-detail-layout <app-card-detail-layout

View File

@ -1,11 +1,11 @@
<app-side-nav-companion-bar [showGoBack]="true"> <app-side-nav-companion-bar [showGoBack]="true">
<h1 title> <h2 title>
<span *ngIf="actions.length > 0"> <span *ngIf="actions.length > 0">
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="readingList.title"></app-card-actionables> <app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="readingList.title"></app-card-actionables>
</span> </span>
{{readingList.title}}&nbsp;<span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>&nbsp; {{readingList.title}}&nbsp;<span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>&nbsp;
<span class="badge bg-primary rounded-pill" attr.aria-label="{{items.length}} total items">{{items.length}}</span> <span class="badge bg-primary rounded-pill" attr.aria-label="{{items.length}} total items">{{items.length}}</span>
</h1> </h2>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<div class="container-fluid mt-2" *ngIf="readingList"> <div class="container-fluid mt-2" *ngIf="readingList">
<div class="mb-3"> <div class="mb-3">

View File

@ -1,8 +1,8 @@
<app-side-nav-companion-bar [showGoBack]="true" pageHeader="Home"> <app-side-nav-companion-bar [showGoBack]="true" pageHeader="Home">
<h1 title> <h2 title>
<app-card-actionables [actions]="actions"></app-card-actionables> <app-card-actionables [actions]="actions"></app-card-actionables>
Reading Lists Reading Lists
</h1> </h2>
<h6 subtitle>{{pagination?.totalItems}} Items</h6> <h6 subtitle>{{pagination?.totalItems}} Items</h6>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>

View File

@ -1,7 +1,7 @@
<app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)"> <app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)">
<h1 title> <h2 title>
Recently Added Recently Added
</h1> </h2>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations> <app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<app-card-detail-layout <app-card-detail-layout

View File

@ -67,7 +67,7 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row g-0"> <div class="row g-0">
<ng-container *ngFor="let chapter of specials; let idx = index; trackBy: trackByChapterIdentity"> <ng-container *ngFor="let chapter of specials; let idx = index; trackBy: trackByChapterIdentity">
<app-card-item class="col-auto p-2" *ngIf="chapter.isSpecial" [entity]="chapter" [title]="chapter.title || chapter.range" (click)="openChapter(chapter)" <app-card-item class="col-auto p-2" [entity]="chapter" [title]="chapter.title || chapter.range" (click)="openChapter(chapter)"
[imageUrl]="imageService.getChapterCoverImage(chapter.id)" [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> [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>
</ng-container> </ng-container>
@ -79,12 +79,12 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row g-0"> <div class="row g-0">
<ng-container *ngFor="let volume of volumes; let idx = index; trackBy: trackByVolumeIdentity"> <ng-container *ngFor="let volume of volumes; let idx = index; trackBy: trackByVolumeIdentity">
<app-card-item class="col-auto p-2" *ngIf="volume.number != 0" [entity]="volume" [title]="formatVolumeTitle(volume)" (click)="openVolume(volume)" <app-card-item class="col-auto p-2" *ngIf="volume.number != 0" [entity]="volume" [title]="volume.name" (click)="openVolume(volume)"
[imageUrl]="imageService.getVolumeCoverImage(volume.id) + '&offset=' + coverImageOffset" [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> [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>
</ng-container> </ng-container>
<ng-container *ngFor="let chapter of storyChapters; let idx = index; trackBy: trackByChapterIdentity"> <ng-container *ngFor="let chapter of storyChapters; let idx = index; trackBy: trackByChapterIdentity">
<app-card-item class="col-auto p-2" *ngIf="!chapter.isSpecial" [entity]="chapter" [title]="formatChapterTitle(chapter)" (click)="openChapter(chapter)" <app-card-item class="col-auto p-2" *ngIf="!chapter.isSpecial" [entity]="chapter" [title]="chapter.title" (click)="openChapter(chapter)"
[imageUrl]="imageService.getChapterCoverImage(chapter.id) + '&offset=' + coverImageOffset" [imageUrl]="imageService.getChapterCoverImage(chapter.id) + '&offset=' + coverImageOffset"
[read]="chapter.pagesRead" [total]="chapter.pages" [actions]="chapterActions" (selection)="bulkSelectionService.handleCardSelection('chapter', idx, storyChapters.length, $event)" [selected]="bulkSelectionService.isCardSelected('chapter', idx)" [allowSelection]="true"></app-card-item> [read]="chapter.pagesRead" [total]="chapter.pages" [actions]="chapterActions" (selection)="bulkSelectionService.handleCardSelection('chapter', idx, storyChapters.length, $event)" [selected]="bulkSelectionService.isCardSelected('chapter', idx)" [allowSelection]="true"></app-card-item>
</ng-container> </ng-container>
@ -96,7 +96,7 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row g-0"> <div class="row g-0">
<ng-container *ngFor="let volume of volumes; let idx = index; trackBy: trackByVolumeIdentity"> <ng-container *ngFor="let volume of volumes; let idx = index; trackBy: trackByVolumeIdentity">
<app-card-item class="col-auto p-2" [entity]="volume" [title]="formatVolumeTitle(volume)" (click)="openVolume(volume)" <app-card-item class="col-auto p-2" [entity]="volume" [title]="volume.name" (click)="openVolume(volume)"
[imageUrl]="imageService.getVolumeCoverImage(volume.id) + '&offset=' + coverImageOffset" [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> [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>
</ng-container> </ng-container>
@ -108,7 +108,7 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row g-0"> <div class="row g-0">
<ng-container *ngFor="let chapter of chapters; let idx = index; trackBy: trackByChapterIdentity"> <ng-container *ngFor="let chapter of chapters; let idx = index; trackBy: trackByChapterIdentity">
<app-card-item class="col-auto p-2" *ngIf="!chapter.isSpecial" [entity]="chapter" [title]="formatChapterTitle(chapter)" (click)="openChapter(chapter)" <app-card-item class="col-auto p-2" *ngIf="!chapter.isSpecial" [entity]="chapter" [title]="chapter.title" (click)="openChapter(chapter)"
[imageUrl]="imageService.getChapterCoverImage(chapter.id) + '&offset=' + coverImageOffset" [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> [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>
</ng-container> </ng-container>

View File

@ -1,7 +1,7 @@
<app-side-nav-companion-bar> <app-side-nav-companion-bar>
<h1 title> <h2 title>
User Dashboard User Dashboard
</h1> </h2>
</app-side-nav-companion-bar> </app-side-nav-companion-bar>
<div class="container-fluid"> <div class="container-fluid">
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-tabs"> <ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-tabs">

View File

@ -8,7 +8,7 @@ body {
color-scheme: var(--color-scheme); color-scheme: var(--color-scheme);
max-height: 100%; max-height: 100%;
overflow-y: auto; overflow-y: auto;
margin-top: 56px; //margin-top: 56px; // Set by nav service
} }