diff --git a/frontend/src/static/js/components/media-page/MediaPage.scss b/frontend/src/static/js/components/media-page/MediaPage.scss index 2f5f99f..5b2280c 100755 --- a/frontend/src/static/js/components/media-page/MediaPage.scss +++ b/frontend/src/static/js/components/media-page/MediaPage.scss @@ -522,6 +522,7 @@ display: block; img { + cursor: pointer; position: relative; display: block; max-width: 100%; @@ -530,6 +531,100 @@ } } +// .viewer-image-container img { +// cursor: pointer; +// width: 100%; +// max-width: 600px; +// display: block; +// margin: 0 auto; +// } + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.slideshow-container { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 90%; + max-width: 900px; +} + +.slideshow-image img { + width: 100%; + max-height: 100vh; + border-radius: 0; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); +} + +.arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: rgba(255, 255, 255, 0.6); + border: none; + color: black; + font-size: 2rem; + cursor: pointer; + padding: 10px; + border-radius: 50%; + z-index: 1010; + transition: 0.2s ease; +} + +.arrow:hover { + background: rgba(255, 255, 255, 0.9); +} + +.arrow.left { + left: -50px; +} + +.arrow.right { + right: -50px; +} + +.dots { + position: fixed; /* Make the dots container fixed to always be under the image */ + bottom: 20%; /* Adjust this to control the vertical spacing */ + left: 50%; /* Center the dots horizontally */ + transform: translateX(-50%); /* Center the dots container */ + display: flex; + gap: 10px; + justify-content: center; + z-index: 1000; /* Ensure it stays above the background */ +} + +.dot { + width: 12px; + height: 12px; + background: rgba(255, 255, 255, 0.6); + border-radius: 50%; + cursor: pointer; + transition: 0.2s ease; +} + +.dot.active { + background: rgba(255, 255, 255, 1); +} + +.dot:hover { + background: rgba(255, 255, 255, 0.8); +} + + + .viewer-container .player-container { @media screen and (min-width: 480px) { border-radius: 10px; diff --git a/frontend/src/static/js/components/media-viewer/ImageViewer.js b/frontend/src/static/js/components/media-viewer/ImageViewer.js index 534d2a4..cb8c4a4 100755 --- a/frontend/src/static/js/components/media-viewer/ImageViewer.js +++ b/frontend/src/static/js/components/media-viewer/ImageViewer.js @@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { SiteContext } from '../../utils/contexts/'; import { MediaPageStore } from '../../utils/stores/'; -export default function ImageViewer(props) { +export default function ImageViewer() { const site = useContext(SiteContext); let initialImage = getImageUrl(); @@ -11,6 +11,9 @@ export default function ImageViewer(props) { initialImage = initialImage ? initialImage : ''; const [image, setImage] = useState(initialImage); + const [slideshowItems, setSlideshowItems] = useState([]); + const [isModalOpen, setIsModalOpen] = useState(false); + const [currentIndex, setCurrentIndex] = useState(0); function onImageLoad() { setImage(getImageUrl()); @@ -19,34 +22,91 @@ export default function ImageViewer(props) { function getImageUrl() { const media_data = MediaPageStore.get('media-data'); - let imgUrl = 'string' === typeof media_data.poster_url ? media_data.poster_url.trim() : ''; - - if ('' === imgUrl) { - imgUrl = 'string' === typeof media_data.thumbnail_url ? media_data.thumbnail_url.trim() : ''; - } - - if ('' === imgUrl) { - imgUrl = - 'string' === typeof MediaPageStore.get('media-original-url') - ? MediaPageStore.get('media-original-url').trim() - : ''; - } - - if ('' === imgUrl) { - return '#'; - } + let imgUrl = + media_data.poster_url?.trim() || + media_data.thumbnail_url?.trim() || + MediaPageStore.get('media-original-url')?.trim() || + '#'; return site.url + '/' + imgUrl.replace(/^\//g, ''); } + const fetchSlideShowItems = () => { + const media_data = MediaPageStore.get('media-data'); + const items = media_data.slideshow_items; + if (Array.isArray(items)) { + setSlideshowItems(items); + } + }; + + useEffect(() => { + if (image) { + fetchSlideShowItems(); + } + }, [image]); + useEffect(() => { MediaPageStore.on('loaded_image_data', onImageLoad); return () => MediaPageStore.removeListener('loaded_image_data', onImageLoad); }, []); + const handleNext = () => { + setCurrentIndex((prevIndex) => (prevIndex + 1) % slideshowItems.length); + }; + + const handlePrevious = () => { + setCurrentIndex((prevIndex) => + (prevIndex - 1 + slideshowItems.length) % slideshowItems.length + ); + }; + + const handleDotClick = (index) => { + setCurrentIndex(index); + }; + + return !image ? null : ( -