From 2cdb9b56dbb9c220c9f7045ba05f86c4e2423871 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Mon, 28 Apr 2025 22:27:17 +0900 Subject: [PATCH 01/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=EC=BA=90?= =?UTF-8?q?=EB=9F=AC=EC=85=80=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?-=20=EC=BA=90=EB=9F=AC=EC=85=80=20=EC=9D=BC=EB=B6=80=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80=EA=B2=BD=20-=20?= =?UTF-8?q?=EC=BA=90=EB=9F=AC=EC=85=80=20=EB=A1=9C=EC=A7=81=20=EA=B0=84?= =?UTF-8?q?=EC=86=8C=ED=99=94=20-=20=EC=9D=BC=EB=B6=80=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=83=81=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 61 +++++++++------------ src/components/carousel/carousel.styles.js | 37 ++++++++----- src/constants/carousel/carousel.js | 7 +++ src/constants/carousel/carouselConstants.js | 10 ---- src/constants/carousel/index.js | 2 +- 5 files changed, 57 insertions(+), 60 deletions(-) create mode 100644 src/constants/carousel/carousel.js delete mode 100644 src/constants/carousel/carouselConstants.js diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index ed0209d2..ab34cad4 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -1,49 +1,41 @@ import { ArrowButton } from '@/components/button'; import { Card } from '@/components/card'; -import { getItemMetrics } from '@/utils/carousel'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useState } from 'react'; +import { CAROUSEL } from '@/constants/carousel'; import * as S from './carousel.styles'; const Carousel = ({ data, setModalType, setSelectedIndex }) => { const [currentIndex, setCurrentIndex] = useState(0); - const [itemsPerView, setItemsPerView] = useState(4); - const containerRef = useRef(null); - - // data.list의 길이를 사용 + const [isAnimating, setIsAnimating] = useState(false); // 애니메이션 상태 추가 const itemsLength = data?.list?.length || 0; - const updateItemsPerView = useCallback(() => { - if (!containerRef.current) return; - - const viewportWidth = containerRef.current.offsetWidth; - const { itemWidth, gap } = getItemMetrics(); - const totalItemWidth = itemWidth + gap; - const calculatedItemsPerView = Math.floor(viewportWidth / totalItemWidth); - - setItemsPerView(calculatedItemsPerView); - const newMaxIndex = Math.max(0, itemsLength - calculatedItemsPerView); - setCurrentIndex((prev) => Math.min(prev, newMaxIndex)); - }, [itemsLength]); - - useEffect(() => { - updateItemsPerView(); - window.addEventListener('resize', updateItemsPerView); - return () => window.removeEventListener('resize', updateItemsPerView); - }, [updateItemsPerView]); - - const maxIndex = Math.max(0, itemsLength - itemsPerView); + // 마지막 인덱스를 계산 (데이터가 10개라면 maxIndex는 6, 즉 마지막 페이지까지 고려) + const maxIndex = Math.max(0, Math.ceil(itemsLength / CAROUSEL.ITEMS_VIEW) - 1); const handleNext = () => { - setCurrentIndex((prev) => Math.min(prev + 1, maxIndex)); + if (isAnimating) return; // 애니메이션 중이면 클릭을 막음 + setIsAnimating(true); // 애니메이션 시작 + setCurrentIndex((prev) => Math.min(prev + CAROUSEL.ITEMS_VIEW, maxIndex * CAROUSEL.ITEMS_VIEW)); // 4개씩 이동 + setTimeout(() => setIsAnimating(false), 400); // 400ms 후에 애니메이션 완료 처리 }; const handlePrev = () => { - setCurrentIndex((prev) => Math.max(prev - 1, 0)); + if (isAnimating) return; // 애니메이션 중이면 클릭을 막음 + setIsAnimating(true); // 애니메이션 시작 + setCurrentIndex((prev) => Math.max(prev - CAROUSEL.ITEMS_VIEW, 0)); // 4개씩 이동 + setTimeout(() => setIsAnimating(false), 400); // 400ms 후에 애니메이션 완료 처리 }; const getSlideOffset = () => { - const { itemWidth, gap } = getItemMetrics(); - return currentIndex * (itemWidth + gap); + const offset = currentIndex * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP); + // 마지막 인덱스에 대해서도 공백을 추가 + if (currentIndex === maxIndex) { + return Math.min( + offset, + (itemsLength - CAROUSEL.ITEMS_VIEW) * (CAROUSEL.DESKTOP_ITEM_WIDTH + gap), + ); + } + return offset; }; return ( @@ -53,10 +45,10 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => { -
+
{ = maxIndex} + disabled={currentIndex >= maxIndex * CAROUSEL.ITEMS_VIEW || isAnimating} + styles={S.navigationButton(true, isAnimating)} />
diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index 791bb48f..0f248ef6 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -4,31 +4,31 @@ import { css } from '@emotion/react'; export const wrapper = css` width: 100%; margin-block: 4rem; + + ${media({ + marginBlock: ['4rem', '4rem', '4rem 6rem', '4rem 6rem', '4rem 6rem'], + })} `; export const carouselTitle = css` - margin-inline: 2rem; - margin-bottom: 1.6rem; font-size: 2.4rem; font-weight: 700; color: var(--white); ${media({ fontSize: ['2rem', '2rem', '2.4rem', '2.4rem'], - marginInline: ['2rem', '2rem', '8rem', '8rem'], marginBottom: ['1.6rem', '1.6rem', '2.4rem', '3.2rem'], })} `; export const viewportArea = css` - display: flex; - align-items: center; - gap: 0; - padding-inline: 2rem; + position: relative; - ${media({ - gap: ['0', '0', '2rem', '2rem'], - })} + &::before { + content: ''; + background: linear-gradient(to bottom, rgb(0 0 0 / 50%), rgb(0 0 0 / 70%)); + } + `; export const carouselContainer = css` @@ -45,7 +45,7 @@ export const carouselContainer = css` export const carouselTrack = css` display: flex; gap: 1.2rem; - transition: transform 0.3s ease-in-out; + transition: transform 1.5s ease-in-out; ${media({ transform: [ @@ -67,8 +67,15 @@ export const carouselItem = css` })} `; -export const navigationButton = css` - ${media({ - display: ['none', 'none', 'flex', 'flex'], - })} +export const navigationButton = (isRight, isAnimating) => css` + position: absolute; + top: 50%; + ${isRight ? 'right: 0.5%' : 'left: 0.5%'}; + z-index: 1; + width: 3rem; + background-color: var(--black); + pointer-events: ${isAnimating ? 'none' : 'auto'}; /* 애니메이션 중 버튼 클릭 방지 */ + transition: opacity 0.3s ease-in-out; /* 버튼에 부드러운 비활성화 효과 추가 */ + transform: translateY(-125%); + opacity: ${isAnimating ? 0.3 : 0.5}; /* 애니메이션 중 버튼의 불투명도 변경 */ `; diff --git a/src/constants/carousel/carousel.js b/src/constants/carousel/carousel.js new file mode 100644 index 00000000..b949f279 --- /dev/null +++ b/src/constants/carousel/carousel.js @@ -0,0 +1,7 @@ +const CAROUSEL = { + DESKTOP_ITEM_WIDTH: 282, + ITEM_GAP: 12, + ITEMS_VIEW: 4, +}; + +export default CAROUSEL; diff --git a/src/constants/carousel/carouselConstants.js b/src/constants/carousel/carouselConstants.js deleted file mode 100644 index c7548f59..00000000 --- a/src/constants/carousel/carouselConstants.js +++ /dev/null @@ -1,10 +0,0 @@ -const CAROUSEL_CONSTANTS = { - MOBILE_BREAKPOINT: 768, - ITEM_DIMENSIONS: { - MOBILE_ITEM_WIDTH: 158, - DESKTOP_ITEM_WIDTH: 282, - ITEM_GAP: 12, - }, -}; - -export default CAROUSEL_CONSTANTS; diff --git a/src/constants/carousel/index.js b/src/constants/carousel/index.js index 458b00f2..41f65ab4 100644 --- a/src/constants/carousel/index.js +++ b/src/constants/carousel/index.js @@ -1 +1 @@ -export { default as CAROUSEL_CONSTANTS } from './carouselConstants'; +export { default as CAROUSEL } from './carousel'; From f82bbda0951cb92ab8036d09ddb6714456a94a0c Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 03:18:53 +0900 Subject: [PATCH 02/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=EC=BA=90?= =?UTF-8?q?=EB=9F=AC=EC=85=80=20=EA=B5=AC=EC=A1=B0=20=EB=B0=8F=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 27 ++++++---------------- src/components/carousel/carousel.styles.js | 24 ++++++++++--------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index ab34cad4..ac9e0f52 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -6,33 +6,25 @@ import * as S from './carousel.styles'; const Carousel = ({ data, setModalType, setSelectedIndex }) => { const [currentIndex, setCurrentIndex] = useState(0); - const [isAnimating, setIsAnimating] = useState(false); // 애니메이션 상태 추가 const itemsLength = data?.list?.length || 0; // 마지막 인덱스를 계산 (데이터가 10개라면 maxIndex는 6, 즉 마지막 페이지까지 고려) const maxIndex = Math.max(0, Math.ceil(itemsLength / CAROUSEL.ITEMS_VIEW) - 1); const handleNext = () => { - if (isAnimating) return; // 애니메이션 중이면 클릭을 막음 - setIsAnimating(true); // 애니메이션 시작 setCurrentIndex((prev) => Math.min(prev + CAROUSEL.ITEMS_VIEW, maxIndex * CAROUSEL.ITEMS_VIEW)); // 4개씩 이동 - setTimeout(() => setIsAnimating(false), 400); // 400ms 후에 애니메이션 완료 처리 }; const handlePrev = () => { - if (isAnimating) return; // 애니메이션 중이면 클릭을 막음 - setIsAnimating(true); // 애니메이션 시작 setCurrentIndex((prev) => Math.max(prev - CAROUSEL.ITEMS_VIEW, 0)); // 4개씩 이동 - setTimeout(() => setIsAnimating(false), 400); // 400ms 후에 애니메이션 완료 처리 }; const getSlideOffset = () => { const offset = currentIndex * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP); - // 마지막 인덱스에 대해서도 공백을 추가 if (currentIndex === maxIndex) { return Math.min( offset, - (itemsLength - CAROUSEL.ITEMS_VIEW) * (CAROUSEL.DESKTOP_ITEM_WIDTH + gap), + (itemsLength - CAROUSEL.ITEMS_VIEW) * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP), ); } return offset; @@ -45,16 +37,11 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => {
-
+
{data?.list?.length > 0 ? ( data.list.map((item, index) => (
@@ -67,15 +54,15 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => {
)) ) : ( -
표시할 항목이 없습니다
+
현재 등록된 후원이 없습니다.
)}
= maxIndex * CAROUSEL.ITEMS_VIEW || isAnimating} - styles={S.navigationButton(true, isAnimating)} + disabled={currentIndex >= maxIndex * CAROUSEL.ITEMS_VIEW} + styles={S.navigationButton(true)} />
diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index 0f248ef6..adcc45b6 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -28,7 +28,6 @@ export const viewportArea = css` content: ''; background: linear-gradient(to bottom, rgb(0 0 0 / 50%), rgb(0 0 0 / 70%)); } - `; export const carouselContainer = css` @@ -42,18 +41,13 @@ export const carouselContainer = css` } `; -export const carouselTrack = css` +export const carouselTrack = (slide) => css` display: flex; gap: 1.2rem; transition: transform 1.5s ease-in-out; ${media({ - transform: [ - 'none', - 'none', - 'translateX(var(--slide-offset))', - 'translateX(var(--slide-offset))', - ], + transform: ['none', 'none', `translateX(-${slide}px)`, `translateX(-${slide}px)`], })} `; @@ -67,15 +61,23 @@ export const carouselItem = css` })} `; -export const navigationButton = (isRight, isAnimating) => css` +export const navigationButton = (isRight) => css` position: absolute; top: 50%; ${isRight ? 'right: 0.5%' : 'left: 0.5%'}; z-index: 1; width: 3rem; background-color: var(--black); - pointer-events: ${isAnimating ? 'none' : 'auto'}; /* 애니메이션 중 버튼 클릭 방지 */ transition: opacity 0.3s ease-in-out; /* 버튼에 부드러운 비활성화 효과 추가 */ transform: translateY(-125%); - opacity: ${isAnimating ? 0.3 : 0.5}; /* 애니메이션 중 버튼의 불투명도 변경 */ +`; + +export const notthingTitle = css` + display: flex; + justify-content: center; + align-items: center; + font-size: 2rem; + font-weight: 700; + text-align: center; + margin-block: 7rem; `; From 15e5d5a3ff1a0d0191037852785f21e9beff0c4a Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 03:19:44 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/card/Card.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/card/Card.jsx b/src/components/card/Card.jsx index b19b9700..9197524d 100644 --- a/src/components/card/Card.jsx +++ b/src/components/card/Card.jsx @@ -9,15 +9,15 @@ const Card = ({ data, setModalType, setSelectedIndex, index }) => { const percent = `${getDonationPercentage(data.targetDonation, data.receivedDonations)}%`; const isDonationAvailable = daysLeft > 0; - // 실시간으로 남은 일수를 갱신하기 위해 setInterval 사용 + // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect(() => { const interval = setInterval(() => { const newDaysLeft = getDaysRemaining(data.deadline); - setDaysLeft(newDaysLeft); // 갱신된 남은 일수로 상태 업데이트 - }, 55000); + setDaysLeft(newDaysLeft); + }, 60000); return () => clearInterval(interval); - }, [data.deadline]); + }, []); const handleClick = () => { setSelectedIndex(index); From 8a0cab5951b5b056d5570f05718d7660333e3389 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 03:20:15 +0900 Subject: [PATCH 04/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=20?= =?UTF-8?q?=ED=9B=84=EC=9B=90=20=EB=AA=A8=EB=8B=AC=20=EB=B0=A9=EC=96=B4?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20Alert=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- .../modals/donationModal/DonationModal.jsx | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/components/modals/donationModal/DonationModal.jsx b/src/components/modals/donationModal/DonationModal.jsx index eff3471e..f6c9be4c 100644 --- a/src/components/modals/donationModal/DonationModal.jsx +++ b/src/components/modals/donationModal/DonationModal.jsx @@ -1,8 +1,8 @@ import creditImg from '@/assets/images/credit.png'; -import { Alert } from '@/components/alert'; import { CustomButton } from '@/components/button'; import { ENDPOINTS } from '@/constants/api'; import { requestPut } from '@/utils/api'; +import { showAlert } from '@/utils/alert/alertController'; import { useRef, useState } from 'react'; import { useRevalidator } from 'react-router-dom'; import * as S from './donationModal.styles'; @@ -12,22 +12,10 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => { const [hasNoMoney, setHasNoMoney] = useState(false); const [isDonating, setIsDonating] = useState(false); const [isInvalidNumber, setIsInvalidNumber] = useState(false); - const [showAlert, setShowAlert] = useState(false); - const [alertContent, setAlertContent] = useState(''); - const [alertType, setAlertType] = useState('warning'); const inputRef = useRef(null); const prevCredit = credit; const revalidator = useRevalidator(); - const triggerAlert = (message, type = 'warning') => { - setAlertContent(message); - setAlertType(type); - setShowAlert(true); - setTimeout(() => { - setShowAlert(false); - }, 2000); - }; - const handleChangeAmount = (e) => { const amount = e.target.value; @@ -51,7 +39,7 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => { }; const handleKeyDown = (e) => { - if (e.key === '.') { + if (e.key === '.' || e.key === ' ') { e.preventDefault(); } }; @@ -67,15 +55,14 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => { const total = prevCredit - donateAmountNum; localStorage.setItem('selectedCredit', total); updateCredit(total); - - triggerAlert('후원에 성공했습니다', 'success'); + showAlert('투표에 성공했습니다', 'success'); setTimeout(() => { onClose(); revalidator.revalidate(); }, 700); } catch (e) { + showAlert('투표에 실패했습니다.', 'warning'); console.error('후원 처리 중 오류 발생', e); - triggerAlert('후원에 실패했습니다', 'warning'); } finally { setIsDonating(false); } @@ -96,6 +83,7 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => {
크레딧 { > 후원하기 - {showAlert && }
); }; From 897be1a384eb585d36efe0169cd5dffef6cb0706 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 04:12:49 +0900 Subject: [PATCH 05/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/card/Card.jsx | 4 +- .../modals/donationModal/DonationModal.jsx | 4 +- .../donationModal/donationModal.styles.js | 48 ++----------------- 3 files changed, 8 insertions(+), 48 deletions(-) diff --git a/src/components/card/Card.jsx b/src/components/card/Card.jsx index 5b19580c..dce51c29 100644 --- a/src/components/card/Card.jsx +++ b/src/components/card/Card.jsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { CustomButton } from '@/components/button'; -import creditImg from '@/assets/images/credit.png'; +import starImg from '@/assets/images/logo.png'; import { addCommas, getDaysRemaining, getDonationPercentage } from '@/utils/format'; import * as S from './card.styles'; @@ -51,7 +51,7 @@ const Card = ({ data, setModalType, setSelectedIndex, index }) => {
- 크레딧 + 크레딧

{`${addCommas(data.receivedDonations)} / ${addCommas(data.targetDonation)}`}

{daysLeft > 1 ? `D-${daysLeft}` : daysLeft === 1 ? '오늘 마감' : '마감 완료'}

diff --git a/src/components/modals/donationModal/DonationModal.jsx b/src/components/modals/donationModal/DonationModal.jsx index 157d62a2..a9d961d9 100644 --- a/src/components/modals/donationModal/DonationModal.jsx +++ b/src/components/modals/donationModal/DonationModal.jsx @@ -4,7 +4,7 @@ import { CustomButton } from '@/components/button'; import { showAlert } from '@/utils/alert/alertController'; import { ENDPOINTS } from '@/constants/api'; import { requestPut } from '@/utils/api'; -import creditImg from '@/assets/images/credit.png'; +import starImg from '@/assets/images/logo.png'; import * as S from './donationModal.styles'; const DonationModal = ({ data, credit, updateCredit, onClose }) => { @@ -81,7 +81,7 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => {
- 크레딧 + 크레딧 css` input { width: 100%; height: 100%; - padding: 1.6rem 4rem 1.6rem 1.6rem; + padding: 1.6rem 1.6rem 1.6rem 6rem; border: 1px solid ${hasNomoney || isInvalidNumber ? 'var(--error-red)' : 'var(--white-full)'}; border-radius: 8px; font-size: 2rem; @@ -140,10 +100,10 @@ export const inputContent = (hasNomoney, isInvalidNumber) => css` img { position: absolute; top: 50%; - right: 5%; + left: 5%; z-index: 1; - width: 3.6rem; - height: 3.6rem; + width: 3rem; + height: 3rem; transform: translateY(-50%); } From 86784e48665e7e0e6281d986d2955ac255350978 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 04:13:31 +0900 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=92=84Style:=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/card/card.styles.js | 7 ++++++- src/components/carousel/carousel.styles.js | 8 ++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/card/card.styles.js b/src/components/card/card.styles.js index 89f1f3f2..3948299e 100644 --- a/src/components/card/card.styles.js +++ b/src/components/card/card.styles.js @@ -102,11 +102,16 @@ export const info = css` export const statusBar = css` display: flex; justify-content: space-between; + align-items: center; p { - font-size: 1.2rem; + font-size: 0.9rem; font-weight: 400; color: var(--white); + + ${media({ + fontSize: ['0.9rem', '0.9rem', '1rem', '1.1rem', '1.2rem'], + })} } & > div > p { diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index e0aefa58..defbe12f 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -23,11 +23,6 @@ export const carouselTitle = css` export const viewportArea = css` position: relative; - - &::before { - content: ''; - background: linear-gradient(to bottom, rgb(0 0 0 / 50%), rgb(0 0 0 / 70%)); - } `; export const carouselContainer = css` @@ -67,7 +62,8 @@ export const navigationButton = (isRight) => css` ${isRight ? 'right: 0.5%' : 'left: 0.5%'}; z-index: 1; width: 3rem; - background-color: var(--black); + background: transparent; + backdrop-filter: blur(5px); transition: opacity 0.3s ease-in-out; /* 버튼에 부드러운 비활성화 효과 추가 */ transform: translateY(-125%); `; From 8e5b515d45f899877d7fdfaa9b3f1ffd4877329b Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 06:08:08 +0900 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=90=9BFix:=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0=20=EB=B3=80=EA=B2=BD=20=EC=8B=9C=20=EC=9D=BC?= =?UTF-8?q?=EB=B6=80=20=ED=9B=84=EC=9B=90=20=EB=AA=A9=EB=A1=9D=EC=9D=B4=20?= =?UTF-8?q?=EB=B3=B4=EC=9D=B4=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 29 ++++++++++++++++++---- src/components/carousel/carousel.styles.js | 8 +++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index c1cdc23c..f047f7e9 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { ArrowButton } from '@/components/button'; import { Card } from '@/components/card'; import { CAROUSEL } from '@/constants/carousel'; @@ -6,17 +6,36 @@ import * as S from './carousel.styles'; const Carousel = ({ data, setModalType, setSelectedIndex }) => { const [currentIndex, setCurrentIndex] = useState(0); + const [itemsView, setItemsView] = useState(CAROUSEL.ITEMS_VIEW); // 동적으로 ITEMS_VIEW 값을 설정 const itemsLength = data?.list?.length || 0; - // 마지막 인덱스를 계산 (데이터가 10개라면 maxIndex는 6, 즉 마지막 페이지까지 고려) - const maxIndex = Math.max(0, Math.ceil(itemsLength / CAROUSEL.ITEMS_VIEW) - 1); + useEffect(() => { + const updateItemsView = () => { + if (window.innerWidth >= 1200) { + setItemsView(3); // 1200px 이상에서는 3개 + } else if (window.innerWidth >= 1000) { + setItemsView(2); // 1000px 이상에서는 2개 + } else { + setItemsView(1); // 그 외에는 1개 + } + }; + + updateItemsView(); // 컴포넌트가 마운트 될 때 바로 실행 + window.addEventListener('resize', updateItemsView); // 화면 크기 변경 시에도 실행 + + return () => { + window.removeEventListener('resize', updateItemsView); // 컴포넌트 언마운트 시 이벤트 리스너 제거 + }; + }, []); // 빈 배열을 주어 한 번만 실행되도록 설정 + + const maxIndex = Math.max(0, Math.ceil(itemsLength / itemsView) - 1); const handleNext = () => { - setCurrentIndex((prev) => Math.min(prev + CAROUSEL.ITEMS_VIEW, maxIndex * CAROUSEL.ITEMS_VIEW)); // 4개씩 이동 + setCurrentIndex((prev) => Math.min(prev + itemsView, maxIndex * itemsView)); }; const handlePrev = () => { - setCurrentIndex((prev) => Math.max(prev - CAROUSEL.ITEMS_VIEW, 0)); // 4개씩 이동 + setCurrentIndex((prev) => Math.max(prev - itemsView, 0)); }; const getSlideOffset = () => { diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index defbe12f..2b1b810d 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -39,9 +39,15 @@ export const carouselContainer = css` export const carouselTrack = (slide) => css` display: flex; gap: 1.2rem; - transition: transform 1.5s ease-in-out; + transition: transform 0.4s ease-in-out; ${media({ + transition: [ + 'transform 0.4s ease-in-out', + 'transform 0.4s ease-in-out', + 'transform 0.7s ease-in-out', + 'transform 1s ease-in-out', + ], transform: ['none', 'none', `translateX(-${slide}px)`, `translateX(-${slide}px)`], })} `; From df46408f1dea32fa034fda69e9de42841396b6dd Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 06:16:29 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=90=9BFix:=20=EC=98=A4=EB=B2=84?= =?UTF-8?q?=ED=94=8C=EB=A1=9C=EC=9A=B0=20=ED=98=84=EC=83=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 34 ++++++++++++---------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index f047f7e9..b81f6a94 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -6,32 +6,33 @@ import * as S from './carousel.styles'; const Carousel = ({ data, setModalType, setSelectedIndex }) => { const [currentIndex, setCurrentIndex] = useState(0); - const [itemsView, setItemsView] = useState(CAROUSEL.ITEMS_VIEW); // 동적으로 ITEMS_VIEW 값을 설정 + const [itemsView, setItemsView] = useState(CAROUSEL.ITEMS_VIEW); const itemsLength = data?.list?.length || 0; useEffect(() => { const updateItemsView = () => { if (window.innerWidth >= 1200) { - setItemsView(3); // 1200px 이상에서는 3개 + setItemsView(3); } else if (window.innerWidth >= 1000) { - setItemsView(2); // 1000px 이상에서는 2개 + setItemsView(2); } else { - setItemsView(1); // 그 외에는 1개 + setItemsView(1); } }; - updateItemsView(); // 컴포넌트가 마운트 될 때 바로 실행 - window.addEventListener('resize', updateItemsView); // 화면 크기 변경 시에도 실행 + updateItemsView(); + window.addEventListener('resize', updateItemsView); return () => { - window.removeEventListener('resize', updateItemsView); // 컴포넌트 언마운트 시 이벤트 리스너 제거 + window.removeEventListener('resize', updateItemsView); }; - }, []); // 빈 배열을 주어 한 번만 실행되도록 설정 - - const maxIndex = Math.max(0, Math.ceil(itemsLength / itemsView) - 1); + }, []); const handleNext = () => { - setCurrentIndex((prev) => Math.min(prev + itemsView, maxIndex * itemsView)); + setCurrentIndex((prev) => { + const nextIndex = prev + itemsView; + return nextIndex >= itemsLength ? prev : nextIndex; + }); }; const handlePrev = () => { @@ -39,14 +40,7 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => { }; const getSlideOffset = () => { - const offset = currentIndex * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP); - if (currentIndex === maxIndex) { - return Math.min( - offset, - (itemsLength - CAROUSEL.ITEMS_VIEW) * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP), - ); - } - return offset; + return currentIndex * (CAROUSEL.DESKTOP_ITEM_WIDTH + CAROUSEL.ITEM_GAP); }; return ( @@ -80,7 +74,7 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => { = maxIndex * CAROUSEL.ITEMS_VIEW} + disabled={currentIndex + itemsView >= itemsLength} styles={S.navigationButton(true)} />
From 4da2a08843a7fb1c2b0328b9531e7e5cc4e12eb2 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 06:33:08 +0900 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=92=84Style:=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/carousel.styles.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index 2b1b810d..be3f63ac 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -68,8 +68,7 @@ export const navigationButton = (isRight) => css` ${isRight ? 'right: 0.5%' : 'left: 0.5%'}; z-index: 1; width: 3rem; - background: transparent; - backdrop-filter: blur(5px); + opacity: 0.5; transition: opacity 0.3s ease-in-out; /* 버튼에 부드러운 비활성화 효과 추가 */ transform: translateY(-125%); `; From 672637e6750e20182dbdfeadb0d5ccad5afdded6 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 07:07:51 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=EC=BA=90?= =?UTF-8?q?=EB=9F=AC=EC=85=80=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?-=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95=20-=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?-=20=EC=83=81=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 10 ++++++---- src/components/carousel/carousel.styles.js | 9 +++++---- src/constants/carousel/carousel.js | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index b81f6a94..5a794e4e 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -11,12 +11,14 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => { useEffect(() => { const updateItemsView = () => { - if (window.innerWidth >= 1200) { - setItemsView(3); - } else if (window.innerWidth >= 1000) { + if (window.innerWidth < 1000) { + setItemsView(CAROUSEL.ITEMS_VIEW); + } else if (window.innerWidth < 1200) { setItemsView(2); + } else if (window.innerWidth < 1920) { + setItemsView(3); } else { - setItemsView(1); + setItemsView(4); } }; diff --git a/src/components/carousel/carousel.styles.js b/src/components/carousel/carousel.styles.js index be3f63ac..b17cc1a9 100644 --- a/src/components/carousel/carousel.styles.js +++ b/src/components/carousel/carousel.styles.js @@ -27,9 +27,9 @@ export const viewportArea = css` export const carouselContainer = css` overflow-x: scroll; - width: 100%; scroll-snap-type: x mandatory; - scroll-behavior: smooth; + width: 100%; + &::-webkit-scrollbar { display: none; @@ -44,9 +44,9 @@ export const carouselTrack = (slide) => css` ${media({ transition: [ 'transform 0.4s ease-in-out', - 'transform 0.4s ease-in-out', + 'transform 0.6s ease-in-out', 'transform 0.7s ease-in-out', - 'transform 1s ease-in-out', + 'transform 0.9s ease-in-out', ], transform: ['none', 'none', `translateX(-${slide}px)`, `translateX(-${slide}px)`], })} @@ -55,6 +55,7 @@ export const carouselTrack = (slide) => css` export const carouselItem = css` flex-basis: 15.8rem; min-width: 15.8rem; + scroll-snap-align: start; ${media({ flexBasis: ['15.8rem', '15.8rem', '28.2rem', '28.2rem'], diff --git a/src/constants/carousel/carousel.js b/src/constants/carousel/carousel.js index b949f279..4aca31c8 100644 --- a/src/constants/carousel/carousel.js +++ b/src/constants/carousel/carousel.js @@ -1,7 +1,7 @@ const CAROUSEL = { DESKTOP_ITEM_WIDTH: 282, ITEM_GAP: 12, - ITEMS_VIEW: 4, + ITEMS_VIEW: 1, }; export default CAROUSEL; From c2c1a3f291bb731d7ce83134f55559be204c303a Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 07:34:28 +0900 Subject: [PATCH 11/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20=ED=9B=84?= =?UTF-8?q?=EC=9B=90=20=EB=AA=A8=EB=8B=AC=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/modals/donationModal/DonationModal.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/modals/donationModal/DonationModal.jsx b/src/components/modals/donationModal/DonationModal.jsx index a9d961d9..4aae7027 100644 --- a/src/components/modals/donationModal/DonationModal.jsx +++ b/src/components/modals/donationModal/DonationModal.jsx @@ -1,7 +1,7 @@ import { useRef, useState } from 'react'; import { useRevalidator } from 'react-router-dom'; import { CustomButton } from '@/components/button'; -import { showAlert } from '@/utils/alert/alertController'; +import { showAlert } from '@/utils/alert'; import { ENDPOINTS } from '@/constants/api'; import { requestPut } from '@/utils/api'; import starImg from '@/assets/images/logo.png'; @@ -55,7 +55,7 @@ const DonationModal = ({ data, credit, updateCredit, onClose }) => { const total = prevCredit - donateAmountNum; localStorage.setItem('selectedCredit', total); updateCredit(total); - showAlert('투표에 성공했습니다', 'success'); + showAlert('후원 완료!', 'success'); setTimeout(() => { onClose(); revalidator.revalidate(); From 1fb8205377a7146bd62aade780676b76d97b95f4 Mon Sep 17 00:00:00 2001 From: Jo Insung Date: Tue, 29 Apr 2025 14:33:07 +0900 Subject: [PATCH 12/12] =?UTF-8?q?=E2=99=BB=EF=B8=8FRefactor:=20resize=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 커밋 메시지 형식 # <이모지><타입>: <제목> (#이슈 번호) # # ⛔ 제목은 100자 이내, 끝에 마침표(.) 사용 금지 # ⛔ 이모지와 타입 사이에 공백 없이 붙여 씁니다 (예: ✨Feat) # ⛔ 제목과 콜론(:) 사이에 공백 없이 붙이고, 콜론 뒤에는 공백 1칸 필요 # ✅ 제목은 커밋의 "무엇"을 나타냅니다 # ✅ 본문은 "왜", "어떻게"를 요약하며, 선택사항입니다 # ✅ 본문은 여러 줄의 메시지를 작성할 땐 "-"로 구분 # 예시: # ✨Feat: 마이페이지 수정 기능 추가 (#15) # 커밋 타입 가이드: # ✨ Feat : 새로운 기능 추가 # 🐛 Fix : 버그 수정 # 📦 Chore : 설정/빌드 수정, 기타 잡일 # 💄 Style : 포맷팅, 세미콜론 등 비즈니스 로직 없는 변경 # 📝 Docs : 문서 작성 및 수정 # ♻️ Refactor : 리팩토링 (동작 변경 없이 코드 개선) --- src/components/carousel/Carousel.jsx | 4 +--- src/constants/carousel/carousel.js | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/carousel/Carousel.jsx b/src/components/carousel/Carousel.jsx index 5a794e4e..efeff225 100644 --- a/src/components/carousel/Carousel.jsx +++ b/src/components/carousel/Carousel.jsx @@ -14,10 +14,8 @@ const Carousel = ({ data, setModalType, setSelectedIndex }) => { if (window.innerWidth < 1000) { setItemsView(CAROUSEL.ITEMS_VIEW); } else if (window.innerWidth < 1200) { - setItemsView(2); - } else if (window.innerWidth < 1920) { setItemsView(3); - } else { + } else if (window.innerWidth < 1920) { setItemsView(4); } }; diff --git a/src/constants/carousel/carousel.js b/src/constants/carousel/carousel.js index 4aca31c8..835ec465 100644 --- a/src/constants/carousel/carousel.js +++ b/src/constants/carousel/carousel.js @@ -1,7 +1,7 @@ const CAROUSEL = { DESKTOP_ITEM_WIDTH: 282, ITEM_GAP: 12, - ITEMS_VIEW: 1, + ITEMS_VIEW: 2, }; export default CAROUSEL;