Created custom Loader component

This commit is contained in:
John Lyon-Smith
2018-03-02 08:55:17 -08:00
parent 5e790ba65c
commit 30fcdf9d77
13 changed files with 113 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
{
"expoServerPort": 19000,
"packagerPort": 19001,
"packagerPid": 46572
"packagerPid": 694
}

View File

@@ -127,6 +127,11 @@
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"animejs": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/animejs/-/animejs-2.2.0.tgz",
"integrity": "sha1-Ne79/FNbgZScnLBvCz5gwC5v3IA="
},
"ansi-align": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-1.1.0.tgz",

View File

@@ -3,6 +3,7 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"animejs": "^2.2.0",
"auto-bind2": "^1.0.2",
"eventemitter3": "^2.0.3",
"prop-types": "^15.5.10",

View File

@@ -150,7 +150,7 @@ export class Login extends React.Component {
</Row.Item>
<Row.Item grow />
<WaitModal active={waitModal} message='Logging In' />
<WaitModal active={waitModal} message='Logging in...' />
<MessageModal error open={!!messageModal}
icon={messageModal ? messageModal.icon : ''}

View File

@@ -4,14 +4,17 @@ import { Dimmer, Loader, Text } from 'ui'
export class WaitModal extends React.Component {
static propTypes = {
message: PropTypes.string.isRequired
active: PropTypes.bool.isRequired,
message: PropTypes.string,
}
render() {
const { active, message } = this.props
return (
<Dimmer>
<Dimmer active={active}>
<Loader />
{this.props.message && <Text size='Huge'>{this.props.message}...</Text>}
{message && <Text size='huge' color='inverse'>{message}</Text>}
</Dimmer>
)
}

View File

@@ -1,8 +1,15 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
import { colorInfo } from 'ui/style'
ReactDOM.render(
<App style={{ minHeight: '100vh', position: 'relative' }} />,
document.getElementById('root')
)
// HACK: See https://github.com/facebook/react/issues/5619
let css = document.createElement('style')
document.body.appendChild(css)
css.innerHTML = `::-webkit-input-placeholder { color: ${colorInfo.textPlaceholder} }`

50
website/src/ui/Anime.js Normal file
View File

@@ -0,0 +1,50 @@
import React from 'react'
import anime from 'animejs'
import PropTypes from 'prop-types'
export default class Anime extends React.Component {
static propTypes = {
as: PropTypes.string,
children: PropTypes.node,
}
constructor(props) {
super(props)
this.targets = []
}
componentDidMount() {
let animeProps = Object.assign({}, this.props, {
targets: this.targets
})
delete animeProps.children
delete animeProps.as
this.anime = anime(animeProps)
}
shouldComponentUpdate(nextProps) {
this.anime = anime(Object.assign({}, { targets: this.targets }, nextProps))
return true
}
addTarget = (newTarget) => {
this.targets = [...this.targets, newTarget]
}
render() {
let children = []
if (this.props.children) {
if (Array.isArray(this.props.children)) {
children = this.props.children
} else {
children = [this.props.children]
}
}
return React.createElement(
(this.props.as || 'div'), {}, children.map((child, i) => (React.cloneElement(child, { key: i, ref: this.addTarget })))
)
}
}

View File

@@ -6,8 +6,8 @@ import { reactAutoBind } from 'auto-bind2'
export class Dimmer extends Component {
static propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.node,
active: PropTypes.bool
}
constructor(props) {

View File

@@ -8,11 +8,8 @@ export default {
color: '#000000',
borderStyle: 'solid',
borderRadius: '5px',
// boxShadow: '0px 0px 0px rgba(66,66,66,.75)'
// textShadow: 'undefined 0px 0px 5px px rgba(66,66,66,.75)'
':focus': {
outline: 'none'
}
},
}
}

View File

@@ -1,6 +1,8 @@
import React from 'react'
import Radium from 'radium'
import PropTypes from 'prop-types'
import { colorInfo } from 'ui/style'
import anime from 'animejs'
class Loader extends React.Component {
static propTypes = {
@@ -15,26 +17,38 @@ class Loader extends React.Component {
margin: '2px'
}
style(i) {
return {
backgroundColor: `${this.props.color}`,
width: `${this.props.size}px`,
height: `${this.props.size}px`,
margin: `${this.props.margin}`,
borderRadius: '100%',
display: 'inline-block',
// 0% {transform: scale(1); opacity: 1} 45% {transform: scale(0.1); opacity: 0.7} 80% {transform: scale(1); opacity: 1} 0.75s ${i * 0.12}s infinite cubic-bezier(.2,.68,.18,1.08)
animation: ``,
animationFillMode: 'both'
}
}
render() {
const size = 20
const spacing = 5
const addAnimation = (elem, i) => {
anime({
targets: elem,
scale: [
{ value: 0.2, duration: 800, easing: 'easeOutSine', delay: 200 * i },
{ value: 1.0, duration: 800, easing: 'easeOutSine' },
{ value: 1.0, duration: 200 * (2 - i) }
],
loop: true
})
}
return (
<div>
<div className={this.style(1)} />
<div className={this.style(2)} />
<div className={this.style(3)} />
<div style={{ height: size }}>
{
[0, 1, 2].map((i) => (
<span key={i} ref={(elem) => addAnimation(elem, i)}
style={{
display: 'inline-block',
marginLeft: i > 0 ? spacing : 0,
width: size,
height: size,
background: colorInfo.textInverse,
borderSize: 0,
borderRadius: '100%'
}} />
))
}
</div>
)
}

View File

@@ -5,10 +5,10 @@ import { fontInfo } from './style'
class Text extends Component {
static propTypes = {
size: PropTypes.string,
size: PropTypes.oneOf(['small', 'medium', 'large', 'huge']),
color: PropTypes.oneOf(['normal', 'inverse', 'alert', 'dimmed']),
margin: PropTypes.number,
children: PropTypes.node,
color: PropTypes.oneOf(['normal', 'alert', 'dimmed']),
width: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
align: PropTypes.string,
}

View File

@@ -1,3 +1,4 @@
export { default as Anime } from './Anime'
export { default as Box } from './Box'
export { default as Button } from './Button'
export { default as HeaderButton } from './HeaderButton'

View File

@@ -1,5 +1,7 @@
export const colorInfo = {
text: '#000000',
textInverse: '#FFFFFF',
textPlaceholder: '#EEEEEE',
alertText: '#FF0000',
grayText: '#B0B0B0',
buttonBackground: '#3498DB',
@@ -28,10 +30,12 @@ export const fontInfo = {
size: {
small: '10pt',
medium: '12pt',
large: '14pt'
large: '14pt',
huge: '26pt',
},
color: {
'normal': colorInfo.text,
'inverse': colorInfo.textInverse,
'alert': colorInfo.alertText,
'dimmed': colorInfo.grayText,
}