Last active
August 16, 2020 20:47
-
-
Save andykent/2574cf9e50a014a7a64ea0ee4b88ab3b to your computer and use it in GitHub Desktop.
Render Medium style blurred preview images using react-imgix
This file contains 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 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 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