Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SP3] 메인 하단 파트 구성 섹션 반응형 #317

Merged
merged 11 commits into from
Dec 15, 2023
4 changes: 2 additions & 2 deletions src/assets/icons/ic_arrow_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/assets/icons/ic_arrow_right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions src/hooks/useDrag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useRef, useState } from 'react';

function useDrag() {
const dragRef = useRef<HTMLDivElement>(null);
const [dragging, setDragging] = useState(false);
const [clickPoint, setClickPoint] = useState(0);
const [scrollLeft, setScrollLeft] = useState(0);

const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
setDragging(true);
if (dragRef.current) {
setClickPoint(e.pageX);
setScrollLeft(dragRef.current.scrollLeft);
}
};

const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!dragging) return;
e.preventDefault();
if (dragRef.current) {
const draggedAmount = e.pageX - clickPoint;
dragRef.current.scrollLeft = scrollLeft - draggedAmount;
}
};

const initDragging = () => {
setDragging(false);
};

return { dragRef, handleMouseDown, handleMouseMove, initDragging };
}

export default useDrag;
49 changes: 48 additions & 1 deletion src/hooks/useInfiniteCarousel.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { useEffect, useRef, useState } from 'react';

const SWIPE_THRESHOLD = 50;
const NEXT = 1;
const PREVIOUS = -1;

export type DirectionType = typeof PREVIOUS | typeof NEXT;

const useInfiniteCarousel = <T>(carouselList: Array<T>, x: string) => {
const TOTAL_SLIDE = carouselList.length;
const [infiniteCarouselList, setInfiniteCarouselList] = useState(carouselList);
const [currentIndex, setCurrentIndex] = useState(0);
const carouselRef = useRef<HTMLDivElement>(null);
const [slideIndex, setSlideIndex] = useState(0);
const [touchStartX, setTouchStartX] = useState(0);

useEffect(() => {
const firstSide = carouselList[0];
Expand Down Expand Up @@ -36,13 +44,52 @@ const useInfiniteCarousel = <T>(carouselList: Array<T>, x: string) => {
}
};

const handleSelectSlide = (clickedIndex: number) => {
setSlideIndex(clickedIndex);
handleSwipe(clickedIndex - slideIndex);
};

const handleCarouselSwipe = (direction: DirectionType) => {
const totalSlide = carouselList.length;
const newIndex = slideIndex + direction;
if (direction === NEXT) {
setSlideIndex(newIndex === totalSlide ? 0 : newIndex);
} else {
setSlideIndex(newIndex === -1 ? totalSlide - 1 : newIndex);
}
handleSwipe(direction);
};

const handleTouchStart = (e: React.TouchEvent<HTMLDivElement>) => {
setTouchStartX(e.touches[0].clientX);
};

const handleTouchEnd = (e: React.TouchEvent<HTMLDivElement>) => {
const endX = e.changedTouches[0].clientX;
const deltaX = touchStartX - endX;
if (deltaX > SWIPE_THRESHOLD) {
handleCarouselSwipe(NEXT);
} else if (deltaX < -SWIPE_THRESHOLD) {
handleCarouselSwipe(PREVIOUS);
}
};

useEffect(() => {
if (carouselRef.current) {
carouselRef.current.style.transform = `translateX(calc(${currentIndex} * ${x}))`;
}
}, [currentIndex, x]);

return { carouselRef, infiniteCarouselList, handleSwipe };
return {
carouselRef,
infiniteCarouselList,
slideIndex,
handleSelectSlide,
handleCarouselSwipe,
handleSwipe,
handleTouchStart,
handleTouchEnd,
};
};

export default useInfiniteCarousel;
106 changes: 63 additions & 43 deletions src/lib/constants/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,140 +277,160 @@ export const keywordList: KeywordListType = {
{
content: '린스타트업 기초',
...yellowStyle,
top: '92.97px',
right: '217.71px',
desktop: { top: '92.97px', right: '11.34vw' },
tablet: { top: '258px', right: '8.59vw' },
mobile: { top: '148px', right: '10.74vw' },
},
{
content: 'IT 프로덕트 기획',
...indigoStyle,
top: '157.13px',
right: '353.2px',
desktop: { top: '157.13px', right: '18.39vw' },
tablet: { top: '297px', right: '29.03vw' },
mobile: { top: '177px', right: '27.1vw' },
},
{
content: '전반적인 매니징',
...blueStyle,
top: '282.28px',
right: '241.04px',
desktop: { top: '282.28px', right: '12.55vw' },
tablet: { top: '383px', right: '11.06vw' },
mobile: { top: '223px', right: '12.86vw' },
},
],
[Part.DESIGN]: [
{
content: '피그마와 같은 협업툴',
...skyStyle,
top: '92.97px',
right: '175.71px',
desktop: { top: '92.97px', right: '9.15vw' },
tablet: { top: '259px', right: '5.72vw' },
mobile: { top: '149.28px', right: '5.98vw' },
},
{
content: 'UX/UI 전반적 과정',
...indigoStyle,
top: '157.13px',
right: '328.2px',
desktop: { top: '157.13px', right: '17.09vw' },
tablet: { top: '306px', right: '20.18vw' },
mobile: { top: '176.14px', right: '20.9vw' },
},
{
content: '새로운 프로덕트',
...blueStyle,
top: '282.28px',
right: '241.04px',
desktop: { top: '282.28px', right: '12.55vw' },
tablet: { top: '386px', right: '11.97vw' },
mobile: { top: '222.02px', right: '12.38vw' },
},
],
[Part.ANDROID]: [
{
content: 'UI 구현 기초/심화',
...yellowStyle,
top: '117.6px',
right: '118.42px',
desktop: { top: '117.6px', right: '6.16vw' },
tablet: { top: '303px', right: '6.38vw' },
mobile: { top: '175px', right: '6.07vw' },
},
{
content: 'Kotlin 언어 활용',
...indigoStyle,
top: '96px',
right: '307.71px',
desktop: { top: '96px', right: 'calc(115px + 10vw)' },
tablet: { top: '287px', right: 'calc(110px + 10.15vw)' },
mobile: { top: '163px', right: 'calc(50px + 14.06vw)' },
},
{
content: '서버 통신',
...blueStyle,
top: '232px',
right: '141.08px',
desktop: { top: '232px', right: '7.34vw' },
tablet: { top: '373px', right: '8.85vw' },
mobile: { top: '218px', right: '10.74vw' },
},
{
content: '페어 프로그래밍',

...greenStyle,
top: '278.38px',
right: '241.04px',
desktop: { top: '278.38px', right: 'calc(50px + 10vw)' },
tablet: { top: '379px', right: '28.77vw' },
mobile: { top: '225px', right: '29.43vw' },
},
],
[Part.IOS]: [
{
content: 'iOS 앱 서비스',
...indigoStyle,
top: '82.31px',
right: '294.93px',
desktop: { top: '82.31px', right: 'calc(102px + 10vw)' },
tablet: { top: '305px', right: 'calc(100px + 9.11vw)' },
mobile: { top: '178px', right: 'calc(50px + 12vw)' },
},
{
content: 'Swift와 UI Kit',
...yellowStyle,
top: '117.6px',
right: '129.08px',
desktop: { top: '117.6px', right: '6.72vw' },
tablet: { top: '324px', right: '6.38vw' },
mobile: { top: '188px', right: '6.07vw' },
},
{
content: '보충 및 심화 세미나',
backgroundColor: '#D65438',
color: '#fff',
top: '223.74px',
right: '129.08px',
desktop: { top: '223.74px', right: 'calc(33px + 5vw)' },
tablet: { top: '400px', right: '16.79vw' },
mobile: { top: '235px', right: '15.42vw' },
},
{
content: '왕초보 스터디',
...blueStyle,
top: '275.88px',
right: '365.24px',
desktop: { top: '275.88px', right: '19.02vw' },
tablet: { top: '360px', right: '39.97vw' },
mobile: { top: '212px', right: '38.78vw' },
},
],
[Part.WEB]: [
{
content: '웹 서비스 개발',
...yellowStyle,
top: '92.97px',
right: '231.71px',
desktop: { top: '92.97px', right: '12.06vw' },
tablet: { top: '262px', right: '10.93vw' },
mobile: { top: '158px', right: '13.08vw' },
},
{
content: '기초부터 심화까지',
...indigoStyle,
top: '157.13px',
right: '339.2px',
desktop: { top: '157.13px', right: '17.66vw' },
tablet: { top: '314px', right: '27.47vw' },
mobile: { top: '188px', right: '29vw' },
},
{
content: 'UI구현과 서버 통신',
...skyStyle,
top: '282.28px',
right: '216.04px',
desktop: { top: '282.28px', right: '11.25vw' },
tablet: { top: '382px', right: '8.33vw' },
mobile: { top: '228px', right: '10.74vw' },
},
],
[Part.SERVER]: [
{
content: '서버 애플리케이션 구축',
...greenStyle,
top: '92.97px',
right: '156.71px',
desktop: { top: '92.97px', right: '8.16vw' },
tablet: { top: '301px', right: '12.10vw' },
mobile: { top: '178px', right: '15.42vw' },
},
{
content: '관계형 데이터베이스',
...indigoStyle,
top: '157.13px',
right: '101.2px',
desktop: { top: '157.13px', right: 'calc(30px + 3.69vw)' },
tablet: { top: '346px', right: '5.2vw' },
mobile: { top: '203px', right: '8.4vw' },
},
{
content: 'AWS 기반',
...skyStyle,
top: '192px',
right: '400.2px',
desktop: { top: '192px', right: 'calc(110px + 15.1vw)' },
tablet: { top: '323px', right: 'calc(110px + 28vw)' },
mobile: { top: '196px', right: '45.79vw' },
},
{
content: 'Spring 프레임 워크',
...blueStyle,
top: '282.28px',
right: '208.04px',
desktop: { top: '282.28px', right: '10.83vw' },
tablet: { top: '389px', right: '25vw' },
mobile: { top: '235px', right: '25.7vw' },
},
],
};
Expand Down
5 changes: 3 additions & 2 deletions src/lib/types/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ type KeywordType = {
content: string;
backgroundColor: string;
color: string;
top: string;
right: string;
desktop: { top: string; right: string };
tablet: { top: string; right: string };
mobile: { top: string; right: string };
};

export type KeywordListType = Record<Part, KeywordType[]>;
Expand Down
19 changes: 19 additions & 0 deletions src/views/MainPage/components/PartConfig/PartButton.tsx/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,23 @@ export const PartButton = styled.button<{ isSelected: boolean }>`
letter-spacing: -0.84px;

cursor: pointer;

@media (max-width: 768px) {
width: 118.982px;
height: 41.313px;

font-size: 17.352px;
line-height: 21.552px; /* 124.206% */
letter-spacing: -0.694px;
}

@media (max-width: 428px) {
width: 68.38px;
height: 23.743px;
border-radius: 5.698px;

font-size: 10px;
line-height: 12.386px; /* 123.859% */
letter-spacing: -0.4px;
}
`;
Loading
Loading