Add animations to loaders.

This commit is contained in:
Paul 2021-06-22 16:29:47 +01:00
parent e98a962071
commit 22b21c030f
16 changed files with 123 additions and 21 deletions

View file

@ -49,7 +49,7 @@ export default function TextFile({ attachment }: Props) {
content ?
<pre><code>{ content }</code></pre>
: <RequiresOnline>
<Preloader />
<Preloader type="ring" />
</RequiresOnline>
}
</div>

View file

@ -1,3 +1,103 @@
export default function Preloader() {
return <span>LOADING</span>;
import styled, { keyframes } from "styled-components";
const skSpinner = keyframes`
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
`;
const prRing = keyframes`
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
`;
const PreloaderBase = styled.div`
width: 100%;
height: 100%;
display: grid;
place-items: center;
.spinner {
width: 58px;
display: flex;
text-align: center;
margin: 100px auto 0;
justify-content: space-between;
}
.spinner > div {
width: 14px;
height: 14px;
background-color: var(--tertiary-foreground);
border-radius: 100%;
display: inline-block;
animation: ${skSpinner} 1.4s infinite ease-in-out both;
}
.spinner div:nth-child(1) {
animation-delay: -0.32s;
}
.spinner div:nth-child(2) {
animation-delay: -0.16s;
}
.ring {
display: inline-block;
position: relative;
width: 48px;
height: 52px;
}
.ring div {
width: 32px;
margin: 8px;
height: 32px;
display: block;
position: absolute;
border-radius: 50%;
box-sizing: border-box;
border: 2px solid #fff;
animation: ${prRing} 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #fff transparent transparent transparent;
}
.ring div:nth-child(1) {
animation-delay: -0.45s;
}
.ring div:nth-child(2) {
animation-delay: -0.3s;
}
.ring div:nth-child(3) {
animation-delay: -0.15s;
}
`;
interface Props {
type: 'spinner' | 'ring'
}
export default function Preloader({ type }: Props) {
return (
<PreloaderBase>
<div class={type}>
<div />
<div />
<div />
</div>
</PreloaderBase>
);
}

View file

@ -39,7 +39,7 @@ export function OnboardingModal({ onClose, callback }: Props) {
</div>
<div className={styles.form}>
{loading ? (
<Preloader />
<Preloader type="spinner" />
) : (
<>
<p>

View file

@ -309,7 +309,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
)}
</div>
) : (
<Preloader />
<Preloader type="ring" />
))}
{tab === "groups" && (
<div className={styles.entries}>

View file

@ -187,7 +187,7 @@ export function FileUploader(props: Props) {
onClick={onClick}>
{ uploading ?
<div className={styles.uploading}>
<Preloader />
<Preloader type="ring" />
</div> :
<div className={styles.edit}>
<Edit size={30} />

View file

@ -29,7 +29,7 @@ const Base = styled.div`
export default function RequiresOnline(props: Props) {
const status = useContext(StatusContext);
if (status === ClientStatus.CONNECTING) return <Preloader />;
if (status === ClientStatus.CONNECTING) return <Preloader type="ring" />;
if (status !== ClientStatus.ONLINE && status !== ClientStatus.READY)
return (
<Base>

View file

@ -202,7 +202,7 @@ function Context({ auth, sync, children, dispatcher }: Props) {
}, []);
if (status === ClientStatus.LOADING) {
return <Preloader />;
return <Preloader type="spinner" />;
}
return (

View file

@ -34,13 +34,15 @@ const Routes = styled.div`
export default function App() {
const path = useLocation().pathname;
const fixedBottomNav = (path === '/' || path === '/settings' || path.startsWith("/friends"));
const inSettings = path === '/settings';
const inChannel = path.includes('/channel');
return (
<OverlappingPanels
width="100vw"
height="100vh"
leftPanel={{ width: 292, component: <LeftSidebar /> }}
rightPanel={{ width: 240, component: <RightSidebar /> }}
leftPanel={inSettings ? undefined : { width: 292, component: <LeftSidebar /> }}
rightPanel={(!inSettings && inChannel) ? { width: 240, component: <RightSidebar /> } : undefined}
bottomNav={{
component: <BottomNavigation />,
showIf: fixedBottomNav ? ShowIf.Always : ShowIf.Left,

View file

@ -12,7 +12,7 @@ export function App() {
<Context>
{/*
// @ts-expect-error */}
<Suspense fallback={<Preloader />}>
<Suspense fallback={<Preloader type="spinner" />}>
<Switch>
<Route path="/login">
<CheckAuth>

View file

@ -215,10 +215,10 @@ export function MessageArea({ id }: Props) {
<MessageAreaWidthContext.Provider value={(width ?? 0) - MESSAGE_AREA_PADDING}>
<Area ref={ref}>
<div>
{state.type === "LOADING" && <Preloader />}
{state.type === "LOADING" && <Preloader type="ring" />}
{state.type === "WAITING_FOR_NETWORK" && (
<RequiresOnline>
<Preloader />
<Preloader type="ring" />
</RequiresOnline>
)}
{state.type === "RENDER" && (

View file

@ -60,7 +60,7 @@ function MessageRenderer({ id, state, queue }: Props) {
} else {
render.push(
<RequiresOnline>
<Preloader />
<Preloader type="ring" />
</RequiresOnline>
);
}
@ -148,7 +148,7 @@ function MessageRenderer({ id, state, queue }: Props) {
} else {
render.push(
<RequiresOnline>
<Preloader />
<Preloader type="ring" />
</RequiresOnline>
);
}

View file

@ -34,7 +34,7 @@ export default function Invite() {
<div className={styles.preloader}>
<RequiresOnline>
{ error ? <Overline type="error" error={error} />
: <Preloader /> }
: <Preloader type="spinner" /> }
</RequiresOnline>
</div>
)
@ -52,7 +52,7 @@ export default function Invite() {
</div> }
<div className={styles.details}>
{ processing ? <Preloader /> :
{ processing ? <Preloader type="ring" /> :
<>
<h1>{ invite.server_name }</h1>
<h2>#{invite.channel_name}</h2>

View file

@ -20,7 +20,7 @@ export function CaptchaBlock(props: CaptchaProps) {
}, []);
if (!client.configuration?.features.captcha.enabled)
return <Preloader />;
return <Preloader type="spinner" />;
return (
<div>

View file

@ -138,7 +138,7 @@ export function Form({ page, callback }: Props) {
}
if (captcha) return <CaptchaBlock {...captcha} />;
if (loading) return <Preloader />;
if (loading) return <Preloader type="spinner" />;
return (
<div className={styles.form}>

View file

@ -55,7 +55,7 @@ export function Sessions() {
if (typeof sessions === "undefined") {
return (
<div className={styles.loader}>
<Preloader />
<Preloader type="ring" />
</div>
);
}

View file

@ -27,7 +27,7 @@ export function Invites({ server }: Props) {
return (
<div className={styles.invites}>
{ typeof invites === 'undefined' && <Preloader /> }
{ typeof invites === 'undefined' && <Preloader type="ring" /> }
{
invites?.map(
invite => {