Skip to content

Commit

Permalink
feat: 무한 캐러셀 컴포넌트에 이미지 슬라이드 기능 추가 및 스타일 개선
Browse files Browse the repository at this point in the history
  • Loading branch information
gwagjiug committed Jan 15, 2025
1 parent 2ec4379 commit e01a08a
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,46 @@ import { style } from '@vanilla-extract/css';
export const wrap = style({
width: '33.5rem',
height: '19.3rem',
overflow: 'hidden',
position: 'relative',
});

export const imageContainer = style({
display: 'flex',
width: '100%',
height: '100%',
position: 'absolute',
transition: 'transform 1s ease-in-out',
});

export const image = style({
width: '100%',
height: '100%',
objectFit: 'cover',
flexShrink: 0,
});

export const active = style({
opacity: 1,
});

export const container = style({
...themeVars.display.flexCenter,
width: '33.5rem',
height: '19.3rem',
background: themeVars.color.black_op,
width: '100%',
height: '100%',
flexShrink: '0',
padding: '1.6rem, 1.2rem',
backgroundColor: themeVars.color.black,
padding: '1.6rem 1.2rem',
position: 'absolute',
top: 0,
left: 0,
});

export const info = style({
...themeVars.display.flexColumn,
width: '31.1rem',
height: '16.1rem',
alignItems: 'flex-start',
gap: '7.1rem',
flexShrink: '0',
});

Expand All @@ -35,16 +58,17 @@ export const infoDday = style({
...themeVars.fontStyles.title1_b_24,
});

export const artist = style({
export const subtitle = style({
...themeVars.fontStyles.title3_b_18,
color: themeVars.color.confeti_lime,
});

export const subtitle = style({
export const fixedWord = style({
...themeVars.fontStyles.title3_b_18,
color: themeVars.color.white,
});

export const infoBottom = style({
marginTop: '9.8rem',
...themeVars.display.flexBetween,
});
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import type { Meta } from '@storybook/react';
import { Meta } from '@storybook/react';
import InfiniteCarousel from './infinite-carousel';
import { BANNER_DATA } from './mocks/bottom-banner-data';

const meta: Meta<typeof InfiniteCarousel.Image> = {
const meta: Meta<typeof InfiniteCarousel.Wrap> = {
title: 'Common/InfiniteCarousel',
component: InfiniteCarousel.Image,
component: InfiniteCarousel.Wrap,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
args: {},
};

const bannerData = BANNER_DATA?.data?.performances || [];
const TotalIndexData = BANNER_DATA?.data?.performanceCount;

export default meta;

export const Default = () => (
<InfiniteCarousel.Image>
<InfiniteCarousel.Info>
<InfiniteCarousel.Dday day="2024.01.14" />
<InfiniteCarousel.Artist artist="고고학" subtitle="공연 예매" />
</InfiniteCarousel.Info>
</InfiniteCarousel.Image>
);
export const Default = () => {
return (
<InfiniteCarousel.Wrap
performances={bannerData}
indexData={TotalIndexData}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,49 +1,133 @@
import * as styles from './infinite-carousel.css';
import { useEffect } from 'react';
import { ReactNode } from 'react';
interface CarouselImageProps {
import * as styles from './infinite-carousel.css';
import ProgressBar from './progress-bar/progress-bar';
import { useCarouselData } from './hooks/use-carousel-data';
import { useCarouselSlide } from './hooks/use-carousel-slide';
import { useControlTime } from './hooks/use-control-time';
interface CarouselWrapProps {
performances: {
reservationBgUrl: string;
subtitle: string;
reserveAt: string;
}[];
indexData: number;
}

interface CarouselContainerProps {
children: React.ReactNode;
}

interface CarouselInfoProps {
children: ReactNode;
artist?: string;
subtitle?: string;
}

interface CarouselDdayProps {
day: string;
reserveAt: string;
}

interface CarouselArtistProps {
artist: string;
subtitle: string;
subtitle: string | undefined;
}

const CarouselImage = ({ children }: CarouselImageProps) => (
<section className={styles.wrap}>
<div className={styles.container}>{children}</div>
</section>
interface CarouselInfoBottomProps {
children: ReactNode;
}

const CarouselWrap = ({ performances, indexData }: CarouselWrapProps) => {
// 슬라이드 데이터
const copyImage = useCarouselData(
performances.map((item) => item.reservationBgUrl),
performances.map((item) => item.subtitle),
performances.map((item) => item.reserveAt),
);

// 슬라이드 상태 관리
const { currentIndex, carouselTransition, nextSlide } = useCarouselSlide(
copyImage.images.length,
);

// 슬라이드 간격 관리
const controlTime = useControlTime(carouselTransition);

// 자동 슬라이드 전환
useEffect(() => {
const interval = setInterval(nextSlide, controlTime);
return () => clearInterval(interval);
}, [nextSlide, controlTime]);

return (
<section className={styles.wrap}>
<div
className={styles.imageContainer}
style={{
transform: `translateX(-${currentIndex * 100}%)`,
transition: carouselTransition,
}}
>
{copyImage.images.map((imgUrl, id) => (
<img
key={id}
src={imgUrl}
alt={`캐러셀 이미지 ${id + 1}`}
className={styles.image}
/>
))}
</div>
<InfiniteCarousel.Container>
<InfiniteCarousel.Info>
<InfiniteCarousel.Dday
reserveAt={copyImage.reserveDates[currentIndex] || ''}
/>
<InfiniteCarousel.Artist
subtitle={copyImage.subtitles[currentIndex]}
/>
<InfiniteCarousel.InfoBottom>
<ProgressBar
size="md"
current={
currentIndex === copyImage.images.length - 1 ? 1 : currentIndex
}
total={indexData}
/>
</InfiniteCarousel.InfoBottom>
</InfiniteCarousel.Info>
</InfiniteCarousel.Container>
</section>
);
};

const CarouselContainer = ({ children }: CarouselContainerProps) => (
<div className={styles.container}>{children}</div>
);

const CarouselInfo = ({ children }: CarouselInfoProps) => (
<section className={styles.info}>
<div className={styles.textSection}>{children}</div>
<div className={styles.infoBottom}>{children}</div>
</section>
);

const CarouselDday = ({ day }: CarouselDdayProps) => (
<div className={styles.infoDday}>D-{day}</div>
const CarouselInfoBottom = ({ children }: CarouselInfoBottomProps) => (
<div className={styles.infoBottom}>{children}</div>
);

const CarouselDday = ({ reserveAt }: CarouselDdayProps) => (
<div className={styles.infoDday}>D-{reserveAt}</div>
);

const CarouselArtist = ({ artist, subtitle }: CarouselArtistProps) => (
<div className={styles.artist}>
{artist} <span className={styles.subtitle}>{subtitle}</span>
</div>
const CarouselArtist = ({ subtitle }: CarouselArtistProps) => (
<>
<span className={styles.subtitle}>
{subtitle} <span className={styles.fixedWord}>예매</span>
</span>
</>
);

const InfiniteCarousel = {
Image: CarouselImage,
Wrap: CarouselWrap,
Container: CarouselContainer,
Info: CarouselInfo,
InfoBottom: CarouselInfoBottom,
Dday: CarouselDday,
Artist: CarouselArtist,
};
Expand Down

0 comments on commit e01a08a

Please sign in to comment.