mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
Upgrade from Angular 20 to 21 + update other dependencies (#1916)
Co-authored-by: acx10 <acx10@users.noreply.github.com>
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"outputPath": "dist/booklore",
|
||||
"index": "src/index.html",
|
||||
@@ -91,7 +91,7 @@
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"builder": "@angular/build:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "booklore:build:production"
|
||||
@@ -103,10 +103,10 @@
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"builder": "@angular/build:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
|
||||
9005
booklore-ui/package-lock.json
generated
9005
booklore-ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,17 +12,17 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^20.3.5",
|
||||
"@angular/cdk": "^20.2.9",
|
||||
"@angular/common": "^20.3.5",
|
||||
"@angular/compiler": "^20.3.5",
|
||||
"@angular/core": "^20.3.5",
|
||||
"@angular/forms": "^20.3.5",
|
||||
"@angular/platform-browser": "^20.3.5",
|
||||
"@angular/platform-browser-dynamic": "^20.3.5",
|
||||
"@angular/router": "^20.3.5",
|
||||
"@angular/animations": "^21.0.5",
|
||||
"@angular/cdk": "^21.0.3",
|
||||
"@angular/common": "^21.0.5",
|
||||
"@angular/compiler": "^21.0.5",
|
||||
"@angular/core": "^21.0.5",
|
||||
"@angular/forms": "^21.0.5",
|
||||
"@angular/platform-browser": "^21.0.5",
|
||||
"@angular/platform-browser-dynamic": "^21.0.5",
|
||||
"@angular/router": "^21.0.5",
|
||||
"@iharbeck/ngx-virtual-scroller": "^19.0.1",
|
||||
"@primeng/themes": "^20.4.0",
|
||||
"@primeng/themes": "^21.0.2",
|
||||
"@stomp/rx-stomp": "^2.3.0",
|
||||
"@stomp/stompjs": "^7.2.1",
|
||||
"@tweenjs/tween.js": "^25.0.0",
|
||||
@@ -34,10 +34,10 @@
|
||||
"jwt-decode": "^4.0.0",
|
||||
"ng-lazyload-image": "^9.1.3",
|
||||
"ng2-charts": "^8.0.0",
|
||||
"ngx-extended-pdf-viewer": "^25.6.1",
|
||||
"ngx-infinite-scroll": "^20.0.0",
|
||||
"ngx-extended-pdf-viewer": "^25.6.4",
|
||||
"ngx-infinite-scroll": "^21.0.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "^20.4.0",
|
||||
"primeng": "^21.0.2",
|
||||
"quill": "^2.0.3",
|
||||
"rxjs": "^7.8.2",
|
||||
"showdown": "^2.1.0",
|
||||
@@ -47,16 +47,16 @@
|
||||
"zone.js": "^0.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^20.3.5",
|
||||
"@angular/cli": "^20.3.5",
|
||||
"@angular/compiler-cli": "^20.3.5",
|
||||
"@angular/build": "^21.0.3",
|
||||
"@angular/cli": "^21.0.3",
|
||||
"@angular/compiler-cli": "^21.0.5",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/jasmine": "^5.1.13",
|
||||
"@types/showdown": "^2.0.6",
|
||||
"angular-eslint": "^20.3.5",
|
||||
"autoprefixer": "^10.4.22",
|
||||
"eslint": "^9.39.1",
|
||||
"jasmine-core": "^5.12.1",
|
||||
"angular-eslint": "^21.1.0",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"eslint": "^9.39.2",
|
||||
"jasmine-core": "^5.13.0",
|
||||
"karma": "^6.4.4",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage": "^2.2.1",
|
||||
@@ -64,6 +64,6 @@
|
||||
"karma-jasmine-html-reporter": "^2.1.0",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.9.3",
|
||||
"typescript-eslint": "^8.48.0"
|
||||
"typescript-eslint": "^8.50.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { DynamicDialogRef, DynamicDialogConfig } from 'primeng/dynamicdialog';
|
||||
import { Select } from 'primeng/select';
|
||||
@@ -29,14 +29,13 @@ interface UploadingFile {
|
||||
selector: 'app-additional-file-uploader',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
Select,
|
||||
Button,
|
||||
FileUpload,
|
||||
Badge,
|
||||
Tooltip
|
||||
],
|
||||
],
|
||||
templateUrl: './additional-file-uploader.component.html',
|
||||
styleUrls: ['./additional-file-uploader.component.scss']
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, DestroyRef, inject, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
|
||||
import {BookReview, BookReviewService} from './book-review-service';
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
@@ -16,7 +16,7 @@ import {AppSettingsService} from '../../../../shared/service/app-settings.servic
|
||||
@Component({
|
||||
selector: 'app-book-reviews',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ProgressSpinner, Rating, Tag, Button, FormsModule, Tooltip],
|
||||
imports: [ProgressSpinner, Rating, Tag, Button, FormsModule, Tooltip],
|
||||
templateUrl: './book-reviews.component.html',
|
||||
styleUrl: './book-reviews.component.scss'
|
||||
})
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
@if (filteredBooks$ | async; as books) {
|
||||
<div class="rounded-xl overflow-hidden border-[1px] border-solid border-[var(--p-content-border-color)]">
|
||||
<p-tabs [value]="tab" lazy="true" scrollable>
|
||||
<p-tablist>
|
||||
<p-tab value="view">
|
||||
<i [class]="'pi pi-crown'"></i>
|
||||
Series Details
|
||||
</p-tab>
|
||||
</p-tablist>
|
||||
<p-tabpanels class="tabpanels-responsive overflow-auto">
|
||||
<p-tabpanel value="view">
|
||||
<div class="rounded-xl overflow-hidden border-[1px] border-solid border-[var(--p-content-border-color)]">
|
||||
<p-tabs [value]="tab" lazy="true" scrollable>
|
||||
<p-tablist>
|
||||
<p-tab value="view">
|
||||
<i [class]="'pi pi-crown'"></i>
|
||||
Series Details
|
||||
</p-tab>
|
||||
</p-tablist>
|
||||
<p-tabpanels class="tabpanels-responsive overflow-auto">
|
||||
<p-tabpanel value="view">
|
||||
|
||||
@if (books[0]; as firstBook) {
|
||||
<div class="flex flex-col justify-between flex-grow">
|
||||
<div class="space-y-4 ">
|
||||
@if (books[0]; as firstBook) {
|
||||
<div class="flex flex-col justify-between flex-grow">
|
||||
<div class="space-y-4 ">
|
||||
|
||||
<!-- <div class="flex items-start justify-between"> -->
|
||||
<div class="flex flex-col text-center gap-4 md:text-left w-full">
|
||||
<!-- <div class="flex items-start justify-between"> -->
|
||||
<div class="flex flex-col text-center gap-4 md:text-left w-full">
|
||||
|
||||
<div class="flex flex-col items-center md:items-start gap-1">
|
||||
<div class="flex items-center gap-2 justify-center md:justify-start flex-wrap text-center md:text-left">
|
||||
<h2 class="text-2xl md:text-3xl font-extrabold leading-tight">
|
||||
{{ seriesTitle$ | async }}
|
||||
</h2>
|
||||
<div class="flex flex-col items-center md:items-start gap-1">
|
||||
<div class="flex items-center gap-2 justify-center md:justify-start flex-wrap text-center md:text-left">
|
||||
<h2 class="text-2xl md:text-3xl font-extrabold leading-tight">
|
||||
{{ seriesTitle$ | async }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<p class="text-lg">
|
||||
@for (author of firstBook.metadata?.authors; track $index; let isLast = $last) {
|
||||
<a class="hover:underline dark:text-blue-400 cursor-pointer" (click)="goToAuthorBooks(author)">
|
||||
{{ author }}
|
||||
</a>
|
||||
@if (!isLast) {
|
||||
<span>, </span>
|
||||
}
|
||||
}
|
||||
</p>
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
<p class="text-lg">
|
||||
@for (author of firstBook.metadata?.authors; track $index; let isLast = $last) {
|
||||
<a class="hover:underline dark:text-blue-400 cursor-pointer" (click)="goToAuthorBooks(author)">
|
||||
{{ author }}
|
||||
</a>
|
||||
@if (!isLast) {
|
||||
<span>, </span>
|
||||
}
|
||||
}
|
||||
</p>
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
@if (firstBook.metadata?.categories?.length) {
|
||||
<div class="overflow-x-auto scrollbar-hide max-w-7xl pt-2 md:pt-0">
|
||||
<div class="flex gap-2 w-max max-w-[1150px]">
|
||||
@for (category of firstBook.metadata?.categories; track category) {
|
||||
<a (click)="goToCategory(category)" class="shrink-0 no-underline cursor-pointer">
|
||||
<p-tag [value]="category"></p-tag>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="px-1 md:px-0">
|
||||
<div
|
||||
class="grid md:grid-cols-5 p-3 gap-y-2.5 text-sm pt-2 md:pt-4 pb-2 text-gray-300 md:min-w-[60rem] md:max-w-[100rem]">
|
||||
<p>
|
||||
<span class="font-bold">Publisher: </span>
|
||||
@if (firstBook.metadata?.publisher; as publisher) {
|
||||
<span class="underline hover:opacity-80 cursor-pointer" (click)="goToPublisher(publisher)">
|
||||
{{publisher}}
|
||||
</span>
|
||||
} @else {
|
||||
<span>-</span>
|
||||
}
|
||||
</p>
|
||||
<p><strong>Years:</strong> {{ (yearsRange$ | async) || '-' }}</p>
|
||||
<p><strong>Number of books:</strong> {{ books.length || 0}}</p>
|
||||
<p><strong>Language:</strong> {{ firstBook.metadata?.language || "-"}}</p>
|
||||
<p><strong>Read Status: </strong>
|
||||
@if (firstBook.metadata?.categories?.length) {
|
||||
<div class="overflow-x-auto scrollbar-hide max-w-7xl pt-2 md:pt-0">
|
||||
<div class="flex gap-2 w-max max-w-[1150px]">
|
||||
@for (category of firstBook.metadata?.categories; track category) {
|
||||
<a (click)="goToCategory(category)" class="shrink-0 no-underline cursor-pointer">
|
||||
<p-tag [value]="category"></p-tag>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="px-1 md:px-0">
|
||||
<div
|
||||
class="grid md:grid-cols-5 p-3 gap-y-2.5 text-sm pt-2 md:pt-4 pb-2 text-gray-300 md:min-w-[60rem] md:max-w-[100rem]">
|
||||
<p>
|
||||
<span class="font-bold">Publisher: </span>
|
||||
@if (firstBook.metadata?.publisher; as publisher) {
|
||||
<span class="underline hover:opacity-80 cursor-pointer" (click)="goToPublisher(publisher)">
|
||||
{{publisher}}
|
||||
</span>
|
||||
} @else {
|
||||
<span>-</span>
|
||||
}
|
||||
</p>
|
||||
<p><strong>Years:</strong> {{ (yearsRange$ | async) || '-' }}</p>
|
||||
<p><strong>Number of books:</strong> {{ books.length || 0}}</p>
|
||||
<p><strong>Language:</strong> {{ firstBook.metadata?.language || "-"}}</p>
|
||||
<p><strong>Read Status: </strong>
|
||||
@let s = seriesReadStatus$ | async;
|
||||
<span class="inline-block px-2 py-0.5 rounded-full text-xs font-bold text-white"
|
||||
[ngClass]="getStatusSeverityClass(s || 'UNREAD')">
|
||||
{{ getStatusLabel(s) }}
|
||||
@if (s === 'PARTIALLY_READ') {
|
||||
({{ seriesReadProgress$ | async }})
|
||||
}
|
||||
({{ seriesReadProgress$ | async }})
|
||||
}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -82,45 +82,49 @@
|
||||
<div [ngClass]="{ 'line-clamp-5': !isExpanded, 'line-clamp-none': isExpanded }"
|
||||
class="transition-all duration-300 overflow-hidden description-container">
|
||||
<div class="readonly-editor px-2"
|
||||
[innerHTML]="(firstDescription$ | async) || 'No description available.'"></div>
|
||||
[innerHTML]="(firstDescription$ | async) || 'No description available.'"></div>
|
||||
</div>
|
||||
@let desc = firstDescription$ | async;
|
||||
@if ((desc?.length ?? 0) > 500) {
|
||||
<p-button [label]="isExpanded ? 'Show less' : 'Show more'"
|
||||
[icon]="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'" iconPos="right" size="small" text
|
||||
(click)="toggleExpand()">
|
||||
</p-button>
|
||||
<p-button [label]="isExpanded ? 'Show less' : 'Show more'"
|
||||
[icon]="isExpanded ? 'pi pi-chevron-up' : 'pi pi-chevron-down'" iconPos="right" size="small" text
|
||||
(click)="toggleExpand()">
|
||||
</p-button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="grid series-items-grid overflow-y-auto" #Container
|
||||
[ngStyle]="{'grid-template-columns': 'repeat(auto-fill, minmax(' + gridColumnMinWidth + ', 1fr))'}">
|
||||
<div class="grid-item" *ngFor="let book of books; let i = index"
|
||||
[ngStyle]="{width: currentCardSize.width + 'px', height: currentCardSize.height + 'px'}">
|
||||
<app-book-card [index]="i" [book]="book" [isCheckboxEnabled]="false" [isSelected]="false"
|
||||
[isSeriesCollapsed]="false">
|
||||
</app-book-card>
|
||||
</div>
|
||||
<div *ngIf="books.length === 0" class="empty-state">No books found for this series.</div>
|
||||
@for (book of books; track book; let i = $index) {
|
||||
<div class="grid-item"
|
||||
[ngStyle]="{width: currentCardSize.width + 'px', height: currentCardSize.height + 'px'}">
|
||||
<app-book-card [index]="i" [book]="book" [isCheckboxEnabled]="false" [isSelected]="false"
|
||||
[isSeriesCollapsed]="false">
|
||||
</app-book-card>
|
||||
</div>
|
||||
}
|
||||
@if (books.length === 0) {
|
||||
<div class="empty-state">No books found for this series.</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
</p-tabpanel>
|
||||
</p-tabpanels>
|
||||
</p-tabs>
|
||||
</p-tabpanel>
|
||||
</p-tabpanels>
|
||||
</p-tabs>
|
||||
</div>
|
||||
|
||||
} @else {
|
||||
<div class="flex flex-col justify-center items-center h-full gap-4">
|
||||
<p-progressSpinner strokeWidth="4" fill="transparent" animationDuration=".8s">
|
||||
</p-progressSpinner>
|
||||
<p style="color: var(--primary-color);">
|
||||
Loading series details...
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center items-center h-full gap-4">
|
||||
<p-progressSpinner strokeWidth="4" fill="transparent" animationDuration=".8s">
|
||||
</p-progressSpinner>
|
||||
<p style="color: var(--primary-color);">
|
||||
Loading series details...
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, inject, ViewChild } from "@angular/core";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
import { Button } from "primeng/button";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { AsyncPipe, NgClass, NgFor, NgIf, NgStyle } from "@angular/common";
|
||||
import { AsyncPipe, NgClass, NgStyle } from "@angular/common";
|
||||
import { map, filter, switchMap } from "rxjs/operators";
|
||||
import { Observable, combineLatest } from "rxjs";
|
||||
import { Book, ReadStatus } from "../../model/book.model";
|
||||
@@ -25,8 +25,6 @@ import { Router } from "@angular/router";
|
||||
AsyncPipe,
|
||||
Button,
|
||||
FormsModule,
|
||||
NgIf,
|
||||
NgFor,
|
||||
NgStyle,
|
||||
NgClass,
|
||||
BookCardComponent,
|
||||
@@ -37,9 +35,8 @@ import { Router } from "@angular/router";
|
||||
TabPanels,
|
||||
TabPanel,
|
||||
Tag,
|
||||
|
||||
VirtualScrollerModule,
|
||||
],
|
||||
VirtualScrollerModule
|
||||
],
|
||||
})
|
||||
export class SeriesPageComponent {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {FormBuilder, FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {Button} from 'primeng/button';
|
||||
import {Tooltip} from 'primeng/tooltip';
|
||||
@@ -18,7 +18,6 @@ import {filter, take} from "rxjs/operators";
|
||||
selector: 'app-bulk-metadata-update-component',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
InputText,
|
||||
@@ -28,7 +27,7 @@ import {filter, take} from "rxjs/operators";
|
||||
Checkbox,
|
||||
ProgressSpinner,
|
||||
AutoComplete
|
||||
],
|
||||
],
|
||||
providers: [MessageService],
|
||||
templateUrl: './bulk-metadata-update-component.html',
|
||||
styleUrl: './bulk-metadata-update-component.scss'
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<div class="comic-reader-container" tabindex="0">
|
||||
<div class="navigation">
|
||||
<div class="goto-page-controls">
|
||||
<button
|
||||
*ngIf="currentBook?.metadata?.seriesName"
|
||||
class="series-nav-button prev-book"
|
||||
(click)="navigateToPreviousBook()"
|
||||
[disabled]="!previousBookInSeries"
|
||||
[title]="getPreviousBookTooltip()">
|
||||
<span>← Previous Book</span>
|
||||
</button>
|
||||
@if (currentBook?.metadata?.seriesName) {
|
||||
<button
|
||||
class="series-nav-button prev-book"
|
||||
(click)="navigateToPreviousBook()"
|
||||
[disabled]="!previousBookInSeries"
|
||||
[title]="getPreviousBookTooltip()">
|
||||
<span>← Previous Book</span>
|
||||
</button>
|
||||
}
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
@@ -18,7 +19,7 @@
|
||||
[max]="pages.length"
|
||||
placeholder="Page"
|
||||
class="page-input"
|
||||
/>
|
||||
/>
|
||||
<button
|
||||
class="go-button"
|
||||
(click)="goToPageInput !== null && goToPage(goToPageInput)"
|
||||
@@ -27,14 +28,15 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
*ngIf="currentBook?.metadata?.seriesName"
|
||||
class="series-nav-button next-book"
|
||||
(click)="navigateToNextBook()"
|
||||
[disabled]="!nextBookInSeries"
|
||||
[title]="getNextBookTooltip()">
|
||||
<span>Next Book →</span>
|
||||
</button>
|
||||
@if (currentBook?.metadata?.seriesName) {
|
||||
<button
|
||||
class="series-nav-button next-book"
|
||||
(click)="navigateToNextBook()"
|
||||
[disabled]="!nextBookInSeries"
|
||||
[title]="getNextBookTooltip()">
|
||||
<span>Next Book →</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="page-controls">
|
||||
@@ -61,8 +63,8 @@
|
||||
<div class="desktop-controls">
|
||||
<div class="fit-mode-dropdown">
|
||||
<button class="view-button fit-mode-toggle"
|
||||
(click)="toggleFitModeDropdown()"
|
||||
title="Fit Mode">
|
||||
(click)="toggleFitModeDropdown()"
|
||||
title="Fit Mode">
|
||||
<span>{{ displayLabel }}</span>
|
||||
</button>
|
||||
@if (showFitModeDropdown) {
|
||||
@@ -99,22 +101,22 @@
|
||||
|
||||
<div class="mobile-controls">
|
||||
<button class="view-button more-options-toggle"
|
||||
(click)="toggleMobileOptionsDropdown()"
|
||||
title="More Options">
|
||||
(click)="toggleMobileOptionsDropdown()"
|
||||
title="More Options">
|
||||
<span>⋮</span>
|
||||
</button>
|
||||
@if (showMobileOptionsDropdown) {
|
||||
<div class="mobile-options-menu">
|
||||
@if (currentBook?.metadata?.seriesName) {
|
||||
<button
|
||||
class="mobile-option"
|
||||
<button
|
||||
class="mobile-option"
|
||||
(click)="navigateToPreviousBook(); toggleMobileOptionsDropdown()"
|
||||
[disabled]="!previousBookInSeries">
|
||||
<span class="option-icon">⬅️</span>
|
||||
<span class="option-label">Previous Book</span>
|
||||
</button>
|
||||
<button
|
||||
class="mobile-option"
|
||||
<button
|
||||
class="mobile-option"
|
||||
(click)="navigateToNextBook(); toggleMobileOptionsDropdown()"
|
||||
[disabled]="!nextBookInSeries">
|
||||
<span class="option-icon">➡️</span>
|
||||
@@ -165,17 +167,17 @@
|
||||
</div>
|
||||
|
||||
<div class="image-container"
|
||||
[class.two-page-view]="isTwoPageView && scrollMode === CbxScrollMode.PAGINATED"
|
||||
[class.infinite-scroll]="scrollMode === CbxScrollMode.INFINITE"
|
||||
[class.fit-actual-size]="fitMode === CbxFitMode.ACTUAL_SIZE"
|
||||
[class.fit-page]="fitMode === CbxFitMode.FIT_PAGE"
|
||||
[class.fit-width]="fitMode === CbxFitMode.FIT_WIDTH"
|
||||
[class.fit-height]="fitMode === CbxFitMode.FIT_HEIGHT"
|
||||
[class.fit-auto]="fitMode === CbxFitMode.AUTO"
|
||||
[class.bg-black]="backgroundColor === CbxBackgroundColor.BLACK"
|
||||
[class.bg-gray]="backgroundColor === CbxBackgroundColor.GRAY"
|
||||
[class.bg-white]="backgroundColor === CbxBackgroundColor.WHITE"
|
||||
(scroll)="onScroll($event)">
|
||||
[class.two-page-view]="isTwoPageView && scrollMode === CbxScrollMode.PAGINATED"
|
||||
[class.infinite-scroll]="scrollMode === CbxScrollMode.INFINITE"
|
||||
[class.fit-actual-size]="fitMode === CbxFitMode.ACTUAL_SIZE"
|
||||
[class.fit-page]="fitMode === CbxFitMode.FIT_PAGE"
|
||||
[class.fit-width]="fitMode === CbxFitMode.FIT_WIDTH"
|
||||
[class.fit-height]="fitMode === CbxFitMode.FIT_HEIGHT"
|
||||
[class.fit-auto]="fitMode === CbxFitMode.AUTO"
|
||||
[class.bg-black]="backgroundColor === CbxBackgroundColor.BLACK"
|
||||
[class.bg-gray]="backgroundColor === CbxBackgroundColor.GRAY"
|
||||
[class.bg-white]="backgroundColor === CbxBackgroundColor.WHITE"
|
||||
(scroll)="onScroll($event)">
|
||||
@if (!isLoading) {
|
||||
@if (pages.length > 0) {
|
||||
@if (scrollMode === CbxScrollMode.PAGINATED) {
|
||||
|
||||
@@ -21,12 +21,12 @@ import {BookState} from '../../book/model/state/book-state.model';
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {NewPdfReaderService} from '../../book/service/new-pdf-reader.service';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-cbx-reader',
|
||||
standalone: true,
|
||||
imports: [ProgressSpinner, FormsModule, NgIf],
|
||||
imports: [ProgressSpinner, FormsModule],
|
||||
templateUrl: './cbx-reader.component.html',
|
||||
styleUrl: './cbx-reader.component.scss'
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, inject, OnDestroy, OnInit} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {ToggleSwitch} from 'primeng/toggleswitch';
|
||||
@@ -16,14 +16,13 @@ import {ExternalDocLinkComponent} from '../../../../../shared/components/externa
|
||||
standalone: true,
|
||||
selector: 'app-koreader-settings-component',
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
InputText,
|
||||
ToggleSwitch,
|
||||
Button,
|
||||
ToastModule,
|
||||
ExternalDocLinkComponent
|
||||
],
|
||||
],
|
||||
providers: [MessageService],
|
||||
templateUrl: './koreader-settings-component.html',
|
||||
styleUrls: ['./koreader-settings-component.scss']
|
||||
|
||||
@@ -8,19 +8,18 @@ import {ExternalDocLinkComponent} from '../../../shared/components/external-doc-
|
||||
import {UserService} from '../user-management/user.service';
|
||||
import {Subject} from 'rxjs';
|
||||
import {filter, takeUntil, tap} from 'rxjs/operators';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-email-v2',
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
TableModule,
|
||||
Divider,
|
||||
EmailV2ProviderComponent,
|
||||
EmailV2RecipientComponent,
|
||||
ExternalDocLinkComponent
|
||||
],
|
||||
],
|
||||
templateUrl: './email-v2.component.html',
|
||||
styleUrls: ['./email-v2.component.scss'],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, inject, OnDestroy, OnInit} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {Button} from 'primeng/button';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {API_CONFIG} from '../../../core/config/api-config';
|
||||
@@ -23,7 +23,6 @@ import {Select} from 'primeng/select';
|
||||
@Component({
|
||||
selector: 'app-opds-settings',
|
||||
imports: [
|
||||
CommonModule,
|
||||
Button,
|
||||
InputText,
|
||||
Tooltip,
|
||||
@@ -35,7 +34,7 @@ import {Select} from 'primeng/select';
|
||||
ToggleSwitch,
|
||||
ExternalDocLinkComponent,
|
||||
Select
|
||||
],
|
||||
],
|
||||
providers: [ConfirmationService],
|
||||
templateUrl: './opds-settings.html',
|
||||
styleUrl: './opds-settings.scss'
|
||||
|
||||
@@ -3,7 +3,7 @@ import {DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {UtilityService} from './utility.service';
|
||||
import {TableModule} from 'primeng/table';
|
||||
import {InputText} from 'primeng/inputtext';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {ProgressSpinner} from 'primeng/progressspinner';
|
||||
import {MenuItem} from 'primeng/api';
|
||||
@@ -20,7 +20,6 @@ import {Tooltip} from 'primeng/tooltip';
|
||||
imports: [
|
||||
TableModule,
|
||||
InputText,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ProgressSpinner,
|
||||
CheckboxModule,
|
||||
@@ -29,7 +28,7 @@ import {Tooltip} from 'primeng/tooltip';
|
||||
InputIcon,
|
||||
IconField,
|
||||
Tooltip
|
||||
],
|
||||
],
|
||||
styleUrls: ['./directory-picker.component.scss']
|
||||
})
|
||||
export class DirectoryPickerComponent implements OnInit {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, inject, ChangeDetectionStrategy, ChangeDetectorRef, OnDestroy} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {DialogModule} from 'primeng/dialog';
|
||||
import {ButtonModule} from 'primeng/button';
|
||||
import {Subscription} from 'rxjs';
|
||||
@@ -8,7 +8,7 @@ import {DownloadProgress, DownloadProgressService} from '../../service/download-
|
||||
@Component({
|
||||
selector: 'app-download-progress-dialog',
|
||||
standalone: true,
|
||||
imports: [CommonModule, DialogModule, ButtonModule],
|
||||
imports: [DialogModule, ButtonModule],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
templateUrl: './download-progress-dialog.component.html',
|
||||
styleUrl: './download-progress-dialog.component.scss'
|
||||
|
||||
@@ -2,7 +2,7 @@ import {Component, inject} from '@angular/core';
|
||||
import {NotificationEventService} from '../../websocket/notification-event.service';
|
||||
import {LogNotification} from '../../websocket/model/log-notification.model';
|
||||
import {Tag} from 'primeng/tag';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
import {TagComponent} from '../tag/tag.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -14,7 +14,7 @@ import {routes} from './app/app.routes';
|
||||
import {AuthInterceptorService} from './app/core/security/auth-interceptor.service';
|
||||
import {AuthService, websocketInitializer} from './app/shared/service/auth.service';
|
||||
import {OAuthStorage, provideOAuthClient} from 'angular-oauth2-oidc';
|
||||
import {APP_INITIALIZER, provideAppInitializer} from '@angular/core';
|
||||
import {APP_INITIALIZER, provideAppInitializer, provideZoneChangeDetection} from '@angular/core';
|
||||
import {initializeAuthFactory} from './app/core/security/auth-initializer';
|
||||
|
||||
export function storageFactory(): OAuthStorage {
|
||||
@@ -27,7 +27,7 @@ import ChartDataLabels from 'chartjs-plugin-datalabels';
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
provideCharts(withDefaultRegisterables(), ChartDataLabels),
|
||||
provideZoneChangeDetection(),provideCharts(withDefaultRegisterables(), ChartDataLabels),
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: websocketInitializer,
|
||||
|
||||
Reference in New Issue
Block a user