mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-27 06:41:12 +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";
|
} from "inferno";
|
||||||
import { I18NextService } from "../../services";
|
import { I18NextService } from "../../services";
|
||||||
import { Icon, Spinner } from "./icon";
|
import { Icon, Spinner } from "./icon";
|
||||||
|
import { LoadingEllipses } from "./loading-ellipses";
|
||||||
|
|
||||||
interface SearchableSelectProps {
|
interface SearchableSelectProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -22,7 +23,6 @@ interface SearchableSelectProps {
|
||||||
interface SearchableSelectState {
|
interface SearchableSelectState {
|
||||||
selectedIndex: number;
|
selectedIndex: number;
|
||||||
searchText: string;
|
searchText: string;
|
||||||
loadingEllipses: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSearch(i: SearchableSelect, e: ChangeEvent<HTMLInputElement>) {
|
function handleSearch(i: SearchableSelect, e: ChangeEvent<HTMLInputElement>) {
|
||||||
|
@ -70,12 +70,10 @@ export class SearchableSelect extends Component<
|
||||||
> {
|
> {
|
||||||
searchInputRef: RefObject<HTMLInputElement> = createRef();
|
searchInputRef: RefObject<HTMLInputElement> = createRef();
|
||||||
toggleButtonRef: RefObject<HTMLButtonElement> = createRef();
|
toggleButtonRef: RefObject<HTMLButtonElement> = createRef();
|
||||||
private loadingEllipsesInterval?: NodeJS.Timer = undefined;
|
|
||||||
|
|
||||||
state: SearchableSelectState = {
|
state: SearchableSelectState = {
|
||||||
selectedIndex: 0,
|
selectedIndex: 0,
|
||||||
searchText: "",
|
searchText: "",
|
||||||
loadingEllipses: "...",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: SearchableSelectProps, context: any) {
|
constructor(props: SearchableSelectProps, context: any) {
|
||||||
|
@ -99,7 +97,7 @@ export class SearchableSelect extends Component<
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { id, options, onSearch, loading } = this.props;
|
const { id, options, onSearch, loading } = this.props;
|
||||||
const { searchText, selectedIndex, loadingEllipses } = this.state;
|
const { searchText, selectedIndex } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="searchable-select dropdown col-12 col-sm-auto flex-grow-1">
|
<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)}
|
onClick={linkEvent(this, focusSearch)}
|
||||||
ref={this.toggleButtonRef}
|
ref={this.toggleButtonRef}
|
||||||
>
|
>
|
||||||
{loading
|
{loading ? (
|
||||||
? `${I18NextService.i18n.t("loading")}${loadingEllipses}`
|
<>
|
||||||
: options[selectedIndex].label}
|
{I18NextService.i18n.t("loading")}
|
||||||
|
<LoadingEllipses />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
options[selectedIndex].label
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
<div className="modlog-choices-font-size dropdown-menu w-100 p-2">
|
<div className="modlog-choices-font-size dropdown-menu w-100 p-2">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
|
@ -180,24 +183,4 @@ export class SearchableSelect extends Component<
|
||||||
selectedIndex,
|
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 { FirstLoadService, HttpService, I18NextService } from "../services";
|
||||||
import { RequestState } from "../services/HttpService";
|
import { RequestState } from "../services/HttpService";
|
||||||
import { HtmlTags } from "./common/html-tags";
|
import { HtmlTags } from "./common/html-tags";
|
||||||
|
import { Spinner } from "./common/icon";
|
||||||
|
import { LoadingEllipses } from "./common/loading-ellipses";
|
||||||
|
|
||||||
interface RemoteFetchProps {
|
interface RemoteFetchProps {
|
||||||
uri?: string;
|
uri?: string;
|
||||||
|
@ -90,7 +92,9 @@ export class RemoteFetch extends Component<any, RemoteFetchState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get content() {
|
get content() {
|
||||||
const status: "success" | "loading" | "empty" = "success";
|
const status = "loading" as "success" | "loading" | "empty";
|
||||||
|
|
||||||
|
const { uri } = getRemoteFetchQueryParams();
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "success": {
|
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