UX Pass 7 (#3135)
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
5bf5558212
commit
79eb98a3bb
67 changed files with 1398 additions and 1006 deletions
|
|
@ -1,166 +1,168 @@
|
|||
<ng-container *transloco="let t; read: 'reading-list-detail'">
|
||||
<app-side-nav-companion-bar [hasExtras]="readingList !== undefined" [extraDrawer]="extrasDrawer">
|
||||
<h4 title>
|
||||
{{readingList?.title}}
|
||||
@if (readingList?.promoted) {
|
||||
<span class="ms-1">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>
|
||||
}
|
||||
@if (actions.length > 0) {
|
||||
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [attr.aria-labelledby]="readingList?.title"></app-card-actionables>
|
||||
}
|
||||
</h4>
|
||||
<h5 subtitle class="subtitle-with-actionables">{{t('item-count', {num: items.length | number})}}</h5>
|
||||
<div class="main-container container-fluid">
|
||||
<ng-container *transloco="let t; read: 'reading-list-detail'">
|
||||
<app-side-nav-companion-bar [hasExtras]="readingList !== undefined" [extraDrawer]="extrasDrawer">
|
||||
<h4 title>
|
||||
{{readingList?.title}}
|
||||
@if (readingList?.promoted) {
|
||||
<span class="ms-1">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>
|
||||
}
|
||||
@if (actions.length > 0) {
|
||||
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [attr.aria-labelledby]="readingList?.title"></app-card-actionables>
|
||||
}
|
||||
</h4>
|
||||
<h5 subtitle class="subtitle-with-actionables">{{t('item-count', {num: items.length | number})}}</h5>
|
||||
|
||||
<ng-template #extrasDrawer let-offcanvas>
|
||||
@if (readingList) {
|
||||
<div>
|
||||
<div class="offcanvas-header">
|
||||
<h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title')}}</h4>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="offcanvas.dismiss()"></button>
|
||||
<ng-template #extrasDrawer let-offcanvas>
|
||||
@if (readingList) {
|
||||
<div>
|
||||
<div class="offcanvas-header">
|
||||
<h4 class="offcanvas-title" id="offcanvas-basic-title">{{t('page-settings-title')}}</h4>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="offcanvas.dismiss()"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-12 col-sm-12 pe-2 mb-3">
|
||||
<button class="btn btn-danger" (click)="removeRead()" [disabled]="readingList.promoted && !this.isAdmin">
|
||||
<span>
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
<span class="read-btn--text"> {{t('remove-read')}}</span>
|
||||
</button>
|
||||
|
||||
@if (!(readingList.promoted && !this.isAdmin)) {
|
||||
<div class="col-auto ms-2 mt-2">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="accessibility-mode" [disabled]="this.utilityService.getActiveBreakpoint() < Breakpoint.Tablet" [value]="accessibilityMode" (change)="updateAccessibilityMode()">
|
||||
<label class="form-check-label" for="accessibility-mode">{{t('order-numbers-label')}}</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-12 col-sm-12 pe-2 mb-3">
|
||||
<button class="btn btn-danger" (click)="removeRead()" [disabled]="readingList.promoted && !this.isAdmin">
|
||||
<span>
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
<span class="read-btn--text"> {{t('remove-read')}}</span>
|
||||
</button>
|
||||
}
|
||||
</ng-template>
|
||||
</app-side-nav-companion-bar>
|
||||
|
||||
@if (!(readingList.promoted && !this.isAdmin)) {
|
||||
<div class="col-auto ms-2 mt-2">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="accessibility-mode" [disabled]="this.utilityService.getActiveBreakpoint() < Breakpoint.Tablet" [value]="accessibilityMode" (change)="updateAccessibilityMode()">
|
||||
<label class="form-check-label" for="accessibility-mode">{{t('order-numbers-label')}}</label>
|
||||
@if (readingList) {
|
||||
<div class="container-fluid mt-2">
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-2 col-xs-4 col-sm-6 d-none d-sm-block">
|
||||
<app-image [styles]="{'max-height': '400px', 'max-width': '300px'}" [imageUrl]="imageService.getReadingListCoverImage(readingList.id)"></app-image>
|
||||
</div>
|
||||
<div class="col-md-10 col-xs-8 col-sm-6 mt-2">
|
||||
<div class="row g-0 mb-3">
|
||||
<div class="col-auto me-2">
|
||||
<!-- Action row-->
|
||||
<div class="btn-group me-3">
|
||||
<button type="button" class="btn btn-primary" (click)="continue()">
|
||||
<span>
|
||||
<i class="fa fa-book-open me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text">{{t('continue')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<div class="btn-group" ngbDropdown role="group" [attr.aria-label]="t('read-options-alt')">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle-split" ngbDropdownToggle></button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu>
|
||||
<button ngbDropdownItem (click)="read()">
|
||||
<span>
|
||||
<i class="fa fa-book" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> {{t('read')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="continue(true)">
|
||||
<span>
|
||||
<i class="fa fa-book-open me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text">{{t('continue')}}</span>
|
||||
(<i class="fa fa-glasses ms-1" aria-hidden="true"></i>)
|
||||
<span class="visually-hidden">{{t('incognito-alt')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="read(true)">
|
||||
<span>
|
||||
<i class="fa fa-book me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> {{t('read')}}</span>
|
||||
(<i class="fa fa-glasses ms-1" aria-hidden="true"></i>)
|
||||
<span class="visually-hidden">{{t('incognito-alt')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
</app-side-nav-companion-bar>
|
||||
|
||||
@if (readingList) {
|
||||
<div class="container-fluid mt-2">
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-2 col-xs-4 col-sm-6 d-none d-sm-block">
|
||||
<app-image [styles]="{'max-height': '400px', 'max-width': '300px'}" [imageUrl]="imageService.getReadingListCoverImage(readingList.id)"></app-image>
|
||||
</div>
|
||||
<div class="col-md-10 col-xs-8 col-sm-6 mt-2">
|
||||
<div class="row g-0 mb-3">
|
||||
<div class="col-auto me-2">
|
||||
<!-- Action row-->
|
||||
<div class="btn-group me-3">
|
||||
<button type="button" class="btn btn-primary" (click)="continue()">
|
||||
<span>
|
||||
<i class="fa fa-book-open me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text">{{t('continue')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<div class="btn-group" ngbDropdown role="group" [attr.aria-label]="t('read-options-alt')">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle-split" ngbDropdownToggle></button>
|
||||
<div class="dropdown-menu" ngbDropdownMenu>
|
||||
<button ngbDropdownItem (click)="read()">
|
||||
<span>
|
||||
<i class="fa fa-book" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> {{t('read')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="continue(true)">
|
||||
<span>
|
||||
<i class="fa fa-book-open me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text">{{t('continue')}}</span>
|
||||
(<i class="fa fa-glasses ms-1" aria-hidden="true"></i>)
|
||||
<span class="visually-hidden">{{t('incognito-alt')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<button ngbDropdownItem (click)="read(true)">
|
||||
<span>
|
||||
<i class="fa fa-book me-1" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> {{t('read')}}</span>
|
||||
(<i class="fa fa-glasses ms-1" aria-hidden="true"></i>)
|
||||
<span class="visually-hidden">{{t('incognito-alt')}}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (readingList.startingYear !== 0) {
|
||||
<div class="row g-0 mt-2">
|
||||
<h4 class="reading-list-years">
|
||||
@if (readingList.startingMonth > 0) {
|
||||
{{(readingList.startingMonth +'/01/2020')| date:'MMM'}}
|
||||
}
|
||||
@if (readingList.startingMonth > 0 && readingList.startingYear > 0) {
|
||||
,
|
||||
}
|
||||
@if (readingList.startingYear > 0) {
|
||||
{{readingList.startingYear}}
|
||||
}
|
||||
—
|
||||
@if (readingList.endingYear > 0) {
|
||||
@if (readingList.endingMonth > 0) {
|
||||
{{(readingList.endingMonth +'/01/2020')| date:'MMM'}}
|
||||
@if (readingList.startingYear !== 0) {
|
||||
<div class="row g-0 mt-2">
|
||||
<h4 class="reading-list-years">
|
||||
@if (readingList.startingMonth > 0) {
|
||||
{{(readingList.startingMonth +'/01/2020')| date:'MMM'}}
|
||||
}
|
||||
@if (readingList.endingMonth > 0 && readingList.endingYear > 0) {
|
||||
@if (readingList.startingMonth > 0 && readingList.startingYear > 0) {
|
||||
,
|
||||
}
|
||||
@if (readingList.endingYear > 0) {
|
||||
{{readingList.endingYear}}
|
||||
@if (readingList.startingYear > 0) {
|
||||
{{readingList.startingYear}}
|
||||
}
|
||||
}
|
||||
</h4>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<!-- Summary row-->
|
||||
<div class="row g-0 mt-2">
|
||||
<app-read-more [text]="readingListSummary" [maxLength]="250"></app-read-more>
|
||||
</div>
|
||||
|
||||
@if (characters$ | async; as characters) {
|
||||
@if (characters && characters.length > 0) {
|
||||
<div class="row mb-2">
|
||||
<div class="row">
|
||||
<h5>{{t('characters-title')}}</h5>
|
||||
<app-badge-expander [items]="characters">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="goToCharacter(item)">{{item.name}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
—
|
||||
@if (readingList.endingYear > 0) {
|
||||
@if (readingList.endingMonth > 0) {
|
||||
{{(readingList.endingMonth +'/01/2020')| date:'MMM'}}
|
||||
}
|
||||
@if (readingList.endingMonth > 0 && readingList.endingYear > 0) {
|
||||
,
|
||||
}
|
||||
@if (readingList.endingYear > 0) {
|
||||
{{readingList.endingYear}}
|
||||
}
|
||||
}
|
||||
</h4>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<!-- Summary row-->
|
||||
<div class="row g-0 mt-2">
|
||||
<app-read-more [text]="readingListSummary" [maxLength]="(utilityService.activeBreakpoint$ | async)! >= Breakpoint.Desktop ? 585 : 200"></app-read-more>
|
||||
</div>
|
||||
|
||||
@if (characters$ | async; as characters) {
|
||||
@if (characters && characters.length > 0) {
|
||||
<div class="row mb-2">
|
||||
<div class="row">
|
||||
<h5>{{t('characters-title')}}</h5>
|
||||
<app-badge-expander [items]="characters">
|
||||
<ng-template #badgeExpanderItem let-item let-position="idx">
|
||||
<a href="javascript:void(0)" class="dark-exempt btn-icon" (click)="goToCharacter(item)">{{item.name}}</a>
|
||||
</ng-template>
|
||||
</app-badge-expander>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 scroll-container" #scrollingBlock>
|
||||
@if (items.length === 0 && !isLoading) {
|
||||
<div class="mx-auto" style="width: 200px;">
|
||||
{{t('no-data')}}
|
||||
</div>
|
||||
} @else if(isLoading) {
|
||||
<app-loading [loading]="isLoading"></app-loading>
|
||||
}
|
||||
|
||||
<app-draggable-ordered-list [items]="items" (orderUpdated)="orderUpdated($event)" [accessibilityMode]="accessibilityMode"
|
||||
[showRemoveButton]="false">
|
||||
<ng-template #draggableItem let-item let-position="idx">
|
||||
<app-reading-list-item [ngClass]="{'content-container': items.length < 100, 'non-virtualized-container': items.length >= 100}" [item]="item" [position]="position" [libraryTypes]="libraryTypes"
|
||||
[promoted]="item.promoted" (read)="readChapter($event)" (remove)="itemRemoved($event, position)"></app-reading-list-item>
|
||||
</ng-template>
|
||||
</app-draggable-ordered-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 scroll-container" #scrollingBlock>
|
||||
@if (items.length === 0 && !isLoading) {
|
||||
<div class="mx-auto" style="width: 200px;">
|
||||
{{t('no-data')}}
|
||||
</div>
|
||||
} @else if(isLoading) {
|
||||
<app-loading [loading]="isLoading"></app-loading>
|
||||
}
|
||||
|
||||
<app-draggable-ordered-list [items]="items" (orderUpdated)="orderUpdated($event)" [accessibilityMode]="accessibilityMode"
|
||||
[showRemoveButton]="false">
|
||||
<ng-template #draggableItem let-item let-position="idx">
|
||||
<app-reading-list-item [ngClass]="{'content-container': items.length < 100, 'non-virtualized-container': items.length >= 100}" [item]="item" [position]="position" [libraryTypes]="libraryTypes"
|
||||
[promoted]="item.promoted" (read)="readChapter($event)" (remove)="itemRemoved($event, position)"></app-reading-list-item>
|
||||
</ng-template>
|
||||
</app-draggable-ordered-list>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ng-container>
|
||||
}
|
||||
</ng-container>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,35 +1,38 @@
|
|||
<ng-container *transloco="let t; read: 'reading-lists'">
|
||||
<app-side-nav-companion-bar>
|
||||
<h4 title>
|
||||
<span>{{t('title')}}</span>
|
||||
<app-card-actionables [actions]="globalActions" (actionHandler)="performGlobalAction($event)"></app-card-actionables>
|
||||
</h4>
|
||||
@if (pagination) {
|
||||
<h5 subtitle class="subtitle-with-actionables">{{t('item-count', {num: pagination.totalItems | number})}}</h5>
|
||||
}
|
||||
<div class="main-container container-fluid">
|
||||
<ng-container *transloco="let t; read: 'reading-lists'">
|
||||
<app-side-nav-companion-bar>
|
||||
<h4 title>
|
||||
<span>{{t('title')}}</span>
|
||||
<app-card-actionables [actions]="globalActions" (actionHandler)="performGlobalAction($event)"></app-card-actionables>
|
||||
</h4>
|
||||
@if (pagination) {
|
||||
<h5 subtitle class="subtitle-with-actionables">{{t('item-count', {num: pagination.totalItems | number})}}</h5>
|
||||
}
|
||||
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
|
||||
<app-card-detail-layout
|
||||
[isLoading]="loadingLists"
|
||||
[items]="lists"
|
||||
[pagination]="pagination"
|
||||
[jumpBarKeys]="jumpbarKeys"
|
||||
[filteringDisabled]="true"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx" >
|
||||
<app-card-item [title]="item.title" [entity]="item" [actions]="actions[item.id]"
|
||||
[suppressLibraryLink]="true" [imageUrl]="imageService.getReadingListCoverImage(item.id)"
|
||||
(clicked)="handleClick(item)"
|
||||
(selection)="bulkSelectionService.handleCardSelection('readingList', position, lists.length, $event)"
|
||||
[selected]="bulkSelectionService.isCardSelected('readingList', position)" [allowSelection]="true"></app-card-item>
|
||||
</ng-template>
|
||||
<app-card-detail-layout
|
||||
[isLoading]="loadingLists"
|
||||
[items]="lists"
|
||||
[pagination]="pagination"
|
||||
[jumpBarKeys]="jumpbarKeys"
|
||||
[filteringDisabled]="true"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx" >
|
||||
<app-card-item [title]="item.title" [entity]="item" [actions]="actions[item.id]"
|
||||
[suppressLibraryLink]="true" [imageUrl]="imageService.getReadingListCoverImage(item.id)"
|
||||
[linkUrl]="'/lists/' + item.id"
|
||||
(clicked)="handleClick(item)"
|
||||
(selection)="bulkSelectionService.handleCardSelection('readingList', position, lists.length, $event)"
|
||||
[selected]="bulkSelectionService.isCardSelected('readingList', position)" [allowSelection]="true"></app-card-item>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #noData>
|
||||
{{t('no-data')}} {{t('create-one-part-1')}} <a [href]="WikiLink.ReadingLists" rel="noopener noreferrer" target="_blank">{{t('create-one-part-2')}}<i class="fa fa-external-link-alt ms-1" aria-hidden="true"></i></a>.
|
||||
</ng-template>
|
||||
</app-card-detail-layout>
|
||||
<ng-template #noData>
|
||||
{{t('no-data')}} {{t('create-one-part-1')}} <a [href]="WikiLink.ReadingLists" rel="noopener noreferrer" target="_blank">{{t('create-one-part-2')}}<i class="fa fa-external-link-alt ms-1" aria-hidden="true"></i></a>.
|
||||
</ng-template>
|
||||
</app-card-detail-layout>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -89,18 +89,16 @@ export class ReadingListsComponent implements OnInit {
|
|||
.filter(action => this.readingListService.actionListFilter(action, readingList, this.isAdmin || this.hasPromote));
|
||||
}
|
||||
|
||||
performAction(action: ActionItem<ReadingList>, readingList: ReadingList) {
|
||||
if (typeof action.callback === 'function') {
|
||||
action.callback(action, readingList);
|
||||
}
|
||||
}
|
||||
|
||||
performGlobalAction(action: ActionItem<any>) {
|
||||
if (typeof action.callback === 'function') {
|
||||
action.callback(action, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(list: ReadingList) {
|
||||
this.router.navigateByUrl('lists/' + list.id);
|
||||
}
|
||||
|
||||
handleReadingListActionCallback(action: ActionItem<ReadingList>, readingList: ReadingList) {
|
||||
switch(action.action) {
|
||||
case Action.Delete:
|
||||
|
|
@ -159,10 +157,6 @@ export class ReadingListsComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
handleClick(list: ReadingList) {
|
||||
this.router.navigateByUrl('lists/' + list.id);
|
||||
}
|
||||
|
||||
bulkActionCallback = (action: ActionItem<any>, data: any) => {
|
||||
const selectedReadingListIndexies = this.bulkSelectionService.getSelectedCardsForSource('readingList');
|
||||
const selectedReadingLists = this.lists.filter((col, index: number) => selectedReadingListIndexies.includes(index + ''));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue