Lag en lightbox med React
Lag en lightbox med React
av Ole Petter den 28. juli 2021
Sist oppdatert: 16 august, 2021 kl 08:21Contents
Kildekode
Kildekoden kan finnes her: https://github.com/olepetterkh91/react-bootstrap-lightbox
Les historien på engelsk her:
https://medium.com/@olepetterkh/create-a-simple-lightbox-with-react-abe04e3e6e7b
Create React App
npx create-react-app
I dette eksempelet brukes Bootstrap til CSS. Bootstrap er et css-rammeverk som gjør det kjapt og enkelt å lage en fin nettside. Det finnes også en React plugin for Bootstrap som legger til funksjoner slik som modal og responsiv navigeringsmeny.
Installer framer-motion
For animasjoner er framer-motion et populært alternativ i React, og det er relativt enkelt å bruke.
npm i framer-motion
App.js
import "./App.css";
import ImageGrid from './components/LightBox/ImageGrid'
function App() {
return (
<div className="container my-3">
<ImageGrid />
</div>
);
}
export default App;
App.css
@import url("https://pro.fontawesome.com/releases/v5.10.0/css/all.css");
.bg-transparent-dark {
background-color: rgba(0, 0, 0, 0.8);
}
.img-wrap {
opacity: 0.8 !important;
}
.img-fixed {
object-fit: cover;
width: 200px;
height: 200px;
}
.left-arrow {
position: fixed;
top: 50%;
left: 0px;
}
.right-arrow {
position: fixed;
top: 50%;
right: 0px;
}
.imageCount {
background-color: rgba(0, 0, 0, 0.85);
font-size: 1;
padding: 1rem;
position: fixed;
top: 0px;
left: 0px;
}
.closeButton {
background-color: rgba(0, 0, 0, 0.85);
font-size: 4rem;
padding: 1rem;
position: fixed;
top: 0px;
right: 0px;
}
.arrow-left,
.arrow-right {
background-color: rgba(0, 0, 0, 0.85);
cursor: pointer;
position: fixed;
top: 50%;
width: auto;
padding: 16px;
margin-top: -50px;
color: white;
font-weight: bold;
font-size: 20px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
-webkit-user-select: none;
}
@media screen and (max-width: 700px) {
.arrow-left, .arrow-right {
background-color: rgba(0, 0, 0, 0.45);
}
}
.arrow-right {
right: 0px;
}
.blocks-gallery-grid {
list-style: none;
}
.image-container {
position: relative;
}
.img-fixed-size {
object-fit: cover;
height:100px;
width: 300px;
}
.image-text {
position: absolute;
bottom: 0px;
width: 100%;
color: white;
padding: 1rem;
background-color: rgba(0, 0, 0, 0.5);
}
.img-fixed-size--wide {
object-fit: cover;
height: 300px;
width: 700px;
}
Sett opp en modal (Modal.js)
import React from "react";
import { motion } from "framer-motion";
const Modal = ({ selectedImg, selectedIndex, setSelectedIndex, images }) => {
const clickHandler = (e) => {
if (e.target.classList.contains("backdrop")) {
setSelectedIndex(-1);
}
};
function nextImage() {
let imageIndex = selectedIndex
if (imageIndex >= images.length - 1) {
imageIndex = 0
} else {
imageIndex = selectedIndex + 1
}
setSelectedIndex(imageIndex)
}
function previousImage() {
let imageIndex = selectedIndex
if (imageIndex > 0) {
imageIndex = selectedIndex - 1
} else {
imageIndex = images.length - 1
}
setSelectedIndex(imageIndex)
}
return (
<motion.div
className="modal show backdrop bg-transparent-dark"
style={{display: "block"}}
onClick={clickHandler}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
<div className="modal-dialog modal-dialog-centered modal-xl">
<div className="modal-content" style={{ border: "none", backgroundColor: "black" }}>
<motion.img
src={selectedImg ? selectedImg : "https://smorasstats.com/v4/wp-content/uploads/2020/06/71951528_2527097874023921_5910925260533792768_o.jpg"}
alt="Modal"
initial={{ width: "110%" }}
animate={{ width: "100%" }}
/>
</div>
</div>
<div className="imageCount text-white">
{selectedIndex + 1} / {images?.length}
</div>
<div className="closeButton">
<button
onClick={() => setSelectedIndex(-1)}
type="button"
class="close"
style={{ color: "white" }}
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="lightbox-navigation">
<div onClick={previousImage} className="arrow-left">
<i className="fas fa-chevron-left"></i>
</div>
<div onClick={nextImage} className="arrow-right">
<i className="fas fa-chevron-right"></i>
</div>
</div>
</motion.div>
);
};
export default Modal;
ImageGrid.js
import { useEffect, useState } from "react";
import LightBox from "./Lightbox";
function ImageGrid() {
const [images, setImages] = useState([])
useEffect(() => {
async function getData() {
const response = await fetch("https://smorasstats.com/v4/wp-json/wp/v2/gallery")
const data = await response.json()
const imageUrls = data?.map((post) => post?.acf?.galleri_poster)
setImages(imageUrls)
}
getData()
}, [])
return (
<div>
<LightBox images={images} />
</div>
)
}
export default ImageGrid
LightBox.js
import { useState } from "react";
import Modal from "./Modal";
import LightBoxListTemplate from "./templates/LightboxListTemplate";
function LightBox({images}) {
const [selectedIndex, setSelectedIndex] = useState(null)
return (
<div>
<div className="row">
{images?.map((image, index) => <LightBoxListTemplate key={index} image={image} index={index} setSelectedIndex={setSelectedIndex} />)}
</div>
{selectedIndex >= 0 && <Modal images={images} selectedImg={images[selectedIndex]} selectedIndex={selectedIndex} setSelectedIndex={setSelectedIndex} />}
</div>
)
}
export default LightBox
LightBoxListTemplate.js
function LightBoxListTemplate({image, index, setSelectedIndex, setSelectedImage}) {
return (
<div className="col-md-4 col-4">
<img src={image ? image : "https://smorasstats.com/v4/wp-content/uploads/2020/06/71951528_2527097874023921_5910925260533792768_o.jpg"} alt="" className="img-fixed-size img-fluid" onClick={() => setSelectedIndex(index)} />
</div>
)
}
export default LightBoxListTemplate
Legg igjen en kommentar
Søk på siden
Siste innlegg
Siste kommentarer
Arkiv
Kategorier