chore: Loading placeholders (#2322)
* Improve visual of loading mask * Normalize placeholder naming * Remove unused file
This commit is contained in:
@ -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
|
||||
|
@ -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;
|
||||
`;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -1,6 +0,0 @@
|
||||
// @flow
|
||||
import ListPlaceholder from "./ListPlaceholder";
|
||||
import LoadingPlaceholder from "./LoadingPlaceholder";
|
||||
|
||||
export default LoadingPlaceholder;
|
||||
export { ListPlaceholder };
|
@ -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>
|
||||
)}
|
||||
</>
|
||||
|
@ -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>
|
@ -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;
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
21
app/components/Sidebar/components/PlaceholderCollections.js
Normal file
21
app/components/Sidebar/components/PlaceholderCollections.js
Normal 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;
|
@ -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>
|
||||
|
@ -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>
|
||||
}
|
||||
>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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>
|
||||
);
|
||||
|
Reference in New Issue
Block a user