Created
November 22, 2016 20:35
-
-
Save vamsiampolu/0c0f59a1273281c2c6304229b70ae1e0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"presets":[ | |
"react", | |
[ | |
"env", | |
{ | |
"targets":{ | |
"chrome":54, | |
"node":true | |
} | |
} | |
] | |
], | |
"plugins":[ | |
"react-hot-loader/babel", | |
"transform-class-properties", | |
["transform-object-rest-spread", { | |
"useBuiltIns":true | |
} | |
] | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react'; | |
import { style, keyframes, merge } from 'glamor'; | |
const { string, number, bool, object } = PropTypes; | |
const defaultWrapperStyle = { | |
width: 200, | |
height: 200, | |
backgroundColor: 'white', | |
backgroundSize: 'contain', | |
backgroundRepeat: 'none', | |
boxSizing: 'border-box', | |
position: 'relative', | |
transition: 'width 150ms, height 150ms', | |
}; | |
const PENDING = 'PENDING'; | |
const LOADING = 'LOADING'; | |
const LOADED = 'LOADED'; | |
const FAILED = 'FAILED'; | |
export default class Image extends Component { | |
constructor(props) { | |
super(props); | |
this.onLoad = this.onLoad.bind(this); | |
this.onFail = this.onFail.bind(this); | |
if (this.props.src != null && typeof this.props.src === 'string') { | |
this.state = { | |
status: LOADING, | |
}; | |
} else { | |
this.state = { | |
status: PENDING, | |
}; | |
} | |
} | |
componentWillReceiveProps(nextProps) { | |
if (this.props.src !== nextProps.src) { | |
this.setState({ | |
status: LOADING, | |
}); | |
} | |
} | |
onLoad() { | |
this.setState({ | |
status: LOADED, | |
}); | |
} | |
onFail() { | |
this.setState({ | |
status: FAILED, | |
}); | |
} | |
render() { | |
const { | |
src, | |
width, | |
height, | |
alt, | |
loadingStyle, | |
failureStyle, | |
rounded, | |
circle, | |
} = this.props; | |
const mainWrapperStyle = style({ | |
...defaultWrapperStyle, | |
width, | |
height, | |
}); | |
let wrapperStyle = {}; | |
if (rounded) { | |
const roundedStyle = style({ | |
borderRadius: '10%', | |
overflow: 'hidden', | |
}); | |
wrapperStyle = merge(mainWrapperStyle, roundedStyle); | |
} else if (circle) { | |
const circularStyle = style({ | |
borderRadius: '50%', | |
overflow: 'hidden', | |
}); | |
wrapperStyle = merge(mainWrapperStyle, circularStyle); | |
} else { | |
wrapperStyle = mainWrapperStyle; | |
} | |
const defaultImageStyle = style({ | |
opacity: 0, | |
transisition: 'opacity 150ms ease', | |
}); | |
const loadedImageStyle = style({ | |
opacity: 1, | |
}); | |
let imageStyle = defaultImageStyle; | |
if (this.state.status === LOADED) { | |
imageStyle = merge(defaultImageStyle, loadedImageStyle); | |
} else { | |
imageStyle = defaultImageStyle; | |
} | |
let image; | |
if (alt != null) { | |
image = (<img | |
className={imageStyle} | |
src={src} | |
width={width} | |
height={height} | |
alt={alt} | |
onLoad={this.onLoad} | |
onError={this.onFail} | |
/>); | |
} else { | |
image = (<img | |
className={imageStyle} | |
src={src} | |
width={width} | |
height={height} | |
role="presentation" | |
onLoad={this.onLoad} | |
onError={this.onFail} | |
/>); | |
} | |
let statusIndicator = null; | |
if (this.state.status === LOADING) { | |
statusIndicator = (<div className={loadingStyle} />); | |
} else if (this.state.status === FAILED) { | |
const crossArm = { | |
background: '#000', | |
width: 5, | |
height: 50, | |
position: 'absolute', | |
top: '30%', | |
left: '50%', | |
transform: 'rotate(45deg)', | |
}; | |
const otherCrossArm = style({ | |
...crossArm, | |
transform: 'rotate(-45deg)', | |
}); | |
statusIndicator = [ | |
(<div className={style(crossArm)} />), | |
(<div className={otherCrossArm} />), | |
]; | |
} | |
return (<div className={wrapperStyle}> | |
{statusIndicator} | |
{image} | |
</div>); | |
} | |
} | |
Image.propTypes = { | |
src: string.isRequired, | |
width: number.isRequired, | |
height: number.isRequired, | |
alt: string, | |
loadingStyle: object, | |
failureStyle: object, | |
circle: bool, | |
rounded: bool, | |
}; | |
const crossArm = { | |
background: '#000', | |
width: 5, | |
height: 50, | |
position: 'absolute', | |
top: '30%', | |
left: '50%', | |
}; | |
const failureStyle = style({ | |
...crossArm, | |
transform: 'rotate(45deg)', | |
':before': { | |
content: '', | |
background: '#000', | |
width: 5, | |
height: 50, | |
position: 'absolute', | |
top: 0, | |
left: 0, | |
transform: 'rotate(-90deg)', | |
}, | |
}); | |
// failureStyle = merge(failureStyle, otherCrossArm); | |
const ring = keyframes({ | |
'0%': { | |
transform: 'rotate(0deg)', | |
}, | |
'100%': { | |
transform: 'rotate(360deg)', | |
}, | |
}); | |
const loadingStyle = style({ | |
position: 'absolute', | |
display: 'block', | |
width: 40, | |
height: 40, | |
top: '37%', | |
left: '37%', | |
borderRadius: 80, | |
boxShadow: '0 3px 0 0 #59ebff', | |
animation: `${ring} 1s linear infinite`, | |
}); | |
Image.defaultProps = { | |
loadingStyle, | |
failureStyle, | |
circle: false, | |
rounded: true, | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { Router, hashHistory } from 'react-router'; | |
import { render } from 'react-dom'; | |
import injectTapEventPlugin from 'react-tap-event-plugin'; | |
import { AppContainer } from 'react-hot-loader'; | |
import routes from './routes'; | |
injectTapEventPlugin(); | |
const root = document.getElementById('root'); | |
const renderApp = appRoutes => render( | |
<AppContainer> | |
<Router routes={appRoutes} history={hashHistory} /> | |
</AppContainer>, | |
root, | |
); | |
renderApp(routes); | |
if (module.hot) { | |
module.hot.accept('./routes', () => { | |
const nextRoutes = require('./routes').default; | |
renderApp(nextRoutes); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { PropTypes } from 'react'; | |
import { style } from 'glamor'; | |
import Image from './Image'; | |
const centerImage = style({ | |
display: 'block', | |
margin: 'auto', | |
paddingLeft: 8, | |
paddingRight: 8, | |
}); | |
export default function LoremPixel({ url = 'http://lorempixel.com', width = 400, height = 400, alt = 'Placeholder image' }) { | |
const src = `${url}/${width}/${height}?t=${Date.now()}`; | |
return (<Image | |
rounded={false} | |
width={width} | |
height={height} | |
className={centerImage} | |
src={src} | |
/>); | |
} | |
const { string, number, oneOf } = PropTypes; | |
LoremPixel.propTypes = { | |
url: string, | |
height: oneOf(string, number), | |
width: oneOf(string, number), | |
alt: string, | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const webpack = require('webpack'); | |
const validator = require('webpack-validator'); | |
const path = require('path'); | |
const HtmlWebpackPlugin = require('html-webpack-plugin'); | |
const template = require('html-webpack-template'); | |
const NpmInstallPlugin = require('npm-install-webpack-plugin'); | |
const DotEnvPlugin = require('webpack-dotenv-plugin'); | |
const APP_PATH = path.resolve('./app'); | |
const BUILD_PATH = path.resolve('./build'); | |
const SPEC_PATH = path.resolve('./spec'); | |
const HotModuleReplacementPlugin = webpack.HotModuleReplacementPlugin; | |
module.exports = validator({ | |
entry: [ | |
require.resolve('react-hot-loader/patch'), | |
require.resolve(`${APP_PATH}/index.js`), | |
], | |
output: { | |
filename: 'bundle.js', | |
path: BUILD_PATH, | |
publicPath: '/css-in-js-test/', | |
}, | |
devtool: 'eval-source-map', | |
devServer: { | |
inline: true, | |
hot: true, | |
host: process.env.HOST || '0.0.0.0', | |
port: process.env.PORT || 3000, | |
stats: 'errors-only', | |
historyApiFallback: true, | |
contentBase: BUILD_PATH, | |
watchOptions: { | |
aggregateTimeout: 300, | |
poll: 1000, | |
}, | |
}, | |
module: { | |
preLoaders: [ | |
{ | |
test: /\.jsx?/, | |
loader: 'eslint', | |
include: [ | |
APP_PATH, | |
SPEC_PATH, | |
], | |
}, | |
], | |
loaders: [ | |
{ | |
test: /\.jsx?/, | |
loader: 'babel', | |
include: APP_PATH, | |
query: { | |
cacheDirectory: true, | |
}, | |
}, | |
{ | |
test: /\.svg$/i, | |
loader: 'svg-sprite!svgo', | |
}, | |
], | |
}, | |
plugins: [ | |
new HotModuleReplacementPlugin(), | |
new DotEnvPlugin({ | |
sample: './.env.default', | |
path: './.env', | |
}), | |
new NpmInstallPlugin({ | |
dev(module) { | |
return (/(^babel-?.*|.*-plugin$|.*-loader)/).test(module); | |
}, | |
}), | |
new HtmlWebpackPlugin({ | |
inject: false, | |
mobile: true, | |
appMountId: 'root', | |
template, | |
}), | |
], | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment