Skip to content

Commit

Permalink
feat(website): create simple grid carousel
Browse files Browse the repository at this point in the history
  • Loading branch information
Media Center committed May 9, 2024
1 parent 0424a36 commit 11872b4
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 12 deletions.
36 changes: 24 additions & 12 deletions apps/dynamic-grid-website/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from 'react';
import styled from '@emotion/styled';
import { DynamicGrid } from '@mordech/dynamic-grid-react';

import { Carousel } from './components/carousel/carousel';
import {
Button,
FeaturedCard,
Expand Down Expand Up @@ -36,6 +37,21 @@ function App() {

return (
<DeleteThisContainer>
<Carousel minColumnWidth="24rem" gap="1rem">
{Array(10)
.fill('')
.map(() => (
<TourCard
title="Test Tour"
description="Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos."
image="https://picsum.photos/seed/1/800/800"
rating={4.5}
discount={50}
duration="7 days"
difficulty="easy"
/>
))}
</Carousel>
<GithubBadge href="#" />
<ToggleThemeButton size="compact" />
<ButtonContainer>
Expand All @@ -60,8 +76,7 @@ function App() {
<Icon icon="arrow_forward" />
</Button>
</ButtonContainer>

<DynamicGrid
<Carousel
minColumnWidth="21.5rem"
gap="2rem 1rem"
isScroll
Expand Down Expand Up @@ -93,9 +108,8 @@ function App() {
duration="4 days"
difficulty="difficult"
/>
</DynamicGrid>

<DynamicGrid
</Carousel>
<Carousel
minColumnWidth="20rem"
gap="2rem 1rem"
isScroll
Expand Down Expand Up @@ -156,9 +170,8 @@ function App() {
location="Dallas, TX"
testimonial="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, libero et aliquam ultrices, nunc elit tincidunt urna, ac lacinia justo nisl sed nunc."
/>
</DynamicGrid>

<DynamicGrid minColumnWidth="15rem" gap="1rem">
</Carousel>
<Carousel minColumnWidth="15rem" gap="1rem">
<FeaturedCard
backgroundImage="url(https://loremflickr.com/600/600/flower?lock=1)"
description="Enigmatic Oasis Discovered in the Heart of the Sahara Desert!"
Expand All @@ -168,9 +181,8 @@ function App() {
backgroundImage="url(https://loremflickr.com/600/600/flower?lock=3)"
description="Mystical Underwater City Unearthed in the Pacific Depths!"
/>
</DynamicGrid>

<DynamicGrid minColumnWidth="10rem" gap="1rem">
</Carousel>
<Carousel minColumnWidth="10rem" gap="1rem">
<MusicCard
variant="album"
src="https://loremflickr.com/320/320/abstract?lock=1"
Expand All @@ -181,7 +193,7 @@ function App() {
src="https://loremflickr.com/320/320/abstract?lock=4"
cardInfo={{ artist: 'Jane Smith', albumName: 'Lonesome' }}
/>
</DynamicGrid>
</Carousel>
<DynamicGrid minColumnWidth="7rem" gap="1rem">
<MusicCard
variant="artist"
Expand Down
116 changes: 116 additions & 0 deletions apps/dynamic-grid-website/src/components/carousel/carousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import {
FC,
MouseEvent,
ReactNode,
useCallback,
useLayoutEffect,
useRef,
useState,
} from 'react';
import styled from '@emotion/styled';
import { DynamicGrid, DynamicGridProps } from '@mordech/dynamic-grid-react';

import { Button } from '../button';
import { Icon } from '../icon';

type CarouselProps = {
children?: ReactNode;
} & DynamicGridProps;

export const CarouselWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 0.75rem;
`;

const ButtonContainer = styled.div`
display: flex;
gap: 0.5rem;
align-self: flex-end;
`;

export const Carousel: FC<CarouselProps> = ({ children, ...rest }) => {
const [leftArrowDisabled, setLeftArrowDisabled] = useState<boolean>(true);
const [rightArrowDisabled, setRightArrowDisabled] = useState<boolean>(false);

const gridRef = useRef<HTMLDivElement>(null);

const handleArrowsState = useCallback(() => {
const buffer = 30;
const grid = gridRef.current;

if (!grid) return;

const isAtEnd =
grid.scrollLeft + grid.offsetWidth >= grid.scrollWidth - buffer;

const isAtStart = grid.scrollLeft < buffer;

isAtStart ? setLeftArrowDisabled(true) : setLeftArrowDisabled(false);
isAtEnd ? setRightArrowDisabled(true) : setRightArrowDisabled(false);
}, []);

const handleScroll = useCallback((mouseEvent: MouseEvent) => {
const grid = gridRef.current;
if (!grid) return;

const firstGridChildWidth = grid.firstElementChild?.clientWidth || 200;

if (!(mouseEvent.target instanceof HTMLElement)) return;
mouseEvent.target.ariaLabel === 'Next'
? grid.scrollBy({ left: firstGridChildWidth })
: grid.scrollBy({ left: -1 * firstGridChildWidth });
}, []);

useLayoutEffect(() => {
const resizeObserver = new ResizeObserver(handleArrowsState);
resizeObserver.observe(gridRef.current!);

return resizeObserver.disconnect;
}, [handleArrowsState]);

return (
<CarouselWrapper>
<ButtonContainer>
<Button
aria-label="Previous"
radius="round"
variant="tonal"
size="compact"
disabled={leftArrowDisabled}
onClick={handleScroll}
>
<Icon icon="arrow_back" />
</Button>

<Button
aria-label="Next"
radius="round"
variant="tonal"
size="compact"
disabled={rightArrowDisabled}
onClick={handleScroll}
>
<Icon icon="arrow_forward" />
</Button>
</ButtonContainer>

<DynamicGrid
ref={gridRef}
onScroll={handleArrowsState}
scrollOptions={{ hideScrollbar: true }}
{...rest}
isScroll
>
{children}
</DynamicGrid>

<ButtonContainer>
<Button radius="pill" variant="text" size="compact">
Inspect
<Icon slot="icon-end" icon="code" />
</Button>
</ButtonContainer>
</CarouselWrapper>
);
};

0 comments on commit 11872b4

Please sign in to comment.