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