diff --git a/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.css b/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.css index 21650b4..470dd50 100644 --- a/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.css +++ b/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.css @@ -30,7 +30,8 @@ padding: 20px; } -.results-error img, .results-end img { +.results-error img, +.results-end img { vertical-align: middle; } @@ -40,4 +41,32 @@ .filter-warning { filter: brightness(0) saturate(100%) invert(52%) sepia(95%) saturate(2039%) hue-rotate(3deg) brightness(106%) contrast(102%); +} + +.loading { + width: fit-content; + font-weight: bold; + font-family: monospace; + font-size: 25px; + align-self: center; + padding: 5px; + margin: 20px; + background: radial-gradient(circle closest-side, #000 94%, #0000) right/calc(200% - 1em) 100%; + animation: l24 1s infinite alternate linear; +} + +.loading::before { + content: "Loading..."; + line-height: 1em; + color: #0000; + background: inherit; + background-image: radial-gradient(circle closest-side, #fff 94%, #000); + -webkit-background-clip: text; + background-clip: text; +} + +@keyframes l24 { + 100% { + background-position: left + } } \ No newline at end of file diff --git a/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.html b/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.html index 903084c..8b44908 100644 --- a/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.html +++ b/frontend/angular-seshat/src/app/library/add-new-page/add-new-page.component.html @@ -1,21 +1,24 @@ -
- +
+
@for (result of results; track $index) { } + @if (busy()) { +
+ } @if (searchError() != null) { -

- error icon - {{searchError()}} -

- } +

+ error icon + {{searchError()}} +

+ } @if (endOfResults()) {
= {} as ElementRef; + search = new BehaviorSubject(''); filters = new BehaviorSubject(new SearchContextDto()); page = new BehaviorSubject(0); results: BookSearchResultDto[] = []; resultsPerPage = signal(10); + busy = signal(false); endOfResults = signal(false); searchError = signal(null); @@ -45,13 +44,14 @@ export class AddNewPageComponent implements OnDestroy { ), filters: this.filters, page: this.page.pipe( - throttleTime(1500, undefined, { leading: true, trailing: true }), + throttleTime(1500, undefined, { leading: false, trailing: true }), ), }).pipe( filter(entry => entry.search!.length > 1), - throttleTime(1000, undefined, { leading: false, trailing: true }), + debounceTime(1000), scan((acc, next) => { // New searches means resetting to page 0. + // Ignore if user is busy loading new pages. if (acc.search != next.search) { this.results = []; return { @@ -65,8 +65,10 @@ export class AddNewPageComponent implements OnDestroy { return acc; } - // Ignore further searching on the same search term. - if (this.endOfResults()) { + // Ignore further page searching if: + // - there are no more results; + // - user is still busy loading new pages. + if (this.endOfResults() || this.busy()) { return { ...next, page: -1, @@ -79,10 +81,12 @@ export class AddNewPageComponent implements OnDestroy { page: Math.min(acc.page + 1, next.page), }; }), - distinctUntilChanged(), filter(entry => entry.page >= 0), - tap(_ => this.endOfResults.set(false)), + distinctUntilChanged(), ).subscribe((entry) => { + this.busy.set(true); + this.endOfResults.set(false); + this.searchContentRef.nativeElement.scrollTop = 0; this._http.get('/api/providers/search', { params: { @@ -99,8 +103,10 @@ export class AddNewPageComponent implements OnDestroy { if (results.length < this.resultsPerPage()) { this.endOfResults.set(true); } + this.busy.set(false); }, error: (err) => { + this.busy.set(false); if (err instanceof HttpErrorResponse) { if (err.status == 400) { this.searchError.set('Something went wrong when Google received the request.'); @@ -128,7 +134,7 @@ export class AddNewPageComponent implements OnDestroy { const limit = scroll.scrollHeight - scroll.clientHeight; // Prevent page changes when: - // - new search is happening (emptying results); + // - new search is happening (emptied results); // - still scrolling through current content. if (scroll.scrollTop == 0 || scroll.scrollTop < limit - 25) { return;