diff --git a/src/components/SquareTabs/index.tsx b/src/components/SquareTabs/index.tsx index b47b2b9126..7e775d5ec0 100644 --- a/src/components/SquareTabs/index.tsx +++ b/src/components/SquareTabs/index.tsx @@ -1,4 +1,5 @@ import classNames from 'classnames' +import { useEffect, useRef, useState } from 'react' import styles from './styles.module.css' @@ -34,15 +35,60 @@ interface SquareTabsProps { export const SquareTabs: React.FC> & { Tab: typeof Tab } = ({ children, sticky }) => { + const navRef = useRef(null) + const containerRef = useRef(null) + const $nav = navRef.current + const $container = containerRef.current + const [showLeftGradient, setShowLeftGradient] = useState(false) + const [showRightGradient, setShowRightGradient] = useState(false) + + const isTabsOverflowing = () => { + if (!$nav || !$container) return false + return $nav.scrollWidth > $container.clientWidth + } + + const calculateGradient = () => { + if (!$nav || !$container) return + + const isAtLeftMost = $nav.scrollLeft <= 0 + const isAtRightMost = $nav.scrollLeft + $nav.clientWidth >= $nav.scrollWidth + + setShowLeftGradient(!isAtLeftMost) + setShowRightGradient(!isAtRightMost) + } + + useEffect(() => { + if (!isTabsOverflowing() || !$nav) return + + // initial gradient + calculateGradient() + + $nav.addEventListener('scroll', calculateGradient) + + return () => { + if (!$nav) return + + $nav.removeEventListener('scroll', calculateGradient) + } + }, [$nav]) + + const containerClasses = classNames({ + [styles.container]: true, + [styles.showLeftGradient]: showLeftGradient, + [styles.showRightGradient]: showRightGradient, + }) + const navClasses = classNames({ [styles.tabList]: true, [styles.sticky]: sticky, }) return ( -
    - {children} -
+
+
    + {children} +
+
) } diff --git a/src/components/SquareTabs/styles.module.css b/src/components/SquareTabs/styles.module.css index c98570d7b3..ec2c2a4078 100644 --- a/src/components/SquareTabs/styles.module.css +++ b/src/components/SquareTabs/styles.module.css @@ -1,3 +1,45 @@ +.container { + position: relative; + + &::before, + &::after { + position: absolute; + top: 0; + bottom: 0; + z-index: calc(var(--z-index-sticky-tabs) + 1); + width: 7.5rem; + pointer-events: none; + content: ''; + opacity: 0; /* Initially hidden */ + transition: opacity 0.3s; + } + + &.showLeftGradient::before, + &.showRightGradient::after { + opacity: 1; /* Show when scrollable */ + } + + &::before { + left: 0; + background: linear-gradient( + -90deg, + rgb(255 255 255 / 0%) 0%, + rgb(255 255 255 / 30%) 20%, + #fff 100% + ); + } + + &::after { + right: 0; + background: linear-gradient( + 90deg, + rgb(255 255 255 / 0%) 0%, + rgb(255 255 255 / 30%) 20%, + #fff 100% + ); + } +} + .tabList { @mixin hide-scrollbar;