Get spinners back in working order
This commit is contained in:
parent
d260200947
commit
5473edc006
16 changed files with 74 additions and 50 deletions
|
@ -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>
|
||||
|
|
|
@ -54,7 +54,7 @@ const LoginCheckpointContainer = () => {
|
|||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ?
|
||||
<Spinner size={'tiny'} className={'mx-auto'}/>
|
||||
<Spinner size={'small'} className={'mx-auto'}/>
|
||||
:
|
||||
'Continue'
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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`}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
9
resources/scripts/components/elements/Label.tsx
Normal file
9
resources/scripts/components/elements/Label.tsx
Normal 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;
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'}>
|
||||
|
|
|
@ -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'}
|
||||
|
|
Loading…
Reference in a new issue