Get spinners back in working order

This commit is contained in:
Dane Everitt 2020-07-04 12:39:55 -07:00
parent d260200947
commit 5473edc006
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
16 changed files with 74 additions and 50 deletions

View file

@ -2,13 +2,13 @@ import React from 'react';
import MessageBox from '@/components/MessageBox';
import { State, useStoreState } from 'easy-peasy';
import { ApplicationStore } from '@/state';
import tw from 'twin.macro';
type Props = Readonly<{
byKey?: string;
spacerClass?: string;
}>;
export default ({ spacerClass, byKey }: Props) => {
export default ({ byKey }: Props) => {
const flashes = useStoreState((state: State<ApplicationStore>) => state.flashes.items);
let filtered = flashes;
@ -25,7 +25,7 @@ export default ({ spacerClass, byKey }: Props) => {
{
filtered.map((flash, index) => (
<React.Fragment key={flash.id || flash.type + flash.message}>
{index > 0 && <div css={tw`${spacerClass || 'mt-2'}`}></div>}
{index > 0 && <div css={tw`mt-2`}></div>}
<MessageBox type={flash.type} title={flash.title}>
{flash.message}
</MessageBox>

View file

@ -54,7 +54,7 @@ const LoginCheckpointContainer = () => {
disabled={isSubmitting}
>
{isSubmitting ?
<Spinner size={'tiny'} className={'mx-auto'}/>
<Spinner size={'small'} className={'mx-auto'}/>
:
'Continue'
}

View file

@ -61,7 +61,7 @@ const LoginContainer = ({ isSubmitting, setFieldValue, values, submitForm, handl
className={'btn btn-primary btn-jumbo'}
>
{isSubmitting ?
<Spinner size={'tiny'} className={'mx-auto'}/>
<Spinner size={'small'} className={'mx-auto'}/>
:
'Login'
}

View file

@ -92,7 +92,7 @@ export default ({ match, history, location }: Props) => {
disabled={isSubmitting}
>
{isSubmitting ?
<Spinner size={'tiny'} className={'mx-auto'}/>
<Spinner size={'small'} className={'mx-auto'}/>
:
'Reset Password'
}

View file

@ -79,7 +79,7 @@ export default ({ server }: { server: Server }) => {
<div css={tw`w-1/3 flex items-baseline relative`}>
{!stats ?
!statsError ?
<SpinnerOverlay size={'tiny'} visible={true} backgroundOpacity={0.25}/>
<SpinnerOverlay size={'small'} visible={true} backgroundOpacity={0.25}/>
:
server.isInstalling ?
<div css={tw`flex-1 text-center`}>

View file

@ -8,6 +8,8 @@ import { Actions, useStoreActions } from 'easy-peasy';
import { ApplicationStore } from '@/state';
import disableAccountTwoFactor from '@/api/account/disableAccountTwoFactor';
import { httpErrorToHuman } from '@/api/http';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
interface Values {
password: string;
@ -45,19 +47,19 @@ export default ({ ...props }: RequiredModalProps) => {
{({ isSubmitting, isValid }) => (
<Modal {...props} dismissable={!isSubmitting} showSpinnerOverlay={isSubmitting}>
<Form className={'mb-0'}>
<FlashMessageRender className={'mb-6'} byKey={'account:two-factor'}/>
<FlashMessageRender css={tw`mb-6`} byKey={'account:two-factor'}/>
<Field
id={'password'}
name={'password'}
type={'password'}
label={'Current Password'}
description={'In order to disable two-factor authentication you will need to provide your account password.'}
autoFocus={true}
autoFocus
/>
<div className={'mt-6 text-right'}>
<button className={'btn btn-red btn-sm'} disabled={!isValid}>
<div css={tw`mt-6 text-right`}>
<Button disabled={!isValid}>
Disable Two-Factor
</button>
</Button>
</div>
</Form>
</Modal>

View file

@ -7,10 +7,9 @@ interface Props {
size?: 'xsmall' | 'small' | 'large' | 'xlarge';
color?: 'green' | 'red' | 'primary' | 'grey';
isSecondary?: boolean;
disabled?: boolean;
}
const StyledButton = styled.button<Props>`
const StyledButton = styled.button<Omit<Props, 'isLoading'>>`
${tw`rounded p-2 uppercase tracking-wide text-sm transition-all duration-150`};
${props => props.isSecondary && css<Props>`
@ -73,9 +72,6 @@ const StyledButton = styled.button<Props>`
${props => props.size === 'xlarge' && tw`p-4 w-full`};
&:disabled { opacity: 0.55; cursor: default }
${props => props.disabled && css`opacity: 0.55; cursor: default`};
`;
type ComponentProps = Props &
@ -88,7 +84,7 @@ const Button: React.FC<ComponentProps> = ({ children, isLoading, ...props }) =>
<div className={'spinner-circle spinner-white spinner-sm'}/>
</div>
}
<span css={isLoading && tw`text-transparent`}>
<span css={isLoading ? tw`text-transparent` : undefined}>
{children}
</span>
</StyledButton>

View file

@ -1,7 +1,7 @@
import React from 'react';
import { Field as FormikField, FieldProps } from 'formik';
import classNames from 'classnames';
import Input from '@/components/elements/Input';
import Label from '@/components/elements/Label';
interface OwnProps {
name: string;
@ -19,7 +19,7 @@ const Field = ({ id, name, light = false, label, description, validate, classNam
({ field, form: { errors, touched } }: FieldProps) => (
<React.Fragment>
{label &&
<label htmlFor={id} className={light ? undefined : 'input-dark-label'}>{label}</label>
<Label htmlFor={id} isLight={light}>{label}</Label>
}
<Input
id={id}

View file

@ -12,7 +12,7 @@ const InputSpinner = ({ visible, children }: { visible: boolean, children: React
classNames={'fade'}
>
<div className={'absolute right-0 h-full flex items-center justify-end pr-3'}>
<Spinner size={'tiny'}/>
<Spinner size={'small'}/>
</div>
</CSSTransition>
{children}

View file

@ -0,0 +1,9 @@
import styled from 'styled-components/macro';
import tw from 'twin.macro';
const Label = styled.label<{ isLight?: boolean }>`
${tw`block text-xs uppercase text-neutral-200 mb-2`};
${props => props.isLight && tw`text-neutral-700`};
`;
export default Label;

View file

@ -1,31 +1,48 @@
import React from 'react';
import classNames from 'classnames';
import styled, { css, keyframes } from 'styled-components/macro';
import tw from 'twin.macro';
export type SpinnerSize = 'large' | 'normal' | 'tiny';
export type SpinnerSize = 'small' | 'base' | 'large';
interface Props {
size?: SpinnerSize;
centered?: boolean;
className?: string;
isBlue?: boolean;
}
const Spinner = ({ size, centered, className }: Props) => (
const spin = keyframes`
to { transform: rotate(360deg); }
`;
// noinspection CssOverwrittenProperties
const SpinnerComponent = styled.div<Props>`
${tw`w-8 h-8`};
border-width: 3px;
border-radius: 50%;
animation: ${spin} 1s cubic-bezier(0.55, 0.25, 0.25, 0.70) infinite;
${props => props.size === 'small' ? tw`w-4 h-4 border-2` : (props.size === 'large' ? css`
${tw`w-16 h-16`};
border-width: 6px;
` : null)};
border-color: ${props => !props.isBlue ? 'rgba(255, 255, 255, 0.2)' : 'hsla(212, 92%, 43%, 0.2)'};
border-top-color: ${props => !props.isBlue ? 'rgb(255, 255, 255)' : 'hsl(212, 92%, 43%)'};
`;
const Spinner = ({ centered, ...props }: Props) => (
centered ?
<div className={classNames(`flex justify-center ${className}`, { 'm-20': size === 'large', 'm-6': size !== 'large' })}>
<div
className={classNames('spinner-circle spinner-white', {
'spinner-lg': size === 'large',
'spinner-sm': size === 'tiny',
})}
/>
<div
css={[
tw`flex justify-center`,
props.size === 'large' ? tw`m-20` : tw`m-6`,
]}
>
<SpinnerComponent {...props}/>
</div>
:
<div
className={classNames(`spinner-circle spinner-white ${className}`, {
'spinner-lg': size === 'large',
'spinner-sm': size === 'tiny',
})}
/>
<SpinnerComponent {...props}/>
);
Spinner.DisplayName = 'Spinner';
export default Spinner;

View file

@ -1,7 +1,7 @@
import React from 'react';
import classNames from 'classnames';
import { CSSTransition } from 'react-transition-group';
import Spinner, { SpinnerSize } from '@/components/elements/Spinner';
import Fade from '@/components/elements/Fade';
import tw from 'twin.macro';
interface Props {
visible: boolean;
@ -11,17 +11,17 @@ interface Props {
}
const SpinnerOverlay = ({ size, fixed, visible, backgroundOpacity }: Props) => (
<CSSTransition timeout={150} classNames={'fade'} in={visible} unmountOnExit={true}>
<Fade timeout={150} in={visible} unmountOnExit>
<div
className={classNames('top-0 left-0 flex items-center justify-center w-full h-full rounded', {
absolute: !fixed,
fixed: fixed,
})}
css={[
tw`top-0 left-0 flex items-center justify-center w-full h-full rounded`,
!fixed ? tw`absolute` : tw`fixed`,
]}
style={{ zIndex: 9999, background: `rgba(0, 0, 0, ${backgroundOpacity || 0.45})` }}
>
<Spinner size={size}/>
</div>
</CSSTransition>
</Fade>
);
export default SpinnerOverlay;

View file

@ -5,7 +5,7 @@ const SuspenseSpinner = ({ children }: { children?: React.ReactNode }) => (
<Suspense
fallback={
<div className={'mx-4 w-3/4 mr-4 flex items-center justify-center'}>
<Spinner centered={true} size={'normal'}/>
<Spinner centered/>
</div>
}
>

View file

@ -69,7 +69,7 @@ export default () => {
<CSSTransition timeout={250} in={true} appear={true} classNames={'fade'}>
<div className={'bg-red-500 py-2'}>
<ContentContainer className={'flex items-center justify-center'}>
<Spinner size={'tiny'}/>
<Spinner size={'small'}/>
<p className={'ml-2 text-sm text-red-100'}>
We're having some trouble connecting to your server, please wait...
</p>

View file

@ -39,7 +39,7 @@ export default ({ backup, className }: Props) => {
{backup.completedAt ?
<FontAwesomeIcon icon={faArchive} className={'text-neutral-300'}/>
:
<Spinner size={'tiny'}/>
<Spinner size={'small'}/>
}
</div>
<div className={'flex-1'}>

View file

@ -19,7 +19,7 @@ const RenameServerBox = () => {
return (
<TitledGreyBox title={'Change Server Name'} className={'relative'}>
<SpinnerOverlay size={'normal'} visible={isSubmitting}/>
<SpinnerOverlay visible={isSubmitting}/>
<Form className={'mb-0'}>
<Field
id={'name'}