diff --git a/src/components/Wallet/VerticalSlide/Table.tsx b/src/components/Wallet/VerticalSlide/Table.tsx new file mode 100644 index 00000000..00fb4f8b --- /dev/null +++ b/src/components/Wallet/VerticalSlide/Table.tsx @@ -0,0 +1,105 @@ +import { type RefObject, useEffect, useState } from 'react' +import { ButtonBase, Grid, Typography } from '@mui/material' +import type { BaseBlock } from '@/components/Home/types' +import BracketLeft from '@/public/images/Wallet/VerticalSlide/bracket-left.svg' +import RecoveryIcon from '@/public/images/Wallet/VerticalSlide/recovery.svg' +import ScanIcon from '@/public/images/Wallet/VerticalSlide/scan.svg' +import MultipleKeysIcon from '@/public/images/Wallet/VerticalSlide/multiple-keys.svg' +import BracketRight from '@/public/images/Wallet/VerticalSlide/bracket-right.svg' +import css from './styles.module.css' +import useScrollProgress from '@/hooks/useScrollProgress' +import { selectIndex } from '@/lib/Wallet/selectIndex' + +const icons = [, , ] + +const indexToScrollProgress = (index: number) => { + if (index === 0) { + return 0.1 + } else if (index === 1) { + return 0.4 + } else { + return 0.5 + } +} + +const Table = ({ items = [], sectionRef }: { items: BaseBlock['items']; sectionRef: RefObject }) => { + const [selectedIndex, setSelectedIndex] = useState(0) + const { scrollYProgress } = useScrollProgress(sectionRef) + + const itemsImages = items.map((item) => item.image) + const selectedImage = itemsImages[selectedIndex] + + const handleCardClick = (index: number) => { + setSelectedIndex(index) + + // Move the scroll to the selected index according to indexToScrollProgress function + if (sectionRef.current) { + const sectionTop = sectionRef.current.getBoundingClientRect().top + window.scrollY + const sectionHeight = sectionRef.current.scrollHeight + + const offset = indexToScrollProgress(index) * sectionHeight + + // @ts-ignore + window.scrollTo({ top: sectionTop + offset, behavior: 'instant' }) + } + } + + useEffect(() => { + const handleScroll = () => { + const newIndex = selectIndex(scrollYProgress.get()) + setSelectedIndex(newIndex) + } + + const unsubscribe = scrollYProgress.on('change', handleScroll) + + return () => { + unsubscribe() + } + }, [scrollYProgress, items.length]) + + return ( + + +
+ + {icons.map((icon, index) => ( + + {icon} + + ))} + +
+ + {selectedImage ? {selectedImage.alt} : null} +
+ + +
+ {items.map((item, index) => { + const { title, text } = item + + return ( + + handleCardClick(index)} + disableRipple + className={`${css.card} ${index === selectedIndex ? css.selected : ''}`} + > + {title} + + {text && ( + + {text} + + )} + + + ) + })} +
+
+
+ ) +} + +export default Table diff --git a/src/components/Wallet/VerticalSlide/index.tsx b/src/components/Wallet/VerticalSlide/index.tsx index ad19df6a..b4e3aa14 100644 --- a/src/components/Wallet/VerticalSlide/index.tsx +++ b/src/components/Wallet/VerticalSlide/index.tsx @@ -1,82 +1,24 @@ -import { useEffect, useState } from 'react' -import { ButtonBase, Container, Grid, Typography } from '@mui/material' +import dynamic from 'next/dynamic' +import { useRef } from 'react' +import { Container, Typography } from '@mui/material' import type { BaseBlock } from '@/components/Home/types' -import BracketLeft from '@/public/images/Wallet/VerticalSlide/bracket-left.svg' -import RecoveryIcon from '@/public/images/Wallet/VerticalSlide/recovery.svg' -import ScanIcon from '@/public/images/Wallet/VerticalSlide/scan.svg' -import MultipleKeysIcon from '@/public/images/Wallet/VerticalSlide/multiple-keys.svg' -import BracketRight from '@/public/images/Wallet/VerticalSlide/bracket-right.svg' import layoutCss from '@/components/common/styles.module.css' import css from './styles.module.css' -const icons = [, , ] +const Table = dynamic(() => import('./Table')) const VerticalSlide = ({ title, items = [] }: BaseBlock) => { - const [selectedIndex, setSelectedIndex] = useState(0) - - const itemsImages = items.map((item) => item.image) - const selectedImage = itemsImages[selectedIndex] - - const handleCardClick = (index: number) => { - setSelectedIndex(index) - } - - // Change index every 5 seconds - useEffect(() => { - const interval = setInterval(() => { - setSelectedIndex((prevIndex) => (prevIndex + 1) % items?.length) - }, 5000) - - return () => clearInterval(interval) // Cleanup interval on component unmount - }, [items.length]) + const sectionRef = useRef(null) return ( - - - {title} - - - - -
- - {icons.map((icon, index) => ( - - {icon} - - ))} - -
- - {selectedImage ? {selectedImage.alt} : null} -
- - -
- {items.map((item, index) => { - const { title, text } = item - - return ( - - handleCardClick(index)} - disableRipple - className={`${css.card} ${index === selectedIndex ? css.selected : ''}`} - > - {title} - - {text && ( - - {text} - - )} - - - ) - })} -
-
-
+ +
+ + {title} + + + + ) } diff --git a/src/components/Wallet/VerticalSlide/styles.module.css b/src/components/Wallet/VerticalSlide/styles.module.css index 53baa4cb..108a2185 100644 --- a/src/components/Wallet/VerticalSlide/styles.module.css +++ b/src/components/Wallet/VerticalSlide/styles.module.css @@ -44,6 +44,21 @@ } @media (min-width: 900px) { + .sectionContainer { + height: 240vh; + } + + .stickyContainer { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + position: sticky; + top: 0; + overflow: hidden; + } + .title { margin-bottom: 80px; } diff --git a/src/components/Wallet/VerticalStack/Table.tsx b/src/components/Wallet/VerticalStack/Table.tsx new file mode 100644 index 00000000..12aa59b3 --- /dev/null +++ b/src/components/Wallet/VerticalStack/Table.tsx @@ -0,0 +1,53 @@ +import { useEffect, useState, type ReactElement, type RefObject } from 'react' +import { Grid, Typography } from '@mui/material' +import useScrollProgress from '@/hooks/useScrollProgress' +import { selectIndex } from '@/lib/Wallet/selectIndex' +import type { BaseBlock } from '@/components/Home/types' +import css from './styles.module.css' + +export const GridItem = ({ + image, + title, + text, + isSelected, +}: Partial & { isSelected: boolean }): ReactElement => ( + + {image ? : null} + + {title} + + {text && ( + + {text} + + )} + +) + +const Table = ({ items = [], sectionRef }: { items: BaseBlock['items']; sectionRef: RefObject }) => { + const [selectedIndex, setSelectedIndex] = useState(0) + const { scrollYProgress } = useScrollProgress(sectionRef) + + useEffect(() => { + const handleScroll = () => { + const newIndex = selectIndex(scrollYProgress.get()) + setSelectedIndex(newIndex) + } + + const unsubscribe = scrollYProgress.on('change', handleScroll) + + return () => { + unsubscribe() + } + }, [scrollYProgress, items.length]) + + return ( +
+ {items.map((item, index) => ( + + ))} +
+ ) +} + +export default Table diff --git a/src/components/Wallet/VerticalStack/index.tsx b/src/components/Wallet/VerticalStack/index.tsx index 3122cc4a..1e7834f8 100644 --- a/src/components/Wallet/VerticalStack/index.tsx +++ b/src/components/Wallet/VerticalStack/index.tsx @@ -1,51 +1,42 @@ -import type { DetailedHTMLProps, ReactElement, SourceHTMLAttributes } from 'react' +import dynamic from 'next/dynamic' +import { useRef, type DetailedHTMLProps, type SourceHTMLAttributes } from 'react' import { Container, Grid, Typography } from '@mui/material' import type { BaseBlock } from '@/components/Home/types' import layoutCss from '@/components/common/styles.module.css' import css from './styles.module.css' +const Table = dynamic(() => import('./Table')) + type VideoEmbed = { sources: Array, HTMLSourceElement>> } -export const GridItem = ({ image, title, text }: Partial): ReactElement => ( - - {image ? : null} - - {title} - - {text && ( - - {text} - - )} - -) - -const VerticalStack = ({ title, video, items = [] }: BaseBlock & { video: VideoEmbed }) => ( - - - - {video && ( - - )} - - {title} - - - -
- {items.map((item, index) => ( - - ))} -
-
-
-
-) +const VerticalStack = ({ title, video, items = [] }: BaseBlock & { video: VideoEmbed }) => { + const sectionRef = useRef(null) + + return ( + +
+ + + {video && ( + + )} + + {title} + + + +
+ + + + + ) +} export default VerticalStack diff --git a/src/components/Wallet/VerticalStack/styles.module.css b/src/components/Wallet/VerticalStack/styles.module.css index 4dbc8ad5..8f194383 100644 --- a/src/components/Wallet/VerticalStack/styles.module.css +++ b/src/components/Wallet/VerticalStack/styles.module.css @@ -11,15 +11,45 @@ flex-direction: column; gap: 16px; align-items: flex-start; - padding: 48px 40px; + padding: 32px; text-align: left; + position: relative; } .video { width: 144px; } +.card.selected::before { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 4px; + background-color: var(--mui-palette-primary-main); +} + +.selected { + color: var(--mui-palette-primary-main); +} + @media (min-width: 900px) { + .sectionContainer { + height: 240vh; + } + + .stickyContainer { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + position: sticky; + top: 0; + overflow: hidden; + } + .titleWrapper { display: flex; flex-direction: column; diff --git a/src/lib/Wallet/selectIndex.ts b/src/lib/Wallet/selectIndex.ts new file mode 100644 index 00000000..b46349e5 --- /dev/null +++ b/src/lib/Wallet/selectIndex.ts @@ -0,0 +1,9 @@ +export const selectIndex = (scrollYProgress: number) => { + if (scrollYProgress >= 0 && scrollYProgress <= 0.4) { + return 0 + } else if (scrollYProgress > 0.4 && scrollYProgress <= 0.6) { + return 1 + } else { + return 2 + } +}