Skip to content

Instantly share code, notes, and snippets.

@artemartemov
Created May 23, 2019 16:56
Show Gist options
  • Save artemartemov/7277dcd8b81514fafe9d5a4ab6a33157 to your computer and use it in GitHub Desktop.
Save artemartemov/7277dcd8b81514fafe9d5a4ab6a33157 to your computer and use it in GitHub Desktop.
image slider using gastby-image fluid
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Img from 'gatsby-image';
import styled from 'styled-components';
const Slider = styled.div`
z-index: -1000;
height: 100vh;
width: 100vw;
transform: translate3d(${props => props.currentIndex * -100}%, 0, 0);
white-space: nowrap;
position: absolute;
top: 0;
transition: transform 0.2s ease-in-out;
&:after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
}
`;
const SlideContainer = styled.div`
transition: opacity 2s ease-in-out;
width: 100vw;
display: inline-block;
/* Sets the gatby image wrapper to be viewport height */
& .gatsby-image-wrapper {
height: 100vh;
}
`;
const requestTimeout = (fn, delay) => {
if (typeof window !== `undefined`) {
if (!window.requestAnimationFrame) return setTimeout(fn, delay);
const start = new Date().getTime();
const handle = {};
const loop = () => {
const current = new Date().getTime();
const delta = current - start;
delta >= delay ? fn.call() : handle.value === window.requestAnimationFrame(loop);
};
handle.value = window.requestAnimationFrame(loop);
return handle;
}
};
class BgImageSlider extends Component {
static propTypes = {
imageSlides: PropTypes.array,
};
static defaultProps = {
imageSlides: [],
};
constructor({ imageSlides }) {
super();
this.state = {
currentIndex: 0,
lastSlide: imageSlides.length - 1,
};
}
// Checks to see if the current image is the
// last image so that it can go to the first slide, otherwise
// update the currentIndex
// This function will be called with a timer to run every x amount
// of seconds.
goToNextSlide = () => {
const { currentIndex, lastSlide } = this.state;
if (currentIndex === lastSlide) {
return this.setState({
currentIndex: 0,
});
}
// update the currentIndex
return this.setState(prevState => ({
currentIndex: prevState.currentIndex + 1,
}));
};
// This function renders out the slides. It contains a map of the images
// from the array. Then it sets an isActive class based on the current
// position. At the end there is a timer that will run goToNextSlide after
// 10 seconds
renderSlides = () => {
const { currentIndex } = this.state;
const { imageSlides } = this.props;
const slides = imageSlides.map((image, i) => {
// If the current slide matches the active slide, set an isActive prop
const isActive = currentIndex === i;
return (
// Each item requires a unique key. Also we are controling the opactiy prop from
// styled components in the first few lines of the document
<SlideContainer key={image.asset._id}>
<Img fluid={image.asset.fluid} />
</SlideContainer>
);
});
// Runs the goToNextSlide function every 10 seconds
// setTimeout(this.goToNextSlide, 3000);
return slides;
};
render() {
const { currentIndex } = this.state;
requestTimeout(this.goToNextSlide, 5000);
// display the renderSlides function within a Slider styled-component
return <Slider currentIndex={currentIndex}>{this.renderSlides()}</Slider>;
}
}
export default BgImageSlider;
const IndexPage = ({ data, errors }) => {
// showSlides({ imageBgNodes });
if (errors) {
return (
<Layout>
<GraphQLErrorList errors={errors} />
</Layout>
);
}
const site = data && data.site;
const postNodes = data && data.posts && mapEdgesToNodes(data.posts);
const projectNodes = data && data.projects && mapEdgesToNodes(data.projects);
const imageBgNodes = site && site.bgImages;
if (!site) {
throw new Error('Missing "Site settings". Open the studio at http://localhost:3333 and add "Site settings" data');
}
return (
<Layout>
<SEO title={site.title} description={site.description} keywords={site.keywords} />
<BgImageSlider imageSlides={imageBgNodes} />
<Container>
<h1 hidden>Welcome to {site.title}</h1>
{projectNodes && projectNodes.length > 0 && (
<ProjectPreviewGrid title="Latest projects" nodes={projectNodes} browseMoreHref="/projects/" />
)}
{postNodes && postNodes.length > 0 && (
<BlogPostPreviewGrid title="Latest blog posts" nodes={postNodes} browseMoreHref="/blog/" />
)}
</Container>
</Layout>
);
};
export default IndexPage;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment