mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-23 12:51:13 +00:00
Add loading screen for remote fetch and refactor loading ellipses
This commit is contained in:
parent
f580e2d8b7
commit
792c0e63a9
3 changed files with 63 additions and 28 deletions
34
src/shared/components/common/loading-ellipses.tsx
Normal file
34
src/shared/components/common/loading-ellipses.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { Component } from "inferno";
|
||||
|
||||
interface LoadingEllipsesState {
|
||||
ellipses: string;
|
||||
}
|
||||
|
||||
export class LoadingEllipses extends Component<any, LoadingEllipsesState> {
|
||||
state: LoadingEllipsesState = {
|
||||
ellipses: "...",
|
||||
};
|
||||
#interval?: NodeJS.Timer;
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.ellipses;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.#interval = setInterval(this.#updateEllipses, 1000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.#interval);
|
||||
}
|
||||
|
||||
#updateEllipses = () => {
|
||||
this.setState(({ ellipses }) => ({
|
||||
ellipses: ellipses.length === 3 ? "" : ellipses + ".",
|
||||
}));
|
||||
};
|
||||
}
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "inferno";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon, Spinner } from "./icon";
|
||||
import { LoadingEllipses } from "./loading-ellipses";
|
||||
|
||||
interface SearchableSelectProps {
|
||||
id: string;
|
||||
|
@ -22,7 +23,6 @@ interface SearchableSelectProps {
|
|||
interface SearchableSelectState {
|
||||
selectedIndex: number;
|
||||
searchText: string;
|
||||
loadingEllipses: string;
|
||||
}
|
||||
|
||||
function handleSearch(i: SearchableSelect, e: ChangeEvent<HTMLInputElement>) {
|
||||
|
@ -70,12 +70,10 @@ export class SearchableSelect extends Component<
|
|||
> {
|
||||
searchInputRef: RefObject<HTMLInputElement> = createRef();
|
||||
toggleButtonRef: RefObject<HTMLButtonElement> = createRef();
|
||||
private loadingEllipsesInterval?: NodeJS.Timer = undefined;
|
||||
|
||||
state: SearchableSelectState = {
|
||||
selectedIndex: 0,
|
||||
searchText: "",
|
||||
loadingEllipses: "...",
|
||||
};
|
||||
|
||||
constructor(props: SearchableSelectProps, context: any) {
|
||||
|
@ -99,7 +97,7 @@ export class SearchableSelect extends Component<
|
|||
|
||||
render() {
|
||||
const { id, options, onSearch, loading } = this.props;
|
||||
const { searchText, selectedIndex, loadingEllipses } = this.state;
|
||||
const { searchText, selectedIndex } = this.state;
|
||||
|
||||
return (
|
||||
<div className="searchable-select dropdown col-12 col-sm-auto flex-grow-1">
|
||||
|
@ -116,9 +114,14 @@ export class SearchableSelect extends Component<
|
|||
onClick={linkEvent(this, focusSearch)}
|
||||
ref={this.toggleButtonRef}
|
||||
>
|
||||
{loading
|
||||
? `${I18NextService.i18n.t("loading")}${loadingEllipses}`
|
||||
: options[selectedIndex].label}
|
||||
{loading ? (
|
||||
<>
|
||||
{I18NextService.i18n.t("loading")}
|
||||
<LoadingEllipses />
|
||||
</>
|
||||
) : (
|
||||
options[selectedIndex].label
|
||||
)}
|
||||
</button>
|
||||
<div className="modlog-choices-font-size dropdown-menu w-100 p-2">
|
||||
<div className="input-group">
|
||||
|
@ -180,24 +183,4 @@ export class SearchableSelect extends Component<
|
|||
selectedIndex,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { loading } = this.props;
|
||||
if (loading && !this.loadingEllipsesInterval) {
|
||||
this.loadingEllipsesInterval = setInterval(() => {
|
||||
this.setState(({ loadingEllipses }) => ({
|
||||
loadingEllipses:
|
||||
loadingEllipses.length === 3 ? "" : loadingEllipses + ".",
|
||||
}));
|
||||
}, 750);
|
||||
} else if (!loading && this.loadingEllipsesInterval) {
|
||||
clearInterval(this.loadingEllipsesInterval);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.loadingEllipsesInterval) {
|
||||
clearInterval(this.loadingEllipsesInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import { InitialFetchRequest } from "../interfaces";
|
|||
import { FirstLoadService, HttpService, I18NextService } from "../services";
|
||||
import { RequestState } from "../services/HttpService";
|
||||
import { HtmlTags } from "./common/html-tags";
|
||||
import { Spinner } from "./common/icon";
|
||||
import { LoadingEllipses } from "./common/loading-ellipses";
|
||||
|
||||
interface RemoteFetchProps {
|
||||
uri?: string;
|
||||
|
@ -90,7 +92,9 @@ export class RemoteFetch extends Component<any, RemoteFetchState> {
|
|||
}
|
||||
|
||||
get content() {
|
||||
const status: "success" | "loading" | "empty" = "success";
|
||||
const status = "loading" as "success" | "loading" | "empty";
|
||||
|
||||
const { uri } = getRemoteFetchQueryParams();
|
||||
|
||||
switch (status) {
|
||||
case "success": {
|
||||
|
@ -103,6 +107,20 @@ export class RemoteFetch extends Component<any, RemoteFetchState> {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
case "loading": {
|
||||
return (
|
||||
<>
|
||||
<h1>
|
||||
Fetching {uri ? uriToQuery(uri) : "remote community"}
|
||||
<LoadingEllipses />
|
||||
</h1>
|
||||
<h5>
|
||||
<Spinner large />
|
||||
</h5>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue