chore: Loading placeholders (#2322)

* Improve visual of loading mask

* Normalize placeholder naming

* Remove unused file
This commit is contained in:
Tom Moor
2021-07-15 15:26:34 -04:00
committed by GitHub
parent 3f030540b3
commit 30cf244610
17 changed files with 70 additions and 100 deletions

View File

@ -15,7 +15,7 @@ import RevisionsStore from "stores/RevisionsStore";
import Button from "components/Button";
import Flex from "components/Flex";
import { ListPlaceholder } from "components/LoadingPlaceholder";
import PlaceholderList from "components/List/Placeholder";
import Revision from "./components/Revision";
import { documentHistoryUrl, documentUrl } from "utils/routeHelpers";
@ -120,7 +120,7 @@ class DocumentHistory extends React.Component<Props> {
</Header>
{showLoading ? (
<Loading>
<ListPlaceholder count={5} />
<PlaceholderList count={5} />
</Loading>
) : (
<ArrowKeyNavigation

View File

@ -45,7 +45,7 @@ const Container = styled.div`
align-items: ${({ align }) => align};
justify-content: ${({ justify }) => justify};
flex-shrink: ${({ shrink }) => (shrink ? 1 : "initial")};
gap: ${({ gap }) => `${gap}px` || "initial"};
gap: ${({ gap }) => (gap ? `${gap}px` : "initial")};
min-height: 0;
min-width: 0;
`;

View File

@ -4,18 +4,19 @@ import * as React from "react";
import styled from "styled-components";
import Fade from "components/Fade";
import Flex from "components/Flex";
import Mask from "components/Mask";
import PlaceholderText from "components/PlaceholderText";
type Props = {
count?: number,
};
const Placeholder = ({ count }: Props) => {
const ListPlaceHolder = ({ count }: Props) => {
return (
<Fade>
{times(count || 2, (index) => (
<Item key={index} column auto>
<Mask />
<PlaceholderText header delay={0.2 * index} />
<PlaceholderText delay={0.2 * index} />
</Item>
))}
</Fade>
@ -23,7 +24,7 @@ const Placeholder = ({ count }: Props) => {
};
const Item = styled(Flex)`
padding: 15px 0 16px;
padding: 10px 0;
`;
export default Placeholder;
export default ListPlaceHolder;

View File

@ -1,30 +0,0 @@
// @flow
import { times } from "lodash";
import * as React from "react";
import styled from "styled-components";
import Fade from "components/Fade";
import Flex from "components/Flex";
import Mask from "components/Mask";
type Props = {
count?: number,
};
const ListPlaceHolder = ({ count }: Props) => {
return (
<Fade>
{times(count || 2, (index) => (
<Item key={index} column auto>
<Mask header />
<Mask />
</Item>
))}
</Fade>
);
};
const Item = styled(Flex)`
padding: 10px 0;
`;
export default ListPlaceHolder;

View File

@ -1,6 +0,0 @@
// @flow
import ListPlaceholder from "./ListPlaceholder";
import LoadingPlaceholder from "./LoadingPlaceholder";
export default LoadingPlaceholder;
export { ListPlaceholder };

View File

@ -7,7 +7,7 @@ import * as React from "react";
import { Waypoint } from "react-waypoint";
import { DEFAULT_PAGINATION_LIMIT } from "stores/BaseStore";
import DelayedMount from "components/DelayedMount";
import { ListPlaceholder } from "components/LoadingPlaceholder";
import PlaceholderList from "components/List/Placeholder";
type Props = {
fetch?: (options: ?Object) => Promise<void>,
@ -128,7 +128,7 @@ class PaginatedList extends React.Component<Props> {
)}
{showLoading && (
<DelayedMount>
<ListPlaceholder count={5} />
<PlaceholderList count={5} />
</DelayedMount>
)}
</>

View File

@ -4,18 +4,19 @@ import styled from "styled-components";
import DelayedMount from "components/DelayedMount";
import Fade from "components/Fade";
import Flex from "components/Flex";
import Mask from "components/Mask";
import PlaceholderText from "components/PlaceholderText";
export default function LoadingPlaceholder(props: Object) {
export default function PlaceholderDocument(props: Object) {
return (
<DelayedMount>
<Wrapper>
<Flex column auto {...props}>
<Mask height={34} />
<PlaceholderText height={34} maxWidth={70} />
<PlaceholderText delay={0.2} maxWidth={40} />
<br />
<Mask />
<Mask />
<Mask />
<PlaceholderText delay={0.2} />
<PlaceholderText delay={0.4} />
<PlaceholderText delay={0.6} />
</Flex>
</Wrapper>
</DelayedMount>

View File

@ -10,36 +10,40 @@ type Props = {|
height?: number,
minWidth?: number,
maxWidth?: number,
delay?: number,
|};
class Mask extends React.Component<Props> {
width: number;
class PlaceholderText extends React.Component<Props> {
width = randomInteger(this.props.minWidth || 75, this.props.maxWidth || 100);
shouldComponentUpdate() {
return false;
}
constructor(props: Props) {
super();
this.width = randomInteger(props.minWidth || 75, props.maxWidth || 100);
}
render() {
return <Redacted width={this.width} height={this.props.height} />;
return (
<Mask
width={this.width}
height={this.props.height}
delay={this.props.delay}
/>
);
}
}
const Redacted = styled(Flex)`
const Mask = styled(Flex)`
width: ${(props) => (props.header ? props.width / 2 : props.width)}%;
height: ${(props) =>
props.height ? props.height : props.header ? 24 : 18}px;
margin-bottom: 6px;
border-radius: 6px;
background-color: ${(props) => props.theme.divider};
animation: ${pulsate} 1.3s infinite;
animation: ${pulsate} 2s infinite;
animation-delay: ${(props) => props.delay || 0}s;
&:last-child {
margin-bottom: 0;
}
`;
export default Mask;
export default PlaceholderText;

View File

@ -9,9 +9,9 @@ import Fade from "components/Fade";
import Flex from "components/Flex";
import useStores from "../../../hooks/useStores";
import CollectionLink from "./CollectionLink";
import CollectionsLoading from "./CollectionsLoading";
import DropCursor from "./DropCursor";
import Header from "./Header";
import PlaceholderCollections from "./PlaceholderCollections";
import SidebarLink from "./SidebarLink";
import useCurrentTeam from "hooks/useCurrentTeam";
type Props = {
@ -105,7 +105,7 @@ function Collections({ onCreateCollection }: Props) {
return (
<Flex column>
<Header>{t("Collections")}</Header>
<CollectionsLoading />
<PlaceholderCollections />
</Flex>
);
}

View File

@ -1,21 +0,0 @@
// @flow
import * as React from "react";
import styled from "styled-components";
import Mask from "components/Mask";
function CollectionsLoading() {
return (
<Wrapper>
<Mask />
<Mask />
<Mask />
</Wrapper>
);
}
const Wrapper = styled.div`
margin: 4px 16px;
width: 75%;
`;
export default CollectionsLoading;

View File

@ -0,0 +1,21 @@
// @flow
import * as React from "react";
import styled from "styled-components";
import PlaceholderText from "components/PlaceholderText";
function PlaceholderCollections() {
return (
<Wrapper>
<PlaceholderText />
<PlaceholderText delay={0.2} />
<PlaceholderText delay={0.4} />
</Wrapper>
);
}
const Wrapper = styled.div`
margin: 4px 16px;
width: 75%;
`;
export default PlaceholderCollections;

View File

@ -8,7 +8,7 @@ import styled from "styled-components";
import Button from "components/Button";
import Empty from "components/Empty";
import Flex from "components/Flex";
import Mask from "components/Mask";
import PlaceholderText from "components/PlaceholderText";
export type Props = {|
data: any[],
@ -170,7 +170,7 @@ export const Placeholder = ({
<Row key={row}>
{new Array(columns).fill().map((_, col) => (
<Cell key={col}>
<Mask minWidth={25} maxWidth={75} />
<PlaceholderText minWidth={25} maxWidth={75} />
</Cell>
))}
</Row>

View File

@ -14,7 +14,7 @@ import Trash from "scenes/Trash";
import CenteredContent from "components/CenteredContent";
import Layout from "components/Layout";
import LoadingPlaceholder from "components/LoadingPlaceholder";
import PlaceholderDocument from "components/PlaceholderDocument";
import Route from "components/ProfiledRoute";
import SocketProvider from "components/SocketProvider";
import { matchDocumentSlug as slug } from "utils/routeHelpers";
@ -43,7 +43,7 @@ export default function AuthenticatedRoutes() {
<React.Suspense
fallback={
<CenteredContent>
<LoadingPlaceholder />
<PlaceholderDocument />
</CenteredContent>
}
>

View File

@ -27,11 +27,11 @@ import Flex from "components/Flex";
import Heading from "components/Heading";
import HelpText from "components/HelpText";
import InputSearchPage from "components/InputSearchPage";
import PlaceholderList from "components/List/Placeholder";
import LoadingIndicator from "components/LoadingIndicator";
import { ListPlaceholder } from "components/LoadingPlaceholder";
import Mask from "components/Mask";
import Modal from "components/Modal";
import PaginatedDocumentList from "components/PaginatedDocumentList";
import PlaceholderText from "components/PlaceholderText";
import Scene from "components/Scene";
import Subheading from "components/Subheading";
import Tab from "components/Tab";
@ -376,9 +376,9 @@ function CollectionScene() {
) : (
<CenteredContent>
<Heading>
<Mask height={35} />
<PlaceholderText height={35} />
</Heading>
<ListPlaceholder count={5} />
<PlaceholderList count={5} />
</CenteredContent>
);
}

View File

@ -18,10 +18,10 @@ import Branding from "components/Branding";
import ErrorBoundary from "components/ErrorBoundary";
import Flex from "components/Flex";
import LoadingIndicator from "components/LoadingIndicator";
import LoadingPlaceholder from "components/LoadingPlaceholder";
import Modal from "components/Modal";
import Notice from "components/Notice";
import PageTitle from "components/PageTitle";
import PlaceholderDocument from "components/PlaceholderDocument";
import Time from "components/Time";
import Container from "./Container";
import Contents from "./Contents";
@ -410,7 +410,7 @@ class DocumentScene extends React.Component<Props> {
)}
</Notice>
)}
<React.Suspense fallback={<LoadingPlaceholder />}>
<React.Suspense fallback={<PlaceholderDocument />}>
<Flex auto={!readOnly}>
{showContents && <Contents headings={headings} />}
<Editor

View File

@ -2,8 +2,8 @@
import * as React from "react";
import { useTranslation } from "react-i18next";
import CenteredContent from "components/CenteredContent";
import LoadingPlaceholder from "components/LoadingPlaceholder";
import PageTitle from "components/PageTitle";
import PlaceholderDocument from "components/PlaceholderDocument";
import Container from "./Container";
import type { LocationWithState } from "types";
@ -20,7 +20,7 @@ export default function Loading({ location }: Props) {
title={location.state ? location.state.title : t("Untitled")}
/>
<CenteredContent>
<LoadingPlaceholder />
<PlaceholderDocument />
</CenteredContent>
</Container>
);

View File

@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
import { useHistory, useLocation, useRouteMatch } from "react-router-dom";
import CenteredContent from "components/CenteredContent";
import Flex from "components/Flex";
import LoadingPlaceholder from "components/LoadingPlaceholder";
import PlaceholderDocument from "components/PlaceholderDocument";
import useStores from "hooks/useStores";
import { editDocumentUrl } from "utils/routeHelpers";
@ -48,7 +48,7 @@ function DocumentNew() {
return (
<Flex column auto>
<CenteredContent>
<LoadingPlaceholder />
<PlaceholderDocument />
</CenteredContent>
</Flex>
);