ClaimList: add default page-load indicator | Apply for Search and Following-Manage
Clients can still choose to roll their own way of showing "is fetching", like how ClaimListDiscover displays a whole bunch of placeholder tiles. This just serves as a default.
This commit is contained in:
parent
06f7cdbe25
commit
f839e0c35d
4 changed files with 21 additions and 1 deletions
|
@ -25,6 +25,7 @@ type Props = {
|
||||||
header: Node | boolean,
|
header: Node | boolean,
|
||||||
headerAltControls: Node,
|
headerAltControls: Node,
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
|
useLoadingSpinner?: boolean, // use built-in spinner when 'loading' is true. Else, roll your own at client-side.
|
||||||
type: string,
|
type: string,
|
||||||
activeUri?: string,
|
activeUri?: string,
|
||||||
empty?: string,
|
empty?: string,
|
||||||
|
@ -65,6 +66,7 @@ export default function ClaimList(props: Props) {
|
||||||
prefixUris,
|
prefixUris,
|
||||||
headerAltControls,
|
headerAltControls,
|
||||||
loading,
|
loading,
|
||||||
|
useLoadingSpinner,
|
||||||
persistedStorageKey,
|
persistedStorageKey,
|
||||||
empty,
|
empty,
|
||||||
defaultSort,
|
defaultSort,
|
||||||
|
@ -200,6 +202,7 @@ export default function ClaimList(props: Props) {
|
||||||
swipeLayout={swipeLayout}
|
swipeLayout={swipeLayout}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
{loading && useLoadingSpinner && <ClaimPreviewTile placeholder="loading" swipeLayout={swipeLayout} />}
|
||||||
{!timedOut && urisLength === 0 && !loading && <div className="empty main--empty">{empty || noResultMsg}</div>}
|
{!timedOut && urisLength === 0 && !loading && <div className="empty main--empty">{empty || noResultMsg}</div>}
|
||||||
{timedOut && timedOutMessage && <div className="empty main--empty">{timedOutMessage}</div>}
|
{timedOut && timedOutMessage && <div className="empty main--empty">{timedOutMessage}</div>}
|
||||||
</section>
|
</section>
|
||||||
|
@ -289,6 +292,11 @@ export default function ClaimList(props: Props) {
|
||||||
|
|
||||||
{!timedOut && urisLength === 0 && !loading && <div className="empty empty--centered">{empty || noResultMsg}</div>}
|
{!timedOut && urisLength === 0 && !loading && <div className="empty empty--centered">{empty || noResultMsg}</div>}
|
||||||
{!loading && timedOut && timedOutMessage && <div className="empty empty--centered">{timedOutMessage}</div>}
|
{!loading && timedOut && timedOutMessage && <div className="empty empty--centered">{timedOutMessage}</div>}
|
||||||
|
{loading && useLoadingSpinner && (
|
||||||
|
<div className="spinnerArea--centered">
|
||||||
|
<Spinner type="small" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ export default function ChannelsFollowingManage(props: Props) {
|
||||||
// Infinite-scroll handling. 'page' is 0-indexed.
|
// Infinite-scroll handling. 'page' is 0-indexed.
|
||||||
const [page, setPage] = React.useState(-1);
|
const [page, setPage] = React.useState(-1);
|
||||||
const lastPage = Math.max(0, Math.ceil(uris.length / FOLLOW_PAGE_SIZE) - 1);
|
const lastPage = Math.max(0, Math.ceil(uris.length / FOLLOW_PAGE_SIZE) - 1);
|
||||||
|
const [loadingPage, setLoadingPage] = React.useState(false);
|
||||||
|
|
||||||
async function resolveUris(uris) {
|
async function resolveUris(uris) {
|
||||||
return doResolveUris(uris, true, false);
|
return doResolveUris(uris, true, false);
|
||||||
|
@ -52,7 +53,11 @@ export default function ChannelsFollowingManage(props: Props) {
|
||||||
|
|
||||||
function bumpPage() {
|
function bumpPage() {
|
||||||
if (page < lastPage) {
|
if (page < lastPage) {
|
||||||
resolveNextPage(uris, page).finally(() => setPage(page + 1));
|
setLoadingPage(true);
|
||||||
|
resolveNextPage(uris, page).finally(() => {
|
||||||
|
setLoadingPage(false);
|
||||||
|
setPage(page + 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +101,8 @@ export default function ChannelsFollowingManage(props: Props) {
|
||||||
onScrollBottom={bumpPage}
|
onScrollBottom={bumpPage}
|
||||||
page={page + 1}
|
page={page + 1}
|
||||||
pageSize={FOLLOW_PAGE_SIZE}
|
pageSize={FOLLOW_PAGE_SIZE}
|
||||||
|
loading={loadingPage}
|
||||||
|
useLoadingSpinner
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -90,6 +90,7 @@ export default function SearchPage(props: Props) {
|
||||||
<ClaimList
|
<ClaimList
|
||||||
uris={uris}
|
uris={uris}
|
||||||
loading={isSearching}
|
loading={isSearching}
|
||||||
|
useLoadingSpinner
|
||||||
onScrollBottom={loadMore}
|
onScrollBottom={loadMore}
|
||||||
// 'page' is 1-indexed; It's not the same as 'from', but it just
|
// 'page' is 1-indexed; It's not the same as 'from', but it just
|
||||||
// needs to be unique to indicate when a fetch is needed.
|
// needs to be unique to indicate when a fetch is needed.
|
||||||
|
|
|
@ -52,3 +52,7 @@
|
||||||
width: 3px;
|
width: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinnerArea--centered {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue