Created
August 21, 2020 17:41
-
-
Save JohanAltamar/2e1ac39ce86c2b36ad6ba4881ca10adf to your computer and use it in GitHub Desktop.
Carousel component to use inside your React, Gatsby projects. An example can be found on https://johanaltamar.com/portfolio/delivree
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
* { | |
box-sizing: border-box; | |
} | |
/* Slideshow container */ | |
.slideshow-container { | |
position: relative; | |
margin: auto; | |
} | |
.slideshow-container .text { | |
width: 100%; | |
background-color: rgba(0, 0, 0, 0.8); | |
} | |
.slideshow-container-portrait, .slideshow-container-landscape { | |
max-width: 100%; | |
} | |
.slideshow-container-portrait img, .slideshow-container-landscape img { | |
max-height: 70vh; | |
margin: auto; | |
border: 1px solid #bbbbbb; | |
} | |
@media screen and (min-width: 500px) { | |
.slideshow-container-portrait { | |
max-width: 75%; | |
} | |
} | |
@media screen and (min-width: 700px) { | |
.slideshow-container-portrait { | |
max-width: 60%; | |
} | |
} | |
@media screen and (min-width: 800px) { | |
.slideshow-container-portrait { | |
max-width: 50%; | |
} | |
} | |
/* Hide the images by default */ | |
.mySlides { | |
display: none; | |
} | |
/* Next & previous buttons */ | |
button { | |
border: none; | |
background-color: transparent; | |
} | |
.prev, | |
.next { | |
cursor: pointer; | |
position: absolute; | |
top: 50%; | |
width: auto; | |
margin-top: -22px; | |
padding: 16px; | |
color: grey; | |
font-weight: bold; | |
font-size: 18px; | |
transition: 0.6s ease; | |
border-radius: 0 3px 3px 0; | |
user-select: none; | |
} | |
/* Position the "next button" to the right */ | |
.next { | |
right: 0; | |
border-radius: 3px 0 0 3px; | |
} | |
/* On hover, add a black background color with a little bit see-through */ | |
.prev:hover, | |
.next:hover { | |
background-color: rgba(0, 0, 0, 0.8); | |
color: white; | |
} | |
/* Caption text */ | |
.text { | |
color: #f2f2f2; | |
font-size: 15px; | |
padding: 8px 12px; | |
position: absolute; | |
bottom: 8px; | |
width: 100%; | |
text-align: center; | |
} | |
/* Number text (1/3 etc) */ | |
.numbertext { | |
background-color: rgba(0, 0, 0, 0.7); | |
color: #f2f2f2; | |
font-size: 12px; | |
font-weight: bold; | |
padding: 8px 12px; | |
position: absolute; | |
top: 0; | |
} | |
/* The dots/bullets/indicators */ | |
.dot { | |
cursor: pointer; | |
height: 15px; | |
width: 15px; | |
margin: 0 2px; | |
background-color: #bbb; | |
border-radius: 50%; | |
display: inline-block; | |
transition: background-color 0.6s ease; | |
} | |
.active, | |
.dot:hover { | |
background-color: #717171; | |
} | |
/* Fading animation */ | |
.fade { | |
-webkit-animation-name: fade; | |
-webkit-animation-duration: 1.5s; | |
animation-name: fade; | |
animation-duration: 1.5s; | |
} | |
.block { | |
display: flex; | |
} | |
.block:not(:last-child) { | |
margin-bottom: 0.5rem; | |
} | |
.none { | |
display: none; | |
} | |
@-webkit-keyframes fade { | |
from { | |
opacity: 0.4; | |
} | |
to { | |
opacity: 1; | |
} | |
} | |
@keyframes fade { | |
from { | |
opacity: 0.4; | |
} | |
to { | |
opacity: 1; | |
} | |
} |
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, { useState } from "react" | |
import PropTypes from "prop-types" | |
import "./styles/portfolioProjectCarousel.css" | |
const Carousel = ({ images, orientation, title }) => { | |
const [slideIndex, setSlideIndex] = useState(1) | |
const plusSlides = step => { | |
setSlideIndex(index => { | |
if (index + step > images.length) { | |
return 1 | |
} else if (index + step < 1) { | |
return images.length | |
} | |
return index + step | |
}) | |
} | |
const currentSlide = slide => { | |
setSlideIndex(slide) | |
} | |
return ( | |
<> | |
{title && <h4 style={{ padding: "0px 0px 8px 16px" }}>{title}</h4>} | |
<div className={`slideshow-container slideshow-container-${orientation}`}> | |
{images.map((image, index) => ( | |
<div | |
key={index} | |
className={`mySlides fade ${ | |
slideIndex === index + 1 ? "block" : "none" | |
}`} | |
> | |
<div className="numbertext"> | |
{index + 1} / {images.length} | |
</div> | |
<img src={image.url} alt={image.title} /> | |
<div className="text">{image.title}</div> | |
</div> | |
))} | |
<button className="prev" onClick={() => plusSlides(-1)}> | |
❮ | |
</button> | |
<button className="next" onClick={() => plusSlides(1)}> | |
❯ | |
</button> | |
</div> | |
<div style={{ textAlign: "center" }}> | |
{images.map((image, idx) => ( | |
<button | |
key={idx} | |
className={`dot ${slideIndex === idx + 1 ? "active" : undefined}`} | |
aria-label={`Image ${idx + 1}`} | |
onClick={() => currentSlide(idx + 1)} | |
></button> | |
))} | |
</div> | |
</> | |
) | |
} | |
Carousel.propTypes = { | |
images: PropTypes.array.isRequired, | |
orientation: PropTypes.oneOf(["portrait", "landscape"]).isRequired, | |
title: PropTypes.string, | |
} | |
export default Carousel |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment