Skip to content

Commit

Permalink
Merge pull request #197 from TEAM-FLASH/Feat/#191
Browse files Browse the repository at this point in the history
[S4] 딤 모달 내 스와이퍼 기능 구현 완료
  • Loading branch information
s0zzang authored Jan 2, 2025
2 parents 2903cec + f7d19bc commit b761f27
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 32 deletions.
6 changes: 3 additions & 3 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ const ModalStyle = styled.section<IModalStyle>`
position: fixed;
z-index: 99;
inset: 0;
background: ${(props) => (props.type !== 'fullscreen' ? 'rgba(0,0,0,0.9)' : variables.colors.white)};
background: ${(props) => (props.type !== 'fullscreen' ? 'rgba(0,0,0,0.85)' : variables.colors.white)};
padding: 0 2rem 4.8rem;
display: flex;
flex-direction: column;
justify-content: ${(props) => (props.type !== 'fullscreen' ? '' : 'space-between')};
`;

const TitleStyle = styled.div<ITitleStyle>`
padding: ${(props) => (props.type === 'fullscreen' ? '1.4rem 0' : '1.8rem 0')};
padding: ${(props) => (props.type === 'fullscreen' ? '1.4rem 0' : '2.8rem 0')};
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -105,13 +105,13 @@ const CloseBtnStyle = styled.button<ICloseBtnStyle>`
position: absolute;
left: ${(props) => props.mode === 'fullscreen' && 0};
right: ${(props) => props.mode === 'dimmed' && 0};
z-index: 9;
`;

const ContentsStyle = styled.div<IContentStyle>`
padding: ${(props) => props.type === 'fullscreen' && '1rem 0'};
flex-grow: 1;
overflow-y: auto;
display: ${(props) => props.type === 'dimmed' && 'flex'};
`;

const ButtonBoxStyle = styled.div`
Expand Down
89 changes: 74 additions & 15 deletions src/components/Swiper/DimSwiper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/** @jsxImportSource @emotion/react */

import { useDimSwiperStore } from '@store/useDimSwiper';
import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from 'react';
import { Navigation, Pagination, Virtual } from 'swiper/modules';
import { Dispatch, ReactNode, SetStateAction, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { Navigation, Virtual } from 'swiper/modules';
import { Swiper, SwiperClass } from 'swiper/react';
import { IPortfolio } from 'types/types';

import 'swiper/css';
import 'swiper/css/pagination';
import { TypoBodyMdR } from '@styles/Common';
import { css } from '@emotion/react';

interface IDimSwiper {
children: ReactNode;
Expand All @@ -14,40 +17,96 @@ interface IDimSwiper {
}

const DimSwiper = ({ children, data, setSlideSet }: IDimSwiper) => {
const [swiperRef, setSwiperRef] = useState<SwiperClass>();
const { selectedId, setSelectedId } = useDimSwiperStore();
const isFirstSlide = data[0].id === selectedId;
const [swiperRef, setSwiperRef] = useState<SwiperClass>();
const [firstSlide, setFirstSlide] = useState<number>();
const [lastSlide, setLastSlide] = useState<number>();
const [activeIndex, setActiveIndex] = useState<number>(0);
const slideIndexMap = useMemo(() => new Map(), []);

const getNewSlideSet = (clickedId: number) => {
return data.filter(({ id }: { id: number }) => id === clickedId || id === clickedId - 1 || id === clickedId + 1);
};

const setIndexByPortfolioId = () => {
for (let i = 0; i < data.length; i++) {
slideIndexMap.set(data[i].id, i + 1);
}
};

const handleChange = () => {
if (!swiperRef) return null;
if (!swiperRef || !firstSlide || !lastSlide) return null;
const toNext = swiperRef.swipeDirection === 'next';
const direction = toNext ? 1 : -1;

// 첫번째, 마지막 슬라이드에서 슬라이드 변경 금지
if (selectedId === firstSlide) if (!toNext) return;
if (selectedId === lastSlide) if (toNext) return;

// 두번째 슬라이드에서 이전 방향으로 변경된 경우
if (selectedId === firstSlide + 1 && !toNext) {
setSelectedId(selectedId, direction);
swiperRef.slideTo(0, 0, false);
return;
}

const direction = swiperRef.swipeDirection === 'next' ? 1 : -1;
setSelectedId(selectedId, direction);
swiperRef.slideTo(isFirstSlide ? 0 : 1, 0, false);
swiperRef.slideTo(1, 0, false);
};

const swiperOption = {
modules: [Virtual, Pagination, Navigation],
modules: [Virtual, Navigation],
onSwiper: (e: SwiperClass) => setSwiperRef(e),
onTransitionEnd: handleChange,
slidesPerView: 1,
initialSlide: isFirstSlide ? 0 : 1,
pagination: {
type: 'fraction' as 'fraction',
},
initialSlide: selectedId === firstSlide ? 0 : 1,
centeredSlides: true,
spaceBetween: 20,
};

useEffect(() => {
// console.log(isFirstSlide);
setIndexByPortfolioId();
if (data) {
setFirstSlide(data[0].id);
setLastSlide(data[data.length - 1].id);
}
}, []);

useLayoutEffect(() => {
setSlideSet(getNewSlideSet(selectedId));
setActiveIndex(slideIndexMap.get(selectedId));
}, [selectedId]);

return <Swiper {...swiperOption}>{children}</Swiper>;
return (
firstSlide && (
<>
<h2 css={[TypoBodyMdR, TitleStyle]}>
{activeIndex} / {data.length}
</h2>
<Swiper {...swiperOption}>{children}</Swiper>
</>
)
);
};

export default DimSwiper;

const TitleStyle = css`
padding: 1.8rem 0;
text-align: center;
position: absolute;
inset: 0;
bottom: auto;
`;

export const SlideImgBox = css`
background: #0f0f0f;
padding: 1rem;
border-radius: 0.6rem;
margin-bottom: 1rem;
img {
aspect-ratio: 308/340;
object-fit: scale-down;
}
`;
15 changes: 11 additions & 4 deletions src/pages/Studio/StudioPortfolio/PortfolioSwiper.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @jsxImportSource @emotion/react */

import DimSwiper from '@components/Swiper/DimSwiper';
import DimSwiper, { SlideImgBox } from '@components/Swiper/DimSwiper';
import { css } from '@emotion/react';
import { TypoBodyMdR } from '@styles/Common';
import { useState } from 'react';
import { SwiperSlide } from 'swiper/react';
Expand All @@ -12,14 +13,20 @@ const PortfolioSwiper = ({ data, studioName }: { data: IPortfolio[]; studioName:
return (
<DimSwiper data={data} setSlideSet={setSlideSet}>
{slideSet &&
slideSet.map(({ id, url, description }) => (
slideSet.map(({ id, url, menuName }) => (
<SwiperSlide key={id} virtualIndex={id}>
<img src={url} alt={`${studioName}-${id}`} />
<p css={TypoBodyMdR}>{description}</p>
<div css={[SlideImgBox, portfolioSlide]}>
<img src={url} alt={`${studioName}-${id}`} />
</div>
<p css={TypoBodyMdR}>{menuName}</p>
</SwiperSlide>
))}
</DimSwiper>
);
};

export default PortfolioSwiper;

const portfolioSlide = css`
margin-top: 4rem;
`;
2 changes: 1 addition & 1 deletion src/pages/Studio/StudioPortfolio/StudioPortfolio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ const StudioPortfolio = () => {
const data = await response.json();
setData(data.portfolioDtos.content);
setMenuNames(data.menuNameList);
setStudioName(data.studioName);
} catch (err) {
console.error('Failed to fetch data');
}
};

useEffect(() => {
fetchPortfolio();
if (data.length) setStudioName(data[0].studio);
}, []);

return (
Expand Down
12 changes: 4 additions & 8 deletions src/pages/Studio/components/DimmedModal.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
/** @jsxImportSource @emotion/react */
import Modal from '@components/Modal/Modal';
// import { css } from '@emotion/react';
import styled from '@emotion/styled';

const DimmedModal = ({ children }: { children: React.ReactNode }) => {
return (
<>
<Modal type="dimmed" title={`3/20`} withBtn={false}>
<Modal type="dimmed" withBtn={false}>
<DimmedModalStyle>{children}</DimmedModalStyle>
</Modal>
</>
);
};

const DimmedModalStyle = styled.div`
width: 100%;
display: flex;
* {
color: #fff;
}
`;

// const swiperStyle = css`
// color: white;
// `;

export default DimmedModal;
2 changes: 1 addition & 1 deletion src/store/useDimSwiper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ interface DimSwiperState {

export const useDimSwiperStore = create<DimSwiperState>((set) => ({
selectedId: 0,
setSelectedId: (id, direction) => set((state) => ({ selectedId: (id || state.selectedId) + (direction || 1) })),
setSelectedId: (id, direction) => set(() => ({ selectedId: id + (direction || 0) })),
}));
1 change: 1 addition & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IPortfolio {
name: string;
url: string;
menuId: number;
menuName: string;
description: string;
created_at: string;
updated_at: null | string;
Expand Down

0 comments on commit b761f27

Please sign in to comment.