mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
Revamp sorting dropdown
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
@@ -18,74 +18,57 @@
|
||||
|
||||
<div class="flex items-center gap-8">
|
||||
|
||||
<a *ngIf="isFilterActive" class="topbar-items topbar-item" (click)="clearFilter()">
|
||||
<i
|
||||
class="pi pi-filter-slash"
|
||||
pTooltip="Clear applied filters"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
<div class="flex flex-row items-center gap-4">
|
||||
<a *ngIf="isFilterActive" class="topbar-items topbar-item" (click)="clearFilter()">
|
||||
<i
|
||||
class="pi pi-filter-slash"
|
||||
pTooltip="Clear applied filters"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
|
||||
<a class="topbar-items topbar-item">
|
||||
<i
|
||||
class="pi pi-sort"
|
||||
pTooltip="Select sorting"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
<a class="topbar-items topbar-item" (click)="sortMenu.toggle($event)">
|
||||
<i class="pi pi-sort" pTooltip="Select sorting" tooltipPosition="top"></i>
|
||||
</a>
|
||||
<p-menu #sortMenu [popup]="true" [model]="sortOptions" appendTo="body">
|
||||
<ng-template pTemplate="item" let-item>
|
||||
<div class="flex justify-between items-center w-full px-4 py-2 cursor-pointer" (click)="sortBooks(item.field)">
|
||||
<span>{{ item.label }}</span>
|
||||
<i *ngIf="item.icon" [class]="item.icon"></i>
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-menu>
|
||||
|
||||
<a class="topbar-items topbar-item" (click)="toggleTableGrid()">
|
||||
<i
|
||||
[ngClass]="viewIcon"
|
||||
pTooltip="Toggle between Grid and Table view"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
<a class="topbar-items topbar-item" (click)="toggleTableGrid()">
|
||||
<i
|
||||
[ngClass]="viewIcon"
|
||||
pTooltip="Toggle between Grid and Table view"
|
||||
tooltipPosition="top">
|
||||
</i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<p-fluid>
|
||||
<div class="relative">
|
||||
<input type="text"
|
||||
pInputText
|
||||
placeholder="Search title or author..."
|
||||
[(ngModel)]="bookTitle"
|
||||
(ngModelChange)="onBookTitleChange($event)"/>
|
||||
<p-button *ngIf="bookTitle"
|
||||
icon="pi pi-times"
|
||||
[text]="true"
|
||||
size="small"
|
||||
[rounded]="true"
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2"
|
||||
(click)="clearSearch()">
|
||||
<input
|
||||
type="text"
|
||||
pInputText
|
||||
placeholder="Search title or author..."
|
||||
[(ngModel)]="bookTitle"
|
||||
(ngModelChange)="onBookTitleChange($event)"/>
|
||||
<p-button
|
||||
*ngIf="bookTitle"
|
||||
icon="pi pi-times"
|
||||
[text]="true"
|
||||
size="small"
|
||||
[rounded]="true"
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2"
|
||||
(click)="clearSearch()">
|
||||
</p-button>
|
||||
</div>
|
||||
</p-fluid>
|
||||
|
||||
<p-select
|
||||
[options]="sortOptions"
|
||||
optionLabel="label"
|
||||
placeholder="Select Sorting"
|
||||
[(ngModel)]="selectedSort"
|
||||
(onChange)="updateSortOption($event.value)"/>
|
||||
|
||||
<!--<p-button
|
||||
[icon]="viewIcon"
|
||||
size="large"
|
||||
[rounded]="true"
|
||||
text="true"
|
||||
pTooltip="Toggle between Grid and Table view"
|
||||
tooltipPosition="top"
|
||||
(click)="toggleTableGrid()"/>-->
|
||||
|
||||
<!--<p-button
|
||||
*ngIf="isFilterActive"
|
||||
icon="pi pi-filter-slash"
|
||||
size="large"
|
||||
[rounded]="true"
|
||||
text="true"
|
||||
(click)="clearFilter()"
|
||||
pTooltip="Clear applied filters"
|
||||
tooltipPosition="top"/>-->
|
||||
|
||||
<p-button
|
||||
class="pr-2"
|
||||
icon="pi pi-chevron-right"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {AfterViewInit, Component, inject, OnInit, ViewChild} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {MenuItem, MessageService} from 'primeng/api';
|
||||
import {MenuItem, MessageService, PrimeTemplate} from 'primeng/api';
|
||||
import {LibraryService} from '../../service/library.service';
|
||||
import {BookService} from '../../service/book.service';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
@@ -11,7 +11,7 @@ import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {Library} from '../../model/library.model';
|
||||
import {Shelf} from '../../model/shelf.model';
|
||||
import {SortService} from '../../service/sort.service';
|
||||
import {SortOption} from '../../model/sort.model';
|
||||
import {SortDirection, SortOption} from '../../model/sort.model';
|
||||
import {BookState} from '../../model/state/book-state.model';
|
||||
import {Book} from '../../model/book.model';
|
||||
import {LibraryShelfMenuService} from '../../service/library-shelf-menu.service';
|
||||
@@ -24,7 +24,6 @@ import {AsyncPipe, NgClass, NgForOf, NgIf} from '@angular/common';
|
||||
import {VirtualScrollerModule} from '@iharbeck/ngx-virtual-scroller';
|
||||
import {BookCardComponent} from './book-card/book-card.component';
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
import {Select} from 'primeng/select';
|
||||
import {Menu} from 'primeng/menu';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
@@ -43,7 +42,7 @@ export enum EntityType {
|
||||
standalone: true,
|
||||
templateUrl: './book-browser.component.html',
|
||||
styleUrls: ['./book-browser.component.scss'],
|
||||
imports: [Button, NgIf, VirtualScrollerModule, BookCardComponent, AsyncPipe, ProgressSpinner, Select, Menu, NgForOf, InputText, FormsModule, BookTableComponent, BookFilterComponent, Tooltip, NgClass, Fluid],
|
||||
imports: [Button, NgIf, VirtualScrollerModule, BookCardComponent, AsyncPipe, ProgressSpinner, Menu, NgForOf, InputText, FormsModule, BookTableComponent, BookFilterComponent, Tooltip, NgClass, Fluid, PrimeTemplate],
|
||||
animations: [
|
||||
trigger('slideInOut', [
|
||||
state('void', style({
|
||||
@@ -72,8 +71,6 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
bookTitle: string = '';
|
||||
entityOptions: MenuItem[] | undefined;
|
||||
selectedBooks = new Set<number>();
|
||||
selectedSort: SortOption | null = null;
|
||||
sortOptions: SortOption[] = [];
|
||||
isDrawerVisible: boolean = false;
|
||||
dynamicDialogRef: DynamicDialogRef | undefined;
|
||||
EntityType = EntityType;
|
||||
@@ -95,9 +92,24 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
private sortService = inject(SortService);
|
||||
private libraryShelfMenuService = inject(LibraryShelfMenuService);
|
||||
|
||||
sortOptions: any[] = [
|
||||
{label: 'Title', icon: '', field: 'title', command: () => this.sortBooks('title')},
|
||||
{label: 'Publisher', icon: '', field: 'publisher', command: () => this.sortBooks('publisher')},
|
||||
{label: 'Published', icon: '', field: 'publishedDate', command: () => this.sortBooks('publishedDate')},
|
||||
{label: 'Pages', icon: '', field: 'pageCount', command: () => this.sortBooks('pageCount')},
|
||||
{label: 'Rating', icon: '', field: 'rating', command: () => this.sortBooks('rating')},
|
||||
{label: 'Reviews', icon: '', field: 'reviewCount', command: () => this.sortBooks('reviewCount')},
|
||||
];
|
||||
|
||||
selectedSort: SortOption = {
|
||||
label: 'Title',
|
||||
field: 'title',
|
||||
direction: SortDirection.DESCENDING,
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.bookService.loadBooks();
|
||||
this.sortOptions = SortService.generateSortOptions();
|
||||
this.sortBooks(this.selectedSort.field);
|
||||
const isAllBooksRoute = this.activatedRoute.snapshot.routeConfig?.path === 'all-books';
|
||||
|
||||
if (isAllBooksRoute) {
|
||||
@@ -324,8 +336,7 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
}
|
||||
|
||||
updateSortOption(sortOption: SortOption): void {
|
||||
this.selectedSort = sortOption;
|
||||
applySortOption(sortOption: SortOption): void {
|
||||
if (this.entityType === EntityType.ALL_BOOKS) {
|
||||
this.bookState$ = this.fetchAllBooks();
|
||||
} else {
|
||||
@@ -346,7 +357,11 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
const {field, direction} = entity.sort;
|
||||
this.selectedSort = this.sortOptions.find(option => option.field === field && option.direction === direction) || null;
|
||||
} else {
|
||||
this.selectedSort = null;
|
||||
this.selectedSort = {
|
||||
label: 'Title',
|
||||
field: 'title',
|
||||
direction: SortDirection.ASCENDING,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +427,25 @@ export class BookBrowserComponent implements OnInit, AfterViewInit {
|
||||
this.clearSearch();
|
||||
}
|
||||
|
||||
sortBooks(field: string) {
|
||||
if (this.selectedSort?.field === field) {
|
||||
this.selectedSort.direction = this.selectedSort.direction === SortDirection.ASCENDING ? SortDirection.DESCENDING : SortDirection.ASCENDING;
|
||||
} else {
|
||||
this.selectedSort.field = field;
|
||||
this.selectedSort.direction = SortDirection.ASCENDING;
|
||||
}
|
||||
this.updateSortOptions();
|
||||
this.applySortOption(this.selectedSort)
|
||||
}
|
||||
|
||||
updateSortOptions() {
|
||||
const directionIcon = this.selectedSort.direction === SortDirection.ASCENDING ? 'pi pi-arrow-up' : 'pi pi-arrow-down';
|
||||
this.sortOptions = this.sortOptions.map((option) => ({
|
||||
...option,
|
||||
icon: option.field === this.selectedSort.field ? directionIcon : '',
|
||||
}));
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.bookFilterComponent.authorSelected.subscribe((authorId: number) => {
|
||||
this.selectedAuthor.next(authorId);
|
||||
|
||||
@@ -38,21 +38,4 @@ export class SortService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static generateSortOptions(): SortOption[] {
|
||||
return [
|
||||
{label: '↑ Title', field: 'title', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Title', field: 'title', direction: SortDirection.DESCENDING},
|
||||
{label: '↑ Published', field: 'publishedDate', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Published', field: 'publishedDate', direction: SortDirection.DESCENDING},
|
||||
{label: '↑ Pages', field: 'pageCount', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Pages', field: 'pageCount', direction: SortDirection.DESCENDING},
|
||||
{label: '↑ Rating', field: 'rating', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Rating', field: 'rating', direction: SortDirection.DESCENDING},
|
||||
{label: '↑ Reviews', field: 'reviewCount', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Reviews', field: 'reviewCount', direction: SortDirection.DESCENDING},
|
||||
{label: '↑ Publisher', field: 'publisher', direction: SortDirection.ASCENDING},
|
||||
{label: '↓ Publisher', field: 'publisher', direction: SortDirection.DESCENDING}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user