Skip to content

Commit

Permalink
Add a loader in the author list
Browse files Browse the repository at this point in the history
Signed-off-by: Jay Wang <jay@zijie.wang>
  • Loading branch information
xiaohk committed Jul 12, 2024
1 parent d7170d8 commit ea67cff
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 15 deletions.
45 changes: 30 additions & 15 deletions src/components/author-list/author-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import iconPerson from '../../images/icon-person.svg?raw';
import componentCSS from './author-list.css?inline';

const AUTHORS_PER_PAGE = 100;
let authorDetailAPITimeout: number | null = null;

/**
* Author list element.
Expand All @@ -28,7 +29,6 @@ export class RecRecAuthorList extends LitElement {
authorDetails: SemanticAuthorDetail[] = [];

authorStartIndex = 0;
authorDetailAPIRetryID = 0;

//==========================================================================||
// Lifecycle Methods ||
Expand Down Expand Up @@ -81,35 +81,50 @@ export class RecRecAuthorList extends LitElement {
//==========================================================================||
// Private Helpers ||
//==========================================================================||
async updateAuthorDetails(retry?: number, retryID?: number) {
async updateAuthorDetails(retry = 3) {
if (this.authors.length === 0) {
this.authorDetails = [];
return;
}

const retryNum = retry || 3;
this.updateIsSearching(true);

// Quit if a newer query has succeeded
if (retryID && retryID != this.authorDetailAPIRetryID) {
return;
}

// Record this query as the newest query
if (retryID === undefined) {
this.authorDetailAPIRetryID += 1;
if (authorDetailAPITimeout !== null) {
clearTimeout(authorDetailAPITimeout);
}

try {
const data = await searchAuthorDetails(this.authors.map(d => d.authorId));
this.authorDetails = data;
this.updateIsSearching(false);
} catch (e) {
await new Promise<void>(resolve => {
setTimeout(resolve, 1000);
});
await this.updateAuthorDetails(retryNum - 1, this.authorDetailAPIRetryID);
// Try again after some delay
console.error(
`Author detail API failed with error (retry remain: ${retry}): ${e}`
);

if (retry > 0) {
authorDetailAPITimeout = setTimeout(() => {
this.updateAuthorDetails(retry - 1).then(
() => {},
() => {}
);
}, 1000);
} else {
this.updateIsSearching(false);
}
}
}

updateIsSearching(isSearching: boolean) {
const event = new CustomEvent<boolean>('is-searching-changed', {
bubbles: true,
composed: true,
detail: isSearching
});
this.dispatchEvent(event);
}

//==========================================================================||
// Templates and Styles ||
//==========================================================================||
Expand Down
31 changes: 31 additions & 0 deletions src/components/author-view/author-view.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,34 @@ button {
}
}
}

.loader {
--stroke: 2px;

width: 128px;
aspect-ratio: 1;
border-radius: 50%;

background:
radial-gradient(farthest-side, var(--blue-700) 94%, #0000) top/var(--stroke)
var(--stroke) no-repeat,
conic-gradient(#0000 30%, var(--blue-700));

-webkit-mask: radial-gradient(
farthest-side,
#0000 calc(100% - var(--stroke)),
#000 0
);
animation: rotation 1200ms infinite linear;

&[is-hidden] {
visibility: hidden;
pointer-events: none;
}
}

@keyframes rotation {
100% {
transform: rotate(1turn);
}
}
13 changes: 13 additions & 0 deletions src/components/author-view/author-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
SemanticAuthorSearch,
SemanticAuthorDetail
} from '../../types/common-types';
import type { RecRecAuthorList } from '../author-list/author-list';

import '@shoelace-style/shoelace/dist/components/input/input.js';
import '../header-bar/header-bar';
Expand Down Expand Up @@ -35,9 +36,15 @@ export class RecRecAuthorView extends LitElement {
@state()
showAuthorList = false;

@state()
isSearching = false;

@query('sl-input')
searchInputComponent: SlInput | undefined;

@query('recrec-author-list')
authorListComponent: RecRecAuthorList | undefined;

//==========================================================================||
// Lifecycle Methods ||
//==========================================================================||
Expand Down Expand Up @@ -177,6 +184,9 @@ export class RecRecAuthorView extends LitElement {
<div class="svg-icon search-icon" slot="prefix">
${unsafeHTML(iconSearch)}
</div>
<div class="svg-icon search-icon" slot="suffix">
<div class="loader" ?is-hidden=${!this.isSearching}></div>
</div>
</sl-input>
</div>
Expand All @@ -186,6 +196,9 @@ export class RecRecAuthorView extends LitElement {
@author-row-clicked=${(e: CustomEvent<SemanticAuthorDetail>) => {
this.authorRowClickedHandler(e);
}}
@is-searching-changed=${(e: CustomEvent<boolean>) => {
this.isSearching = e.detail;
}}
></recrec-author-list>
</div>
</div>
Expand Down

0 comments on commit ea67cff

Please sign in to comment.