1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00
vault-frontend/src/components/node/NodeImageSwiperBlock/index.tsx
2022-07-14 21:22:56 +07:00

133 lines
3.5 KiB
TypeScript

import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { observer } from 'mobx-react-lite';
import SwiperCore, { Keyboard, Navigation, Pagination, SwiperOptions } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';
import SwiperClass from 'swiper/types/swiper-class';
import { ImagePreloader } from '~/components/media/ImagePreloader';
import { INodeComponentProps } from '~/constants/node';
import { useModal } from '~/hooks/modal/useModal';
import { useImageModal } from '~/hooks/navigation/useImageModal';
import { useNodeImages } from '~/hooks/node/useNodeImages';
import { normalizeBrightColor } from '~/utils/color';
import styles from './styles.module.scss';
SwiperCore.use([Navigation, Pagination, Keyboard]);
interface IProps extends INodeComponentProps {}
const breakpoints: SwiperOptions['breakpoints'] = {
599: {
spaceBetween: 20,
},
};
const pagination = { type: 'fraction' as const };
const NodeImageSwiperBlock: FC<IProps> = observer(({ node }) => {
const [controlledSwiper, setControlledSwiper] = useState<SwiperClass | undefined>(undefined);
const showPhotoSwiper = useImageModal();
const { isOpened: isModalActive } = useModal();
const images = useNodeImages(node);
const keyboard = useMemo(
() => ({
enabled: !isModalActive,
onlyInViewport: true,
}),
[isModalActive]
);
const updateSwiper = useCallback(() => {
if (!controlledSwiper) return;
controlledSwiper.updateSlides();
controlledSwiper.updateSize();
controlledSwiper.update();
controlledSwiper.updateAutoHeight();
controlledSwiper.updateProgress();
}, [controlledSwiper]);
const onOpenPhotoSwipe = useCallback(
(index: number) => {
if (index !== controlledSwiper?.activeIndex && controlledSwiper?.slideTo) {
controlledSwiper.slideTo(index, 300);
return;
}
showPhotoSwiper(images, index);
},
[images, controlledSwiper, showPhotoSwiper]
);
useEffect(() => {
controlledSwiper?.slideTo(0, 0);
return () => controlledSwiper?.slideTo(0, 0);
}, [images, node?.id]);
useEffect(() => {
if (isModalActive) {
controlledSwiper?.keyboard.disable();
} else {
controlledSwiper?.keyboard.enable();
}
}, [isModalActive]);
if (!images?.length) {
return null;
}
if (images.length === 1) {
return (
<div className={styles.single}>
<ImagePreloader
file={images[0]}
onClick={() => onOpenPhotoSwipe(0)}
className={styles.image}
/>
</div>
);
}
return (
<div className={styles.wrapper}>
<Swiper
enabled={images.length > 1}
initialSlide={0}
slidesPerView="auto"
onSwiper={setControlledSwiper}
breakpoints={breakpoints}
pagination={pagination}
centeredSlides
observeSlideChildren
observeParents
observer
resizeObserver
watchOverflow
updateOnImagesReady
keyboard={keyboard}
grabCursor
autoHeight
zoom
navigation
>
{images.map((file, i) => (
<SwiperSlide className={styles.slide} key={file.id}>
<ImagePreloader
file={file}
onLoad={updateSwiper}
onClick={() => onOpenPhotoSwipe(i)}
className={styles.image}
color={normalizeBrightColor(file?.metadata?.dominant_color)}
/>
</SwiperSlide>
))}
</Swiper>
</div>
);
});
export { NodeImageSwiperBlock };