-
-
Save ilionic/33cbfe83c5a19fd73b972e28fdbb0f0a to your computer and use it in GitHub Desktop.
Render Medium style blurred preview images using react-imgix
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
.aspectWrapper { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
} | |
.wrapper { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
} | |
.container { | |
position: relative; | |
overflow: hidden; | |
width: 100%; | |
height: 100%; | |
& img { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
} | |
} | |
.preview { | |
z-index: 1; | |
opacity: 1; | |
width: 100%; | |
height: 100%; | |
transition: opacity 500ms; | |
background-position: center center; | |
} | |
.previewLoaded { | |
z-index: 1; | |
opacity: 1; | |
width: 100%; | |
height: 100%; | |
transition: opacity 500ms; | |
} | |
.loaded { | |
& .preview { | |
opacity: 0; | |
} | |
& .full { | |
opacity: 1; | |
} | |
} | |
.full { | |
opacity: 1; | |
z-index: 2; | |
transition: opacity 300ms; | |
height: 100%; | |
width: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
background-position: center center; | |
} |
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 classes from './FastImg.css' | |
import classNames from 'classnames' | |
import Imgix from 'react-imgix' | |
import FluidImgix from 'FluidImgix' | |
export class FastImgix extends Component { | |
static propTypes = { | |
src: PropTypes.string.isRequired, | |
className: PropTypes.string, | |
aspect: PropTypes.number, | |
useFluid: PropTypes.bool, | |
previewSrc: PropTypes.string, | |
onLoad: PropTypes.func, | |
bg: PropTypes.bool | |
}; | |
constructor (props) { | |
super(props) | |
let preloaded = props.previewSrc != null | |
this.state = {loaded: false, preloaded, mounted: false} | |
} | |
render () { | |
const { className, aspect } = this.props | |
const loadStateClasses = { | |
[classes.loaded]: this.state.loaded, | |
[classes.preloaded]: this.state.preloaded | |
} | |
let styles = {} | |
if (aspect) styles = { position: 'relative', height: 0, paddingBottom: `${aspect * 100}%` } | |
return ( | |
<div className={classNames(classes.aspectWrapper, className)} style={styles}> | |
<div className={classes.wrapper}> | |
<div className={classNames(classes.container, loadStateClasses)}> | |
{this.renderPreviewImage()} | |
{this.renderFullImage()} | |
</div> | |
</div> | |
</div> | |
) | |
} | |
componentDidMount () { | |
this.setState({mounted: true}) | |
} | |
renderPreviewImage () { | |
const { src, previewSrc, bg } = this.props | |
const previewImageProps = { onLoad: this.onPreviewLoad } | |
if (previewSrc) { | |
return <img className={classes.previewLoaded} {...previewImageProps} src={previewSrc} /> | |
} else { | |
return <Imgix src={src} className={classes.preview} bg={bg} width={10} height={10} fit='clip' faces={false} generateSrcSet={false} customParams={{q: 10, blur: 2000, bri: 25, sat: 25}} imgProps={previewImageProps} aggressiveLoad /> | |
} | |
} | |
renderFullImage () { | |
if (!this.state.mounted) return null | |
const fullImageProps = { onLoad: this.onFullLoad } | |
const { src, aspect, useFluid } = this.props | |
const fit = aspect ? 'clip' : 'crop' | |
const auto = 'compress' | |
if (useFluid) { | |
return <FluidImgix src={src} fit='clip' height={1} className={classes.full} faces={false} {...this.options} imgProps={fullImageProps} customParams={{auto}} /> | |
} else { | |
return <Imgix src={src} fit={fit} className={classes.full} onLoad={this.onFullLoad} faces={false} {...this.options} imgProps={fullImageProps} customParams={{auto}} /> | |
} | |
} | |
get options () { | |
let o = {...this.props} | |
delete o.src | |
delete o.className | |
delete o.aspect | |
delete o.useFluid | |
return o | |
} | |
onPreviewLoad = () => this.setState({preloaded: true}) | |
onFullLoad = (e) => { | |
const { onLoad } = this.props | |
this.setState({loaded: true, preloaded: false}) | |
if (onLoad) onLoad(e.target) | |
} | |
} |
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 Imgix from 'react-imgix' | |
import ReactDOM from 'react-dom' | |
// sizes image based on width of parent container | |
export default class FluidImgix extends Imgix { | |
forceLayout = () => { | |
const node = ReactDOM.findDOMNode(this) | |
const parent = node.parentNode | |
this.setState({ | |
width: parent.scrollWidth, | |
height: 1, | |
mounted: true | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment