From 9e024ef1eb5053dc435dc4c55ef09d4456c8681d Mon Sep 17 00:00:00 2001 From: Benno Tielen Date: Tue, 26 Nov 2024 16:21:12 +0100 Subject: [PATCH] fix: Gallery --- src/components/Gallery/AutoScroll.tsx | 67 +++++++++++++++++++ src/components/Gallery/Fullscreen.tsx | 30 +++++++++ src/components/Gallery/Gallery.stories.tsx | 35 ++++++++++ src/components/Gallery/Gallery.tsx | 66 ++++++++++-------- src/components/Gallery/autoscroll.module.scss | 4 ++ src/components/Gallery/fullscreen.module.scss | 42 ++++++++++++ src/components/Gallery/styles.module.scss | 57 ---------------- src/utils/dto/gallery.ts | 4 +- 8 files changed, 219 insertions(+), 86 deletions(-) create mode 100644 src/components/Gallery/AutoScroll.tsx create mode 100644 src/components/Gallery/Fullscreen.tsx create mode 100644 src/components/Gallery/Gallery.stories.tsx create mode 100644 src/components/Gallery/autoscroll.module.scss create mode 100644 src/components/Gallery/fullscreen.module.scss diff --git a/src/components/Gallery/AutoScroll.tsx b/src/components/Gallery/AutoScroll.tsx new file mode 100644 index 0000000..bc38716 --- /dev/null +++ b/src/components/Gallery/AutoScroll.tsx @@ -0,0 +1,67 @@ +import styles from "./autoscroll.module.scss" +import { useEffect, useRef, useState } from 'react' + +type AutoScrollProps = { + isScrolling: boolean + onTouch?: () => void + children: JSX.Element +} +/** + * This component autoscroll the content from left to right + * automatically + * + */ +export const AutoScroll = ({children, isScrolling, onTouch}: AutoScrollProps) => { + + const [step, setStep] = useState(0) + const [direction, setDirection] = useState<'left' | 'right'>('right') + const wrapper = useRef(null) + + useEffect(() => { + if(wrapper && wrapper.current) { + if (isScrolling) { + const scrollSpeed = 30; // 30px per second + const toScroll = wrapper.current.scrollWidth - window.innerWidth; + + // nothing to scroll + if (toScroll <= 0) { + return; + } + + const steps = toScroll/scrollSpeed * 1000 + + const t = setTimeout(() => { + let left = toScroll * step/steps + + if(wrapper.current) { + wrapper.current.scrollTo({ + left: left, + }) + } + + if(step >= steps) { + setDirection("left") + } + + if(step <= 0) { + setDirection("right") + } + + setStep(direction === "right" ? step + 1 : step - 1) + + return () => clearTimeout(t); + }, 1); + } + + }}, [wrapper, step, setStep, direction, setDirection]) + + return ( +
+ {children} +
+ ) +} \ No newline at end of file diff --git a/src/components/Gallery/Fullscreen.tsx b/src/components/Gallery/Fullscreen.tsx new file mode 100644 index 0000000..a311bbd --- /dev/null +++ b/src/components/Gallery/Fullscreen.tsx @@ -0,0 +1,30 @@ +import styles from './fullscreen.module.scss' +import Image, { StaticImageData } from 'next/image' + +type FullScreenProps = { + display: boolean + image: StaticImageData + alt?: string + closeClicked: () => void + nextClicked: () => void +} + +export const Fullscreen = ({display, image, closeClicked, alt, nextClicked}: FullScreenProps) => { + if(display) + return ( +
+
x
+ {alt +
+ ) +} \ No newline at end of file diff --git a/src/components/Gallery/Gallery.stories.tsx b/src/components/Gallery/Gallery.stories.tsx new file mode 100644 index 0000000..0565674 --- /dev/null +++ b/src/components/Gallery/Gallery.stories.tsx @@ -0,0 +1,35 @@ +import { Meta, StoryObj } from '@storybook/react' +import { Gallery } from './Gallery' +import chris from "./../../assets/christophorus.jpeg" + +const meta: Meta = { + component: Gallery, +} + +type Story = StoryObj; +export default meta + +export const Default: Story = { + args: { + items: [ + { + id: "1", + thumbnail: chris, + image: chris, + alt: "hallo" + }, + { + id: "2", + thumbnail: chris, + image: chris, + alt: "hallo" + }, + { + id: "3", + thumbnail: chris, + image: chris, + alt: "hallo" + } + ] + }, +} \ No newline at end of file diff --git a/src/components/Gallery/Gallery.tsx b/src/components/Gallery/Gallery.tsx index 5f6dbc2..990b60f 100644 --- a/src/components/Gallery/Gallery.tsx +++ b/src/components/Gallery/Gallery.tsx @@ -2,13 +2,15 @@ import styles from './styles.module.scss' import Image, { StaticImageData } from 'next/image' -import { useCallback, useState } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' +import { AutoScroll } from '@/components/Gallery/AutoScroll' +import { Fullscreen } from '@/components/Gallery/Fullscreen' type ImageType = { - url: string, + src: string, width: number, height: number -} +} | StaticImageData export type GalleryItem = { id: string; @@ -29,22 +31,32 @@ type GalleryProps = { const GalleryItem = ({ thumbnail, alt, onClick }: GalleryItemProps) => { return ( - {alt} + {alt} ) } export const Gallery = ({ items }: GalleryProps) => { - const [display, setDisplay] = useState(false) + const [displayFullscreen, setDisplayFullscreen] = useState(false) const [idx, setIdx] = useState(0) + const [isScrolling, setIsScrolling] = useState(true) const displayImage = useCallback((n: number) => { setIdx(n); - setDisplay(true); - }, [setDisplay, setIdx]); + setDisplayFullscreen(true); + setIsScrolling(false) + }, [setDisplayFullscreen, setIdx, setIsScrolling]); const next = useCallback(() => { setIdx((idx + 1) % items.length) }, [idx, setIdx, items]) + if(items.length == 0) { return null; } @@ -52,27 +64,27 @@ export const Gallery = ({ items }: GalleryProps) => { const { image, alt } = items[idx] return ( <> -
- {items.map((item, index) => - displayImage(index)} - key={item.id} - thumbnail={item.thumbnail} - alt={item.alt} - />)} -
- {display && -
-
setDisplay(false)}>x
- {alt} + setIsScrolling(false)} + > +
+ {items.map((item, index) => + displayImage(index)} + key={item.id} + thumbnail={item.thumbnail} + alt={item.alt} + />)}
- } +
+ + setDisplayFullscreen(false)} + nextClicked={next} + /> diff --git a/src/components/Gallery/autoscroll.module.scss b/src/components/Gallery/autoscroll.module.scss new file mode 100644 index 0000000..60a3c8a --- /dev/null +++ b/src/components/Gallery/autoscroll.module.scss @@ -0,0 +1,4 @@ +.wrapper { + overflow: scroll; + scrollbar-width: none; +} \ No newline at end of file diff --git a/src/components/Gallery/fullscreen.module.scss b/src/components/Gallery/fullscreen.module.scss new file mode 100644 index 0000000..7eb4219 --- /dev/null +++ b/src/components/Gallery/fullscreen.module.scss @@ -0,0 +1,42 @@ +@import "template.scss"; + +.display { + position: fixed; + top: 0; + left: 0; + z-index: 99; + width: 100vw; + height: 100vh; + background-color: rgba(63, 63, 63, 0.82); + backdrop-filter: blur(8px); + display: flex; + justify-content: center; + align-items: center; +} + +.displayImage { + display: block; + max-height: 90vh; + max-width: 90vw; + object-fit: contain; +} + +.close { + color: #ffffff; + font-weight: bold; + position: fixed; + top: 35px; + right: 35px; + background-color: $base-color; + border-radius: 50%; + width: 50px; + height: 50px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; +} + +.close:hover { + background-color: $shade1; +} \ No newline at end of file diff --git a/src/components/Gallery/styles.module.scss b/src/components/Gallery/styles.module.scss index c7c172c..999cf7d 100644 --- a/src/components/Gallery/styles.module.scss +++ b/src/components/Gallery/styles.module.scss @@ -4,66 +4,9 @@ display: flex; gap: 30px; flex-wrap: nowrap; - overflow: hidden; - --width: -500px; -} - -.display { - position: fixed; - top: 0; - left: 0; - z-index: 99; - width: 100vw; - height: 100vh; - background-color: rgba(63, 63, 63, 0.82); - backdrop-filter: blur(8px); - display: flex; justify-content: center; - align-items: center; -} - -.displayImage { - display: block; - max-height: 90vh; - max-width: 90vw; - object-fit: contain; -} - -.close { - color: #ffffff; - font-weight: bold; - position: fixed; - top: 10px; - right: 10px; - background-color: $base-color; - border-radius: 50%; - width: 50px; - height: 50px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; -} - -.close:hover { - background-color: $shade1; -} -@keyframes slide { - 0% { - transform: translateX(var(--width)); - } - 50% { - transform: translateX(0); - } - 100% { - transform: translateX(var(--width)); - } } .item { - animation-name: slide; - animation-duration: 60s; - animation-iteration-count: infinite; - animation-timing-function: linear; cursor: pointer; } \ No newline at end of file diff --git a/src/utils/dto/gallery.ts b/src/utils/dto/gallery.ts index f3d3784..99ec2da 100644 --- a/src/utils/dto/gallery.ts +++ b/src/utils/dto/gallery.ts @@ -23,12 +23,12 @@ export const transformGallery = (items: Items) => { alt: item.photo.alt, id: item.id, thumbnail: { - url: thumbnail, + src: thumbnail, width: tWidth, height: tHeight, }, image: { - url: image, + src: image, width: iWidth, height: iHeight }