웹/개인 프로젝트

포트폴리오 웹사이트 클론코딩 회고록

공대생철이 2022. 7. 11. 21:37
728x90

https://www.youtube.com/watch?v=OPaLnMw2i_0&list=PL6QREj8te1P7gixBDSU8JLvQndTEEX3c3

 

어떤 스프린트를 해볼까하다가 Next를 좀 더 익숙하게 다뤄보고자 하는 마음에 클론코딩을 하나 더 해보기로 했다.

 

저번에 했던 포트폴리오 웹사이트인데 전혀 다른 구성과 디자인으로 해보았다.

 

일단 완성본부터 보자.

 

솔직히 유튜브 영상 썸네일이 너무 까리해보여서 선택하기는 했음.

 

SPA(single page application)이고 페이지 구성은

 

-헤더와 푸터

-Hero 섹션

-Projects 섹션

-Technology 섹션

-Timeline 섹션

- Accomplishments 섹션

 

헤더와 푸터는 그렇게 어려운 부분이 없었다.

컴포넌트를 좀더 잘게 쪼개어 헤더와 푸터 내부에서 Div1, Div2, DIv3로 나누어 구성하였다.

		<Div2>
			<li>
				<Link href='#projects'>
					<NavLink>Project</NavLink>
				</Link>
			</li>
			<li>
				<Link href='#tech'>
					<NavLink>Technologies</NavLink>
				</Link>
			</li>
			<li>
				<Link href='#about'>
					<NavLink>About</NavLink>
				</Link>
			</li>
		</Div2>

이번에 처음 알게 된 건데 id를 href로 받았다.

이게 뭐지? 했는데

해당되는 id를 가진 섹션으로 페이지가 이동하게 되는 것이다.

 

예를 들어 Technologies 링크를 클릭하면

아래의 Technologies 섹션으로 자동스크롤 되면서 넘어간다.

이건 좀 신기방기

 

 

Hero 섹션

 

역시 컴포넌트들을 조합하여 위치만 조정해주면 되는데 여기서 새롭게 추가된 것

			<Button
				onClick={() => {
					window.location = "https://google.com";
				}}>
				Learn More
			</Button>

버튼에 window.location을 추가해주었다. 

보통 html a 태그나 nextjs에서의 link 태그로 링크를 많이 걸어줬는데

button을 활용하여 window.location으로 링크를 걸어주었다.

 

Projects 섹션

 

<Section nopadding id='projects'>
		<SectionDivider />
		<SectionTitle main>Projects</SectionTitle>
		<GridContainer>
			{projects.map(({ image, title, description, tags, source, visit }) => {
				return (
					<BlogCard>
						<Img src={image} />
						<TitleContent>
							<HeaderThree title>{title}</HeaderThree>
							<Hr />
						</TitleContent>
						<CardInfo>{description}</CardInfo>
						<div>
							<TitleContent>Stack</TitleContent>
							<TagList>
								{tags.map((tag, i) => {
									return <Tag key={i}>{tag}</Tag>;
								})}
							</TagList>
						</div>
						<UtilityList>
							<ExternalLinks href={visit}>Code</ExternalLinks>
							<ExternalLinks href={source}>Source</ExternalLinks>
						</UtilityList>
					</BlogCard>
				);
			})}
		</GridContainer>
	</Section>

BlogCard라는 컴포넌트로 map을 돌렸고 BlogCard 안에서 컴포넌트들을 조합해서 만들었다. 

더미 데이터를 활용하여 projects를 만들어서 돌린건데

그 안에 프로젝트 주소와 소스 코드를 볼 수 있는 링크가 포함되어있는 object 형식으로 만들었다.

그래서 object 안의 visit과 source를 각각 link url로 받을 수 있도록 하였다.

그 외에는 별다른 특이사항 없음.

 

Technology 섹션

 

List로 만들어서 각각 아이콘이랑 글자만 따로 넣어주었음.

컴포넌트들 짬뽕해서 만든 거라 시간도 엄청 짧게 걸림.

 

Timeline 섹션 

 

이게 제일 어려웠다.

사실 지금도 이해를 잘 못했다.

<CarouselContainer ref={carouselRef} onScroll={handleScroll}>
				<>
					{TimeLineData.map((item, index) => {
						return (
							<CarouselMobileScrollNode
								key={index}
								final={index === TOTAL_CAROUSEL_COUNT - 1}>
								<CarouselItem
									index={index}
									id={`carousel_item-${index}`}
									active={activeItem}
									onClick={(event) => handleClick(event, index)}>
									<CarouselItemTitle>
										{item.year}
										<CarouselItemImg
											width='208'
											height='6'
											viewBox='0 0 208 6'
											fill='none'
											xmlns='http://www.w3.org/2000/svg'>
											<path
												fill-rule='evenodd'
												clip-rule='evenodd'
												d='M2.5 5.5C3.88071 5.5 5 4.38071 5 3V3.5L208 3.50002V2.50002L5 2.5V3C5 1.61929 3.88071 0.5 2.5 0.5C1.11929 0.5 0 1.61929 0 3C0 4.38071 1.11929 5.5 2.5 5.5Z'
												fill='url(#paint0_linear)'
												fill-opacity='0.33'
											/>
											<defs>
												<linearGradient
													id='paint0_linear'
													x1='-4.30412e-10'
													y1='0.5'
													x2='208'
													y2='0.500295'
													gradientUnits='userSpaceOnUse'>
													<stop stop-color='white' />
													<stop
														offset='0.79478'
														stop-color='white'
														stop-opacity='0'
													/>
												</linearGradient>
											</defs>
										</CarouselItemImg>
									</CarouselItemTitle>
									<CarouselItemText>{item.text}</CarouselItemText>
								</CarouselItem>
							</CarouselMobileScrollNode>
						);
					})}
				</>
			</CarouselContainer>

Carousel 형식으로 만들었는데 위의 부분이 Carousel의 데이터가 담겨있는 부분이다. 

이렇게 숫자 + 별똥별 + 내용으로 구성되어있는 컴포넌트를 연도별로 map을 돌린 것이다. 

이게 컴퓨터 모니터상으로는 이제 별 문제가 없다.

하지만 반응형을 안하면 섭하지.

 

그래서 모바일에서는 내용을 스크롤할 수 있도록 만들어주려고 했다.

	const [activeItem, setActiveItem] = useState(0);
    
	//useRef를 활용하여 carouselContainer으로 Dom으로 활용할 수 있도록 했다.
    const carouselRef = useRef();
	
    //선택된 노드를 왼쪽으로 스크롤하는 함수
	const scroll = (node, left) => {
		return node.scrollTo({ left, behavior: "smooth" });
	};
	
    //해당 아이템을 클릭하면 맨 왼쪽에 올 수 있도록 자동 스크롤. 없으면 그냥 스크롤기능만
	const handleClick = (e, i) => {
		e.preventDefault();

		if (carouselRef.current) {
			const scrollLeft = Math.floor(
				carouselRef.current.scrollWidth * 0.7 * (i / TimeLineData.length)
			);

			scroll(carouselRef.current, scrollLeft);
		}
	};
	
    //스크롤된 정도에 따라 중간에서 놓았을 때 넘어갈 위치 정해준다.
	const handleScroll = () => {
		if (carouselRef.current) {
			const index = Math.round(
				(carouselRef.current.scrollLeft /
					(carouselRef.current.scrollWidth * 0.7)) *
					TimeLineData.length
			);

			setActiveItem(index);
		}
	};
    
   //화면 창이 바뀌면 다시 처음화면으로 돌아오게 만들기
    useEffect(() => {
		const handleResize = () => {
			scroll(carouselRef.current, 0);
		};

		window.addEventListener("resize", handleResize);
	}, []);

스크롤 기능을 넣어준 코드들이다. 각각의 설명은 코드 위에 있으니 참고.

<CarouselButtons>
				{TimeLineData.map((item, index) => {
					return (
						<CarouselButton
							key={index}
							index={index}
							active={activeItem}
							onClick={(event) => handleClick(event, index)}>
							<CarouselButtonDot active={activeItem} />
						</CarouselButton>
					);
				})}
</CarouselButtons>

그리고 아이템들 중 어떤 것들에 해당되어있는지 알려주는 점 5개를 보여주었다.

이걸 말하는 거다.

그래서 5개의 아이템 중 focus가 몇번째에 되어있는지 위에서 useState로 불러온 activeItem으로 추적하고 그 index에 해당하는 점의 opacity와 scale을 키워 표시될 수 있도록 했다.

 

지금 회고하면서 조금 더 이해가 된 거 같긴 한데 혼자 하라하면 못할듯. 그래서 다시 봐야됨.

 

Accomplishments 섹션

 

걍 컴포넌트들 짬뽕

데이터 별로 map만 돌리면 끝.

 

그래서 완성한 결과는 이렇다.

모바일 디자인이 핵심이었기에 모바일로 스샷을 찍었다.


배운점

- 링크를 href가 아니라 window.location으로 걸어도 되는구나.(근데 둘의 차이점이 과연 뭘까?)

- 링크에서 url이 아니라 id로 href를 걸면 자동으로 그 section으로 찾아가는구나. (이건 진짜 신박했는데 왜 몰랐을까?)

- 모바일에서 양 옆으로 스크롤하는 것도 내장 메소드가 다 있다. 잘 활용하면 만들 수 있음.

 

아쉬운 점

-이번 클론코딩은 이미 디자인이 다 되어있는 컴포넌트에 각각의 component들을 끼워맞추기만 하면 되는 작업이었다. 그  래서 직접 css를 다루지는 못했다는 점이 좀 아쉬웠다.

- 처음 세팅되어있는 컴포넌트들이 진짜 많았어서 뭔지도 모르고 따라치기만 한 부분도 꽤 많았던 것 같다. 그래도 그 부분은 제외하고 페이지 구성의 매커니즘을 이해하는 데 포커싱을 두었다.

 

728x90