Skip to content

Instantly share code, notes, and snippets.

@vamsiampolu
Created November 22, 2016 20:35
Show Gist options
  • Save vamsiampolu/0c0f59a1273281c2c6304229b70ae1e0 to your computer and use it in GitHub Desktop.
Save vamsiampolu/0c0f59a1273281c2c6304229b70ae1e0 to your computer and use it in GitHub Desktop.
{
"presets":[
"react",
[
"env",
{
"targets":{
"chrome":54,
"node":true
}
}
]
],
"plugins":[
"react-hot-loader/babel",
"transform-class-properties",
["transform-object-rest-spread", {
"useBuiltIns":true
}
]
]
}
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,
};
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);
});
}
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,
};
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