feat: add animated preloader (#2464)
* feat: add animated preloader * feat: add animated preloader - add scss lines * feat: add animated preloader - add scss lines * feat: add animated preloader - ref scss lines * feat: add animated preloader - add preloader property to loader component
This commit is contained in:
parent
485c609791
commit
64aa39fe4b
2
.github/workflows/cypress-explorer-e2e.yml
vendored
2
.github/workflows/cypress-explorer-e2e.yml
vendored
@ -98,7 +98,7 @@ jobs:
|
|||||||
while read -r file; do
|
while read -r file; do
|
||||||
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
|
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
|
||||||
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
|
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
|
@ -8,8 +8,7 @@ import {
|
|||||||
Web3Provider as Web3ProviderInternal,
|
Web3Provider as Web3ProviderInternal,
|
||||||
useWeb3ConnectStore,
|
useWeb3ConnectStore,
|
||||||
} from '@vegaprotocol/web3';
|
} from '@vegaprotocol/web3';
|
||||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer, Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
|
||||||
|
|
||||||
interface AppLoaderProps {
|
interface AppLoaderProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -21,10 +20,7 @@ interface AppLoaderProps {
|
|||||||
*/
|
*/
|
||||||
export function AppLoader({ children }: AppLoaderProps) {
|
export function AppLoader({ children }: AppLoaderProps) {
|
||||||
return (
|
return (
|
||||||
<NetworkLoader
|
<NetworkLoader skeleton={<Loader />} cache={cacheConfig}>
|
||||||
skeleton={<Splash>{t('Loading...')}</Splash>}
|
|
||||||
cache={cacheConfig}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
);
|
);
|
||||||
|
22
apps/trading/components/preloader/preloader.tsx
Normal file
22
apps/trading/components/preloader/preloader.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Loader } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
export const Preloader = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
body{
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
<div className="pre-loader">
|
||||||
|
<Loader forceTheme="light" preloader />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Preloader;
|
@ -1,4 +1,5 @@
|
|||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
import dynamic from 'next/dynamic';
|
||||||
import type { AppProps } from 'next/app';
|
import type { AppProps } from 'next/app';
|
||||||
import { Navbar } from '../components/navbar';
|
import { Navbar } from '../components/navbar';
|
||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
@ -22,6 +23,7 @@ import {
|
|||||||
} from '@vegaprotocol/environment';
|
} from '@vegaprotocol/environment';
|
||||||
import { AppLoader, Web3Provider } from '../components/app-loader';
|
import { AppLoader, Web3Provider } from '../components/app-loader';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
import './gen-styles.scss';
|
||||||
import { usePageTitleStore } from '../stores';
|
import { usePageTitleStore } from '../stores';
|
||||||
import { Footer } from '../components/footer';
|
import { Footer } from '../components/footer';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
@ -67,7 +69,7 @@ function AppBody({ Component }: AppProps) {
|
|||||||
const { VEGA_ENV } = useEnvironment();
|
const { VEGA_ENV } = useEnvironment();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="h-full dark:bg-black dark:text-white">
|
||||||
<Head>
|
<Head>
|
||||||
{/* Cannot use meta tags in _document.page.tsx see https://nextjs.org/docs/messages/no-document-viewport-meta */}
|
{/* Cannot use meta tags in _document.page.tsx see https://nextjs.org/docs/messages/no-document-viewport-meta */}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
@ -76,7 +78,7 @@ function AppBody({ Component }: AppProps) {
|
|||||||
<VegaWalletProvider>
|
<VegaWalletProvider>
|
||||||
<AppLoader>
|
<AppLoader>
|
||||||
<Web3Provider>
|
<Web3Provider>
|
||||||
<div className="h-full relative dark:bg-black dark:text-white z-0 grid grid-rows-[min-content,1fr,min-content]">
|
<div className="h-full relative z-0 grid grid-rows-[min-content,1fr,min-content]">
|
||||||
<Navbar
|
<Navbar
|
||||||
navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'}
|
navbarTheme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'}
|
||||||
/>
|
/>
|
||||||
@ -92,10 +94,17 @@ function AppBody({ Component }: AppProps) {
|
|||||||
</Web3Provider>
|
</Web3Provider>
|
||||||
</AppLoader>
|
</AppLoader>
|
||||||
</VegaWalletProvider>
|
</VegaWalletProvider>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DynamicLoader = dynamic(
|
||||||
|
() => import('../components/preloader/preloader'),
|
||||||
|
{
|
||||||
|
loading: () => <>Loading...</>,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function VegaTradingApp(props: AppProps) {
|
function VegaTradingApp(props: AppProps) {
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
@ -106,7 +115,9 @@ function VegaTradingApp(props: AppProps) {
|
|||||||
setMounted(true);
|
setMounted(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!mounted) return null;
|
if (!mounted) {
|
||||||
|
return <DynamicLoader />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
|
50
apps/trading/pages/gen-styles.scss
Normal file
50
apps/trading/pages/gen-styles.scss
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
.pre-loader {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@for $i from 0 through 16 {
|
||||||
|
.loader-item:nth-child(#{$i}) {
|
||||||
|
@if $i % 2 == 0 {
|
||||||
|
animation-delay: #{$i * 50 * random(5)}ms;
|
||||||
|
animation-direction: reverse;
|
||||||
|
} @else {
|
||||||
|
animation-delay: #{$i * -50 * random(5)}ms;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pre-loader-center {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.pre-loader-wrapper {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.loader-item {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: black;
|
||||||
|
animation: flickering 0.4s steps(2, jump-none) alternate infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes flickering {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
26% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
@ -4,20 +4,27 @@ import { useEffect, useState } from 'react';
|
|||||||
export interface LoaderProps {
|
export interface LoaderProps {
|
||||||
size?: 'small' | 'large';
|
size?: 'small' | 'large';
|
||||||
forceTheme?: 'dark' | 'light';
|
forceTheme?: 'dark' | 'light';
|
||||||
|
preloader?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Loader = ({ size = 'large', forceTheme }: LoaderProps) => {
|
export const Loader = ({
|
||||||
|
size = 'large',
|
||||||
|
forceTheme,
|
||||||
|
preloader,
|
||||||
|
}: LoaderProps) => {
|
||||||
const [, forceRender] = useState(false);
|
const [, forceRender] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = preloader
|
||||||
forceRender((x) => !x);
|
? undefined
|
||||||
}, 100);
|
: setInterval(() => {
|
||||||
|
forceRender((x) => !x);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, []);
|
}, [preloader]);
|
||||||
|
|
||||||
const itemClasses = classNames({
|
const itemClasses = classNames('loader-item', {
|
||||||
'dark:bg-white bg-black': !forceTheme,
|
'dark:bg-white bg-black': !forceTheme,
|
||||||
'bg-white': forceTheme === 'dark',
|
'bg-white': forceTheme === 'dark',
|
||||||
'bg-black': forceTheme === 'light',
|
'bg-black': forceTheme === 'light',
|
||||||
@ -29,8 +36,11 @@ export const Loader = ({ size = 'large', forceTheme }: LoaderProps) => {
|
|||||||
const items = size === 'small' ? 9 : 16;
|
const items = size === 'small' ? 9 : 16;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center" data-testid="loader">
|
<div
|
||||||
<div className={`${wrapperClasses} flex flex-wrap`}>
|
className="flex flex-col items-center pre-loader-center"
|
||||||
|
data-testid="loader"
|
||||||
|
>
|
||||||
|
<div className={`${wrapperClasses} flex flex-wrap pre-loader-wrapper`}>
|
||||||
{new Array(items).fill(null).map((_, i) => {
|
{new Array(items).fill(null).map((_, i) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
Loading…
Reference in New Issue
Block a user