From 22b21c030f427f08a3ce040021ce6f16b75379fa Mon Sep 17 00:00:00 2001
From: Paul <paulmakles@gmail.com>
Date: Tue, 22 Jun 2021 16:29:47 +0100
Subject: [PATCH] Add animations to loaders.

---
 .../common/messaging/attachments/TextFile.tsx |   2 +-
 src/components/ui/Preloader.tsx               | 104 +++++++++++++++++-
 .../intermediate/modals/Onboarding.tsx        |   2 +-
 .../intermediate/popovers/UserProfile.tsx     |   2 +-
 src/context/revoltjs/FileUploads.tsx          |   2 +-
 src/context/revoltjs/RequiresOnline.tsx       |   2 +-
 src/context/revoltjs/RevoltClient.tsx         |   2 +-
 src/pages/RevoltApp.tsx                       |   6 +-
 src/pages/app.tsx                             |   2 +-
 src/pages/channels/messaging/MessageArea.tsx  |   4 +-
 .../channels/messaging/MessageRenderer.tsx    |   4 +-
 src/pages/invite/Invite.tsx                   |   4 +-
 src/pages/login/forms/CaptchaBlock.tsx        |   2 +-
 src/pages/login/forms/Form.tsx                |   2 +-
 src/pages/settings/panes/Sessions.tsx         |   2 +-
 src/pages/settings/server/Invites.tsx         |   2 +-
 16 files changed, 123 insertions(+), 21 deletions(-)

diff --git a/src/components/common/messaging/attachments/TextFile.tsx b/src/components/common/messaging/attachments/TextFile.tsx
index 810a2f0..c01976f 100644
--- a/src/components/common/messaging/attachments/TextFile.tsx
+++ b/src/components/common/messaging/attachments/TextFile.tsx
@@ -49,7 +49,7 @@ export default function TextFile({ attachment }: Props) {
                 content ?
                     <pre><code>{ content }</code></pre>
                     : <RequiresOnline>
-                        <Preloader />
+                        <Preloader type="ring" />
                     </RequiresOnline>
             }
         </div>
diff --git a/src/components/ui/Preloader.tsx b/src/components/ui/Preloader.tsx
index 4f92146..7e3ec3f 100644
--- a/src/components/ui/Preloader.tsx
+++ b/src/components/ui/Preloader.tsx
@@ -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>
+    );
 }
diff --git a/src/context/intermediate/modals/Onboarding.tsx b/src/context/intermediate/modals/Onboarding.tsx
index 032aa5f..8f3894d 100644
--- a/src/context/intermediate/modals/Onboarding.tsx
+++ b/src/context/intermediate/modals/Onboarding.tsx
@@ -39,7 +39,7 @@ export function OnboardingModal({ onClose, callback }: Props) {
             </div>
             <div className={styles.form}>
                 {loading ? (
-                    <Preloader />
+                    <Preloader type="spinner" />
                 ) : (
                     <>
                         <p>
diff --git a/src/context/intermediate/popovers/UserProfile.tsx b/src/context/intermediate/popovers/UserProfile.tsx
index 2b37ee7..2bcddb3 100644
--- a/src/context/intermediate/popovers/UserProfile.tsx
+++ b/src/context/intermediate/popovers/UserProfile.tsx
@@ -309,7 +309,7 @@ export function UserProfile({ user_id, onClose, dummy, dummyProfile }: Props) {
                             )}
                         </div>
                     ) : (
-                        <Preloader />
+                        <Preloader type="ring" />
                     ))}
                 {tab === "groups" && (
                     <div className={styles.entries}>
diff --git a/src/context/revoltjs/FileUploads.tsx b/src/context/revoltjs/FileUploads.tsx
index df10fb4..4be51c1 100644
--- a/src/context/revoltjs/FileUploads.tsx
+++ b/src/context/revoltjs/FileUploads.tsx
@@ -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} />
diff --git a/src/context/revoltjs/RequiresOnline.tsx b/src/context/revoltjs/RequiresOnline.tsx
index 73b7f72..20779e5 100644
--- a/src/context/revoltjs/RequiresOnline.tsx
+++ b/src/context/revoltjs/RequiresOnline.tsx
@@ -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>
diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx
index 045b7f9..8718ef4 100644
--- a/src/context/revoltjs/RevoltClient.tsx
+++ b/src/context/revoltjs/RevoltClient.tsx
@@ -202,7 +202,7 @@ function Context({ auth, sync, children, dispatcher }: Props) {
     }, []);
 
     if (status === ClientStatus.LOADING) {
-        return <Preloader />;
+        return <Preloader type="spinner" />;
     }
 
     return (
diff --git a/src/pages/RevoltApp.tsx b/src/pages/RevoltApp.tsx
index 53400ce..ad93f0c 100644
--- a/src/pages/RevoltApp.tsx
+++ b/src/pages/RevoltApp.tsx
@@ -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,
diff --git a/src/pages/app.tsx b/src/pages/app.tsx
index c6af90a..d77f32e 100644
--- a/src/pages/app.tsx
+++ b/src/pages/app.tsx
@@ -12,7 +12,7 @@ export function App() {
         <Context>
             {/* 
             // @ts-expect-error */}
-            <Suspense fallback={<Preloader />}>
+            <Suspense fallback={<Preloader type="spinner" />}>
                 <Switch>
                     <Route path="/login">
                         <CheckAuth>
diff --git a/src/pages/channels/messaging/MessageArea.tsx b/src/pages/channels/messaging/MessageArea.tsx
index 6e60966..a178fab 100644
--- a/src/pages/channels/messaging/MessageArea.tsx
+++ b/src/pages/channels/messaging/MessageArea.tsx
@@ -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" && (
diff --git a/src/pages/channels/messaging/MessageRenderer.tsx b/src/pages/channels/messaging/MessageRenderer.tsx
index ab53edf..2c66582 100644
--- a/src/pages/channels/messaging/MessageRenderer.tsx
+++ b/src/pages/channels/messaging/MessageRenderer.tsx
@@ -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>
         );
     }
diff --git a/src/pages/invite/Invite.tsx b/src/pages/invite/Invite.tsx
index cb01eaf..831895d 100644
--- a/src/pages/invite/Invite.tsx
+++ b/src/pages/invite/Invite.tsx
@@ -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>
diff --git a/src/pages/login/forms/CaptchaBlock.tsx b/src/pages/login/forms/CaptchaBlock.tsx
index e55b098..f435f01 100644
--- a/src/pages/login/forms/CaptchaBlock.tsx
+++ b/src/pages/login/forms/CaptchaBlock.tsx
@@ -20,7 +20,7 @@ export function CaptchaBlock(props: CaptchaProps) {
     }, []);
 
     if (!client.configuration?.features.captcha.enabled)
-        return <Preloader />;
+        return <Preloader type="spinner" />;
 
     return (
         <div>
diff --git a/src/pages/login/forms/Form.tsx b/src/pages/login/forms/Form.tsx
index c3709b5..5d8911b 100644
--- a/src/pages/login/forms/Form.tsx
+++ b/src/pages/login/forms/Form.tsx
@@ -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}>
diff --git a/src/pages/settings/panes/Sessions.tsx b/src/pages/settings/panes/Sessions.tsx
index dff8026..e0501d7 100644
--- a/src/pages/settings/panes/Sessions.tsx
+++ b/src/pages/settings/panes/Sessions.tsx
@@ -55,7 +55,7 @@ export function Sessions() {
     if (typeof sessions === "undefined") {
         return (
             <div className={styles.loader}>
-                <Preloader />
+                <Preloader type="ring" />
             </div>
         );
     }
diff --git a/src/pages/settings/server/Invites.tsx b/src/pages/settings/server/Invites.tsx
index 42144a9..21e0337 100644
--- a/src/pages/settings/server/Invites.tsx
+++ b/src/pages/settings/server/Invites.tsx
@@ -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 => {
-- 
GitLab