Просмотр исходного кода

Merge pull request #244 from smiclea/status-animation

Animate 'success' and 'error' status images
Dorin Paslaru 8 лет назад
Родитель
Сommit
2d9b64f098

+ 5 - 5
src/components/atoms/StatusImage/images/error.svg → src/components/atoms/StatusImage/images/error.js

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+export default `<?xml version="1.0" encoding="UTF-8"?>
 <svg width="96px" height="96px" viewBox="0 0 96 96" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
     <title>splash-1</title>
@@ -8,11 +8,11 @@
         <g id="Wizard/03-Instances---Search-Error" transform="translate(-672.000000, -336.000000)" stroke="#F91661" stroke-width="1.5">
             <g id="Splash-Copy" transform="translate(501.000000, 336.000000)">
                 <g id="Icon/Error/Red-96" transform="translate(171.000000, 0.000000)">
-                    <circle id="Oval-2" cx="48" cy="48" r="47"></circle>
-                    <path d="M68.5714286,27.4285714 L27.4285714,68.5714286" id="Line"></path>
-                    <path d="M68.5714286,68.5714286 L27.4285714,27.4285714" id="Line-Copy"></path>
+                    <circle class="circle" cx="48" cy="48" r="47"></circle>
+                    <path class="path" d="M68.5714286,27.4285714 L27.4285714,68.5714286" id="Line"></path>
+                    <path class="path" d="M68.5714286,68.5714286 L27.4285714,27.4285714" id="Line-Copy"></path>
                 </g>
             </g>
         </g>
     </g>
-</svg>
+</svg>`

+ 4 - 4
src/components/atoms/StatusImage/images/success.svg → src/components/atoms/StatusImage/images/success.js

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+export default `<?xml version="1.0" encoding="UTF-8"?>
 <svg width="96px" height="96px" viewBox="0 0 96 96" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
     <title>User-VL Copy</title>
@@ -9,11 +9,11 @@
             <g id="Modal-Connection">
                 <g id="Group-Copy" transform="translate(32.000000, 95.967742)">
                     <g id="Icon/Ok/Green-96" transform="translate(208.000000, 0.032258)">
-                        <circle id="Oval-2" cx="48" cy="48" r="47.25"></circle>
-                        <polyline id="Stroke-3" stroke-linecap="round" stroke-linejoin="round" points="69 35 43.1861395 61 27 45.4206722"></polyline>
+                        <circle class="circle" cx="48" cy="48" r="47.25"></circle>
+                        <polyline class="path" stroke-linecap="round" stroke-linejoin="round" points="69 35 43.1861395 61 27 45.4206722"></polyline>
                     </g>
                 </g>
             </g>
         </g>
     </g>
-</svg>
+</svg>`

+ 58 - 46
src/components/atoms/StatusImage/index.jsx

@@ -20,8 +20,8 @@ import styled, { css } from 'styled-components'
 import StyleProps from '../../styleUtils/StyleProps'
 import Palette from '../../styleUtils/Palette'
 
-import errorImage from './images/error.svg'
-import successImage from './images/success.svg'
+import errorImage from './images/error'
+import successImage from './images/success'
 import loadingImage from './images/loading.svg'
 
 type Props = {
@@ -29,36 +29,13 @@ type Props = {
   loading?: boolean,
   loadingProgress?: number,
 }
-
-const statuses = () => {
-  return {
-    ERROR: css`
-      background-image: url('${errorImage}');
-    `,
-    COMPLETED: css`
-      background-image: url('${successImage}');
-    `,
-    RUNNING: css`
-      background-image: url('${loadingImage}');
-      transform-origin: 48px 48px;
-      animation: rotate 1s linear infinite;
-
-      @keyframes rotate {
-        0% {transform: rotate(0deg);}
-        100% {transform: rotate(360deg);}
-      }
-    `,
-    PROGRESS: css``,
-  }
-}
 const Wrapper = styled.div`
   position: relative;
   ${StyleProps.exactSize('96px')}
   background-repeat: no-repeat;
   background-position: center;
-  ${(props: Props) => statuses()[props.status || 'RUNNING']}
 `
-const SvgWrapper = styled.svg`
+const ProgressSvgWrapper = styled.svg`
   ${StyleProps.exactSize('100%')}
   transform: rotate(-90deg);
 `
@@ -73,20 +50,56 @@ const ProgressText = styled.div`
 const CircleProgressBar = styled.circle`
   transition: stroke-dashoffset ${StyleProps.animations.swift};
 `
-
+const dashAnimationStyle = css`
+  .circle {
+    stroke-dasharray: 300;
+    stroke-dashoffset: 300;
+    animation: dash 300ms ease-in-out forwards;
+  }
+  .path {
+    stroke-dasharray: 60;
+    stroke-dashoffset: 60;
+    animation: dash 300ms ease-in-out forwards;
+  }
+  @keyframes dash {
+    to { stroke-dashoffset: 0; }
+  }
+`
+const loadingAnimationStyle = css`
+  background: url(${loadingImage}) center no-repeat;
+  animation: rotate 1s linear infinite;
+  @keyframes rotate {
+    0% {transform: rotate(0deg);}
+    100% {transform: rotate(360deg);}
+  }
+`
+const Image = styled.div`
+  ${StyleProps.exactSize('96px')}
+  ${props => props.cssStyle}
+`
+const Images = {
+  COMPLETED: {
+    image: successImage,
+    style: dashAnimationStyle,
+  },
+  ERROR: {
+    image: errorImage,
+    style: dashAnimationStyle,
+  },
+  RUNNING: {
+    style: loadingAnimationStyle,
+    image: '',
+  },
+}
 @observer
 class StatusImage extends React.Component<Props> {
   static defaultProps: $Shape<Props> = {
     status: 'RUNNING',
   }
 
-  renderProgressImage(status: string) {
-    if (status !== 'PROGRESS') {
-      return null
-    }
-
+  renderProgressImage() {
     return (
-      <SvgWrapper id="svg" width="96" height="96" viewPort="0 0 96 96" version="1.1" xmlns="http://www.w3.org/2000/svg">
+      <ProgressSvgWrapper id="svg" width="96" height="96" viewPort="0 0 96 96" version="1.1" xmlns="http://www.w3.org/2000/svg">
         <g strokeWidth="2">
           <circle
             r="47"
@@ -106,15 +119,11 @@ class StatusImage extends React.Component<Props> {
             strokeDashoffset={300 - ((this.props.loadingProgress || 0) * 3)}
           />
         </g>
-      </SvgWrapper>
+      </ProgressSvgWrapper>
     )
   }
 
-  renderProgressText(status: string) {
-    if (status !== 'PROGRESS') {
-      return null
-    }
-
+  renderProgressText() {
     return (
       <ProgressText
         data-test-id="statusImage-progressText"
@@ -123,7 +132,7 @@ class StatusImage extends React.Component<Props> {
   }
 
   render() {
-    let status = this.props.status
+    let status = this.props.status || ''
     if (this.props.loading) {
       status = 'RUNNING'
       if (this.props.loadingProgress !== undefined && this.props.loadingProgress > -1) {
@@ -132,12 +141,15 @@ class StatusImage extends React.Component<Props> {
     }
 
     return (
-      <Wrapper
-        {...this.props}
-        status={status}
-      >
-        {this.renderProgressImage(status || '')}
-        {this.renderProgressText(status || '')}
+      <Wrapper>
+        {status !== 'PROGRESS' ? (
+          <Image
+            dangerouslySetInnerHTML={{ __html: Images[status || 'RUNNING'].image }}
+            cssStyle={Images[status || 'RUNNING'].style}
+          />
+        ) : null}
+        {status === 'PROGRESS' ? this.renderProgressImage() : null}
+        {status === 'PROGRESS' ? this.renderProgressText() : null}
       </Wrapper>
     )
   }