Merged in fix/sw-1127-image-fixes (pull request #1123)

Fix/sw-1127 image fixes for lightbox

* fix(SW-1127): move back to top button behind lightbox

* fix(SW-1127): don't loop lightbox thumbnails

* fix(SW-1127): nicer animation in the gallery

This both fixes a bug in the gallery where the animation in the carousel
didn't work so good and also animates the images different directions
depending on if the user go left or right.


Approved-by: Matilda Landström
This commit is contained in:
Niclas Edenvin
2025-01-07 07:56:17 +00:00
parent f2e29ae049
commit dca02b90f0
5 changed files with 60 additions and 13 deletions

View File

@@ -123,6 +123,7 @@
--booking-widget-z-index: 10;
--booking-widget-open-z-index: 100;
--dialog-z-index: 9;
--back-to-top-button: 80;
--sidepeek-z-index: 100;
--lightbox-z-index: 150;
--default-modal-overlay-z-index: 100;

View File

@@ -1,5 +1,6 @@
"use client"
import { AnimatePresence, motion } from "framer-motion"
import { useState } from "react"
import ArrowRightIcon from "@/components/Icons/ArrowRight"
import CloseIcon from "@/components/Icons/Close"
@@ -20,10 +21,35 @@ export default function FullView({
currentIndex,
totalImages,
}: FullViewProps) {
const [animateLeft, setAnimateLeft] = useState(true)
function handleSwipe(offset: number) {
if (offset > 30) onPrev()
if (offset < -30) onNext()
}
function handleNext() {
setAnimateLeft(true)
onNext()
}
function handlePrev() {
setAnimateLeft(false)
onPrev()
}
const variants = {
initial: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? 300 : -300,
}),
animate: { opacity: 1, x: 0 },
exit: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? -300 : 300,
}),
}
return (
<div className={styles.fullViewContainer}>
<Button
@@ -48,13 +74,14 @@ export default function FullView({
</span>
</div>
<div className={styles.fullViewImageContainer}>
<AnimatePresence initial={false} custom={currentIndex}>
<AnimatePresence initial={false} custom={animateLeft}>
<motion.div
key={image.imageSizes.medium}
custom={currentIndex}
initial={{ opacity: 0, x: 300 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -300 }}
custom={animateLeft}
variants={variants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className={styles.fullViewImage}
drag="x"
@@ -78,13 +105,13 @@ export default function FullView({
<motion.button
className={`${styles.navigationButton} ${styles.fullViewPrevButton}`}
onClick={onPrev}
onClick={handlePrev}
>
<ArrowRightIcon color="burgundy" className={styles.leftTransformIcon} />
</motion.button>
<motion.button
className={`${styles.navigationButton} ${styles.fullViewNextButton}`}
onClick={onNext}
onClick={handleNext}
>
<ArrowRightIcon color="burgundy" />
</motion.button>

View File

@@ -1,5 +1,6 @@
"use client"
import { AnimatePresence, motion } from "framer-motion"
import { useState } from "react"
import { useIntl } from "react-intl"
import { ChevronLeftIcon } from "@/components/Icons"
@@ -21,12 +22,13 @@ export default function Gallery({
selectedImage,
}: GalleryProps) {
const intl = useIntl()
const [animateLeft, setAnimateLeft] = useState(true)
const mainImage = selectedImage || images[0]
const mainImageIndex = images.findIndex((img) => img === mainImage)
function getThumbImages() {
const thumbs = []
for (let i = 1; i <= 5; i++) {
for (let i = 1; i <= Math.min(5, images.length); i++) {
const index = (mainImageIndex + i) % images.length
thumbs.push(images[index])
}
@@ -34,15 +36,29 @@ export default function Gallery({
}
function handleNext() {
setAnimateLeft(true)
const nextIndex = (mainImageIndex + 1) % images.length
onSelectImage(images[nextIndex])
}
function handlePrev() {
setAnimateLeft(false)
const prevIndex = (mainImageIndex - 1 + images.length) % images.length
onSelectImage(images[prevIndex])
}
const variants = {
initial: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? 300 : -300,
}),
animate: { opacity: 1, x: 0 },
exit: (animateLeft: boolean) => ({
opacity: 0,
x: animateLeft ? -300 : 300,
}),
}
return (
<div className={styles.galleryContainer}>
<Button
@@ -72,13 +88,15 @@ export default function Gallery({
)}
</div>
<div className={styles.mainImageWrapper}>
<AnimatePresence initial={false} mode="wait">
<AnimatePresence initial={false} custom={animateLeft}>
<motion.div
key={mainImage.imageSizes.medium}
className={styles.mainImageContainer}
initial={{ opacity: 0, x: 300 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -300 }}
custom={animateLeft}
variants={variants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
>
<Image

View File

@@ -108,6 +108,7 @@
height: 100%;
will-change: transform;
overflow: hidden;
position: absolute;
}
.mainImageContainer img,

View File

@@ -5,7 +5,7 @@
align-items: flex-end;
position: fixed;
bottom: 20px;
z-index: 1000;
z-index: var(--back-to-top-button);
background-color: var(--Base-Surface-Primary-light-Normal);
color: var(--Base-Button-Secondary-On-Fill-Normal);
border: 2px solid var(--Base-Button-Secondary-On-Fill-Normal);