From d7deb9819bbf2d22b0eaab4bfad9502ddbfcfe60 Mon Sep 17 00:00:00 2001 From: Fouad Date: Thu, 2 Feb 2023 16:42:11 +0000 Subject: [PATCH] NymConnect - Add button animations (#2950) * add button animations * pulse and disable button on connecting/disconnecting status * update button component story * disabled hover on connecting/disconnecting * add transition delay fix up overflow --- nym-connect/src/components/PowerButton.tsx | 132 ------------------ .../components/PowerButton/PowerButton.tsx | 123 ++++++++++++++++ .../components/PowerButton/power-button.css | 72 ++++++++++ .../src/pages/connection/Connected.tsx | 4 +- .../src/pages/connection/Disconnected.tsx | 8 +- .../src/stories/PowerButton.stories.tsx | 8 +- 6 files changed, 204 insertions(+), 143 deletions(-) delete mode 100644 nym-connect/src/components/PowerButton.tsx create mode 100644 nym-connect/src/components/PowerButton/PowerButton.tsx create mode 100644 nym-connect/src/components/PowerButton/power-button.css diff --git a/nym-connect/src/components/PowerButton.tsx b/nym-connect/src/components/PowerButton.tsx deleted file mode 100644 index 426028a767..0000000000 --- a/nym-connect/src/components/PowerButton.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React from 'react'; -import { ConnectionStatusKind } from 'src/types'; - -const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isError: boolean): string => { - if (isError && hover) { - return '#21D072'; - } - if (isError) { - return '#40475C'; - } - - switch (status) { - case 'disconnected': - if (hover) { - return '#FFF'; - } - return '#BBB'; - case 'connecting': - return '#FFF'; - case 'disconnecting': - return '#FFF'; - default: - // connected - if (hover) { - return '#E43E3E'; - } - return '#21D072'; - } -}; - -export const PowerButton: FCWithChildren<{ - onClick?: (status: ConnectionStatusKind) => void; - isError?: boolean; - disabled?: boolean; - status: ConnectionStatusKind; - busy?: boolean; -}> = ({ onClick, disabled, status, isError }) => { - const [hover, setHover] = React.useState(false); - - const handleClick = () => { - if (disabled === true) { - return; - } - if (onClick) { - onClick(status); - } - }; - - const statusFillColor = getStatusFillColor(status, hover, Boolean(isError)); - - return ( - !disabled && setHover(true)} - onMouseLeave={() => !disabled && setHover(false)} - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/nym-connect/src/components/PowerButton/PowerButton.tsx b/nym-connect/src/components/PowerButton/PowerButton.tsx new file mode 100644 index 0000000000..a0c6dc757a --- /dev/null +++ b/nym-connect/src/components/PowerButton/PowerButton.tsx @@ -0,0 +1,123 @@ +import React, { useCallback } from 'react'; +import { ConnectionStatusKind } from 'src/types'; +import './power-button.css'; + +const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isError: boolean): string => { + if (isError && hover) { + return '#21D072'; + } + if (isError) { + return '#40475C'; + } + + switch (status) { + case 'disconnected': + if (hover) { + return '#FFF'; + } + return '#BBB'; + case 'connecting': + return '#FFF'; + case 'disconnecting': + return '#FFF'; + default: + // connected + if (hover) { + return '#E43E3E'; + } + return '#21D072'; + } +}; + +export const PowerButton: FCWithChildren<{ + onClick?: (status: ConnectionStatusKind) => void; + isError?: boolean; + disabled?: boolean; + status: ConnectionStatusKind; + busy?: boolean; +}> = ({ onClick, disabled, status, isError }) => { + const [hover, setHover] = React.useState(false); + + const handleClick = () => { + if (disabled === true) { + return; + } + if (onClick) { + onClick(status); + } + }; + + const statusFillColor = getStatusFillColor(status, hover, Boolean(isError)); + + const getClassName = useCallback(() => { + if (hover) { + switch (status) { + case 'disconnected': + return 'expand'; + default: + return 'contract'; + } + } + if (!hover) { + switch (status) { + case 'connected': + return 'expand'; + default: + return 'contract'; + } + } + }, [status, hover]); + + const buttonPulse = () => { + if (status === 'connecting' || status === 'disconnecting') return 'pulse'; + return undefined; + }; + + return ( + !disabled && setHover(true)} + onMouseLeave={() => !disabled && setHover(false)} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/nym-connect/src/components/PowerButton/power-button.css b/nym-connect/src/components/PowerButton/power-button.css new file mode 100644 index 0000000000..a493d8df25 --- /dev/null +++ b/nym-connect/src/components/PowerButton/power-button.css @@ -0,0 +1,72 @@ +#ring-expand { + animation-name: rings-expand; + animation-duration: 0.4s; + animation-timing-function: ease-in-out; + animation-play-state: paused; +} + +#ring-one.expand { + opacity: 0.3; + transition: opacity 0.1s ease-in-out; +} + +#ring-two.expand { + opacity: 0.2; + transition: opacity 0.2s ease-in-out; +} + +#ring-three.expand { + opacity: 0.1; + transition: opacity 0.3s ease-in-out; +} + +#ring-four.expand { + opacity: 0.05; + transition: opacity 0.4s ease-in-out; +} + +#ring-one.contract { + opacity: 0; + transition: opacity 0.4s; + transition-delay: 0.1s; +} + +#ring-two.contract { + opacity: 0; + transition: opacity 0.3s; + transition-delay: 0.1s; +} + +#ring-three.contract { + opacity: 0; + transition: opacity 0.1s; + transition-delay: 0.1s; +} + +#ring-four.contract { + opacity: 0; + transition: opacity 0.1s; + transition-delay: 0.1s; +} + +circle, +path { + transition: stroke 0.5s, fill 0.5s; +} + +.pulse { + animation-name: pulse; + animation-duration: 0.5s; + animation-iteration-count: infinite; + animation-direction: alternate; +} + +@keyframes pulse { + from { + opacity: 1; + } + + to { + opacity: 0.3; + } +} diff --git a/nym-connect/src/pages/connection/Connected.tsx b/nym-connect/src/pages/connection/Connected.tsx index 63da0d6fb1..a896380fd4 100644 --- a/nym-connect/src/pages/connection/Connected.tsx +++ b/nym-connect/src/pages/connection/Connected.tsx @@ -10,7 +10,7 @@ import { IpAddressAndPort } from 'src/components/IpAddressAndPort'; import { ServiceProvider } from 'src/types/directory'; import { ExperimentalWarning } from 'src/components/ExperimentalWarning'; import { ConnectionLayout } from 'src/layouts/ConnectionLayout'; -import { PowerButton } from 'src/components/PowerButton'; +import { PowerButton } from 'src/components/PowerButton/PowerButton'; export const Connected: FCWithChildren<{ status: ConnectionStatusKind; @@ -58,7 +58,7 @@ export const Connected: FCWithChildren<{ busy={busy} onClick={onConnectClick} isError={isError} - disabled={status === 'connecting' || status === 'disconnecting'} + disabled={status === 'disconnecting'} /> } BottomContent={ diff --git a/nym-connect/src/pages/connection/Disconnected.tsx b/nym-connect/src/pages/connection/Disconnected.tsx index f92d70ad55..781f49eb85 100644 --- a/nym-connect/src/pages/connection/Disconnected.tsx +++ b/nym-connect/src/pages/connection/Disconnected.tsx @@ -2,14 +2,12 @@ import React from 'react'; import { Stack, Typography } from '@mui/material'; import { ConnectionStatus } from 'src/components/ConnectionStatus'; import { ConnectionTimer } from 'src/components/ConntectionTimer'; -import { useClientContext } from 'src/context/main'; import { InfoModal } from 'src/components/InfoModal'; import { Error } from 'src/types/error'; import { ExperimentalWarning } from 'src/components/ExperimentalWarning'; import { ServiceProvider, Services } from 'src/types/directory'; import { ConnectionStatusKind } from 'src/types'; -import { ConnectionButton } from 'src/components/ConnectionButton'; -import { PowerButton } from 'src/components/PowerButton'; +import { PowerButton } from 'src/components/PowerButton/PowerButton'; import { Box } from '@mui/system'; import { ConnectionLayout } from 'src/layouts/ConnectionLayout'; @@ -22,7 +20,7 @@ export const Disconnected: FCWithChildren<{ serviceProvider?: ServiceProvider; clearError: () => void; onConnectClick: (status: ConnectionStatusKind) => void; -}> = ({ status, error, onConnectClick, clearError, serviceProvider }) => { +}> = ({ status, error, onConnectClick, clearError }) => { return ( <> {error && } @@ -33,7 +31,7 @@ export const Disconnected: FCWithChildren<{ } - ConnectButton={} + ConnectButton={} BottomContent={ = () => ( ); export const Connecting: ComponentStory = () => ( - + ); export const Connected: ComponentStory = () => ( @@ -21,9 +21,9 @@ export const Connected: ComponentStory = () => ( ); export const Disconnecting: ComponentStory = () => ( - + ); export const Disabled: ComponentStory = () => ( - + );