diff --git a/packages/ui/src/components/molecules/SliderDeck/SliderDeck.tsx b/packages/ui/src/components/molecules/SliderDeck/SliderDeck.tsx new file mode 100644 index 000000000..c3b2722d1 --- /dev/null +++ b/packages/ui/src/components/molecules/SliderDeck/SliderDeck.tsx @@ -0,0 +1,118 @@ +import React, { FC, useState, useRef } from 'react'; +import { styled } from 'styled-components'; + +import { SliderStop } from './SliderStop'; + +const SliderContainer = styled.div` + position: relative; + width: 628px; + padding: var(--Subscription-Years, 1px) 0px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 10px; + cursor: pointer; +`; + +const LineSegment = styled.div<{ isActive: boolean }>` + position: absolute; + height: 4px; + background-color: ${({ isActive, theme }) => + isActive + ? theme.palette.background.golden + : theme.palette.background.separator}; +`; + +const StopContainer = styled.div<{ left: string }>` + position: absolute; + top: -25px; + left: ${({ left }) => left}; +`; + +const TextContainer = styled.div` + margin-top: 8px; + color: ${({ theme }) => theme.palette.background.golden}; + font-family: 'Poppins', sans-serif; + font-size: 12px; + font-weight: 500; + line-height: 18px; + text-align: center; + width: 45px; + position: absolute; + top: 50px; +`; + +interface SliderProps { + selectedYear: number; +} + +export const SliderDeck: FC = ({ + selectedYear: initialSelectedYear, +}) => { + const [selectedYear, setSelectedYear] = useState(initialSelectedYear); + const sliderRef = useRef(null); + + const handleMouseMove = (event: MouseEvent) => { + if (sliderRef.current) { + const sliderRect = sliderRef.current.getBoundingClientRect(); + const mousePosition = + (event.clientX - sliderRect.left) / sliderRect.width; + const newSelectedYear = Math.round(mousePosition * 5); + setSelectedYear(newSelectedYear); + } + }; + + const stops = [ + { label: '1 Year', isActive: selectedYear >= 1 }, + { label: '2 Years', isActive: selectedYear >= 2 }, + { label: '3 Years', isActive: selectedYear >= 3 }, + { label: '4 Years', isActive: selectedYear >= 4 }, + { label: '5 Years', isActive: selectedYear >= 5 }, + ]; + + const stopPositions = ['0%', '25%', '50%', '75%', '100%']; + + return ( + { + sliderRef.current?.addEventListener('mousemove', handleMouseMove); + }} + onMouseUp={() => { + sliderRef.current?.removeEventListener('mousemove', handleMouseMove); + }} + onMouseLeave={() => { + sliderRef.current?.removeEventListener('mousemove', handleMouseMove); + }} + > + {stopPositions.map((_, index) => ( + index + 1} + style={{ + left: stopPositions[index], + width: + index < stopPositions.length - 1 + ? `calc(${stopPositions[index + 1]} - ${stopPositions[index]})` + : '0%', + }} + /> + ))} + {stops.map((stop, index) => ( + + setSelectedYear(index + 1)} + isSelected={selectedYear === index + 1} + />{' '} + {stop.isActive && {stop.label}} + + ))} + + ); +}; diff --git a/packages/ui/src/components/molecules/SliderDeck/SliderStop.tsx b/packages/ui/src/components/molecules/SliderDeck/SliderStop.tsx new file mode 100644 index 000000000..369d1c425 --- /dev/null +++ b/packages/ui/src/components/molecules/SliderDeck/SliderStop.tsx @@ -0,0 +1,110 @@ +import React, { CSSProperties, FC, useEffect, useState } from 'react'; +import { styled } from 'styled-components'; + +import { colors } from '../../../themes/color.styled'; + +export interface SliderStopProps { + Label: string; + isActive: boolean; + isSelected: boolean; + onClick: () => void; +} + +const ContainerStyle: CSSProperties = { + fontFamily: 'Poppins', + fontSize: '12px', + fontWeight: 500, + lineHeight: '18px', + textAlign: 'center', + width: '45px', + height: '66px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + alignItems: 'center', + position: 'absolute', + top: '0', + zIndex: 8, +}; + +const StyledContainer = styled.div<{ + isActive: boolean; + isSelected: boolean; + isHover: boolean; +}>` + width: ${({ isSelected }) => (isSelected ? '48px' : '40px')}; + height: ${({ isSelected }) => (isSelected ? '48px' : '40px')}; + border-radius: 50%; + margin-top: ${({ isActive, isSelected, isHover }) => { + if (isSelected) { + return '-1px'; + } + if (!isActive && isHover) { + return '0px'; + } + return '8px'; + }}; + border: ${({ isSelected }) => (isSelected ? '8px solid' : 'none')}; + border-color: ${({ isActive, isSelected, isHover }) => + isSelected || (!isActive && isHover) ? colors.active.main : 'inherit'}; + background: ${({ isActive, isSelected, isHover }) => + isActive || isSelected || isHover + ? colors.text.gold + : colors.background.separator}; +`; + +const TextStyle = (isSelected: boolean, isHover: boolean): CSSProperties => ({ + background: + isSelected && !isHover ? colors.text.gold : colors.background.muted, + WebkitBackgroundClip: 'text', + WebkitTextFillColor: 'transparent', + marginTop: '8px', + textAlign: 'center', + fontFamily: 'Poppins', + fontSize: '12px', + fontStyle: ' normal', + fontWeight: '500', + lineHeight: ' normal', +}); + +export const SliderStop: FC = ({ + Label, + isActive, + isSelected, + onClick, +}) => { + const [isHover, setIsHover] = useState(false); + + useEffect(() => { + if (!isActive) { + setIsHover(false); + } + }, [isActive]); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.key === ' ') { + onClick(); + } + }; + + return ( +
setIsHover(true)} + onClick={onClick} + onMouseLeave={() => setIsHover(false)} + onKeyDown={handleKeyDown} + role="button" + tabIndex={0} + > + +
+ {!isActive && (isHover || isSelected) ? Label : ''} +
+
+ ); +}; diff --git a/packages/ui/src/components/molecules/SliderDeck/index.ts b/packages/ui/src/components/molecules/SliderDeck/index.ts new file mode 100644 index 000000000..8044c1feb --- /dev/null +++ b/packages/ui/src/components/molecules/SliderDeck/index.ts @@ -0,0 +1 @@ +export * from './SliderDeck'; diff --git a/packages/ui/src/components/molecules/index.ts b/packages/ui/src/components/molecules/index.ts index 5890307f7..339246dcc 100644 --- a/packages/ui/src/components/molecules/index.ts +++ b/packages/ui/src/components/molecules/index.ts @@ -40,4 +40,6 @@ export * from './Topbar'; export * from './UpdateBar'; export * from './WallectConnect'; export * from './WalletDialogMainContainer'; +export * from './SliderDeck/SliderStop'; export * from './SimpleJsonView'; +export * from './SliderDeck'; diff --git a/packages/ui/src/stories/molecules/SliderDeck.stories.tsx b/packages/ui/src/stories/molecules/SliderDeck.stories.tsx new file mode 100644 index 000000000..5d8b57a1e --- /dev/null +++ b/packages/ui/src/stories/molecules/SliderDeck.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { SliderDeck } from '../../components'; + +const meta: Meta = { + component: SliderDeck, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + selectedYear: 1, + }, +}; + +export const TwoYears: Story = { + args: { + selectedYear: 2, + }, +}; + +export const ThreeYears: Story = { + args: { + selectedYear: 3, + }, +}; + +export const FourYears: Story = { + args: { + selectedYear: 4, + }, +}; + +export const FiveYears: Story = { + args: { + selectedYear: 5, + }, +}; diff --git a/packages/ui/src/stories/molecules/SliderStop.stories.tsx b/packages/ui/src/stories/molecules/SliderStop.stories.tsx new file mode 100644 index 000000000..b5d242168 --- /dev/null +++ b/packages/ui/src/stories/molecules/SliderStop.stories.tsx @@ -0,0 +1,26 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { SliderStop } from '../../components'; + +const meta: Meta = { + component: SliderStop, + tags: ['autodocs'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + Label: '5 Years', + isActive: false, + }, +}; + +export const Active: Story = { + args: { + Label: '5 Years', + isActive: true, + }, +}; diff --git a/packages/ui/src/themes/color.styled.ts b/packages/ui/src/themes/color.styled.ts index 9ae764c25..b25b80cb5 100644 --- a/packages/ui/src/themes/color.styled.ts +++ b/packages/ui/src/themes/color.styled.ts @@ -21,6 +21,9 @@ export const colors = { info: { main: '#F1AE4A', }, + active: { + main: '#3c3329', + }, warning: { main: '#FF624C', },