// Variables
$black: #111;
$radius: 10px;
$transition: all .25s ease-in-out;
html,
body {
min-height: 100%;
height: 100%;
}
html {
font-size: 16px;
}
body {
position: relative;
font-size: 100%;
}
.gallery-container {
padding-top: .9375rem;
}
.gallery-card {
position: relative;
overflow: hidden;
margin-bottom: 1.875rem;
}
.gallery-thumbnail {
max-width: 100%;
height: auto;
border-radius: $radius;
}
.card-icon-open {
display: block;
position: absolute;
top: 50%;
left: 50%;
font-size: 2rem;
color: #fff;
cursor: pointer;
opacity: 0;
transform: translate(-50%, -50%);
transition: $transition;
&:focus,
&:hover {
color: $black;
}
}
.gallery-thumbnail:focus ~ .card-icon-open,
.gallery-thumbnail:hover ~ .card-icon-open,
.gallery-thumbnail ~ .card-icon-open:focus,
.gallery-thumbnail ~ .card-icon-open:hover {
opacity: 1;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
background: rgba(21,21,21,.75);
}
.modal-body {
position: absolute;
top: 50%;
left: 50%;
z-index: 11;
padding: 0;
overflow: auto;
max-width: 100%;
max-height: 100%;
border-radius: $radius;
transform: translate(-50%, -50%);
}
.modal-close {
position: absolute;
top: 0;
right: 8px;
font-size: 1.5rem;
color: $black;
transition: $transition;
&:focus,
&:hover {
color: #fff;
}
}
View Compiled
// Cache gallery container
const galleryContainer = document.querySelector('.react-gallery');
// Create new array with URLs for images
let imgUrls = [
'https://source.unsplash.com/4rDCa5hBlCs/800x600',
'https://source.unsplash.com/01vFmYAOqQ0/800x600',
'https://source.unsplash.com/2Bjq3A7rGn4/800x600',
'https://source.unsplash.com/cFplR9ZGnAk/800x600',
'https://source.unsplash.com/pHANr-CpbYM/800x600',
'https://source.unsplash.com/RkmyeYA6xuE/800x600',
'https://source.unsplash.com/E4944K_4SvI/800x600',
'https://source.unsplash.com/-hI5dX2ObAs/800x600',
'https://source.unsplash.com/vZlTg_McCDo/800x600'
];
// Component for gallery image
class GalleryImage extends React.Component {
render() {
return(
<img className={this.props.className} src={this.props.src} alt={this.props.alt} />
)
}
}
// Component for gallery modal
class GalleryModal extends React.Component {
render() {
if (this.props.isOpen === false) {
return null;
}
return(
<div isOpen={this.props.isOpen} className='modal-overlay' onClick={this.props.onClick} name={this.props.name}>
<div className='modal-body'>
<a className='modal-close' href='#' onClick={this.props.onClick}><span className='fa fa-times'></span></a>
<img src={this.props.src} />
</div>
</div>
)
}
}
// Component for gallery
class Gallery extends React.Component{
constructor(props) {
super(props);
this.state = {
showModal: false,
url: ''
}
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
render() {
return(
<div refs='gallery-container' className='container-fluid gallery-container'>
<div className='row'>
{
imgUrls.map((url, index) => {
return <div className='col-sm-6 col-md-3 col-xl-2'>
<div className='gallery-card'>
<GalleryImage className='gallery-thumbnail' src={url} alt={'Image number ' + (index + 1)} />
<span className='card-icon-open fa fa-expand' value={url} onClick={(e) => this.openModal(url, e)}></span>
</div>
</div>
})
}
</div>
<GalleryModal isOpen={this.state.showModal} onClick={this.closeModal} src={this.state.url} />
</div>
)
}
// Function for opening modal dialog
openModal(url, e) {
this.setState({
showModal: true,
url: url
})
};
// Function for closing modal dialog
closeModal() {
this.setState({
showModal: false,
url: ''
})
}
}
// Let's render the whole thing
ReactDOM.render(
<Gallery imgUrls={imgUrls} />
, galleryContainer);
View Compiled