원티드 X 코드스테이츠 프리온보딩 프론트엔드 과정 기업과제 4번

원티드 X 코드스테이츠 프리온보딩 프론트엔드 과정 기업과제 4번

담당했던 부분 : 전체페이지 Grid 구현 / Loading Indicator 제작


✨ 주요 기능

  • [상단 Tab bar]는 Click을 통해 각각의 Tab으로 이동할 수 있습니다. Tab 간 이동 시 슬라이딩 애니메이션을 넣습니다.
  • [공유하기] 기능은 해당 컨텐츠 링크를 새 창으로 띄웁니다.
  • [새로 올라왔어요]의 Carousel View는 5초에 한번씩 바로 다음 컨텐츠로 슬라이딩 애니메이션 처리가 되면서 이동합니다.
  • [더보기] 버튼을 눌렀을 때 모든 컨텐츠가 각 sector에 맞게 조회됩니다.
  • 전역 데이터 관리를 도입하여 구현합니다.
  • 프론트엔드 서버는 localhost:8888 으로 설정되어 있습니다.

시간이 훌쩍 가서 마지막 프로젝트! 이번 프로젝트에서는 더더욱 맡은 부분이 크지 않았다. 나는 기본적으로 동떨어져 있는 컴포넌트 하나를 만들거나 전체적인 그리드 부분을 잡거나 하는 걸 잘 하고 흥미로워 한다는 것을 짧은 프로젝트들 여러 개를 해 보면서 배워나갔던 시간이었던 것 같다.

이번에도 로딩인디케이터를 만들면서 키프레임과 여러가지 transition에 대해 좀 더 학습하는 시간이 되었던 것 같고, 전체적인 그리드를 잡는 부분에서도 더 학습하게 되었다.

협업은 언제나 중요하지만 전체적인 틀만 잡고 가느냐 아니면 세세한 부분까지도 일단 이야기 해보고느냐에서 차이가 많이 난다는 것도 배운 시간이었다. 이번 프로젝트는 모바일로 제작되어 있는 환경의 서비스를 웹페이지로 만들어보라는 것이었는데 모바일은 참고를 해서 디자인을 하면 되지만 웹 쪽은 팀원들과 이야기를 나누어 배치를 어떻게 해야 할지 등등을 이야기 해야 했다.

모바일 같은 경우에는 가로가 좁고 세로가 긴 형태이니까 새로올라왔어요 와 상세리스트가 row 형태로 되어야 하지만, 웹의 경우에는 가로가 길고 세로가 짧은 형태이니 이 둘이 column 형태로 바뀌는 식이 되었다. 이 과정에서 그리드를 잡을 때 내가 맡은 파트에서만 하면 되는 게 아니라 이 안에 컨텐츠를 끼워넣게 되니까 컨텐츠를 맡은 팀원들에게 '패딩이나 마진은 내 쪽에서 책임질테니 작업을 할 때 크기를 100%로 해서 작업해주세요'라고 미리 말을 해 놓았으면 나중에 합쳤을 때 조정하는 시간이 덜 걸렸을 것이라는 뒤늦은 깨달음도 얻었다. 이걸 조정하는 데에 엄청난 시간이 걸리거나 대단히 어려운 작업은 아니지만 쓰지 않아도 되는 시간을 할애한 셈이니 결과적으로는 낭비가 아닌가 하는 생각이 들었다.

또 하나 알게 된 것은 position: firxed는 루트 기준으로 크기를 잡게 되는 것이고 position: absolute는 가장 가까운 부모 컴포넌트 기준으로 크기를 잡게 되는 것이라고 한다.

import React from 'react';
import styled from '@emotion/styled';

const LoadingIndicator = () => {
  return (
    <Ring>LOADING
      <span></span>
    </Ring>
  );
};

const Ring = styled.div`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  width: 15rem;
  height: 15rem;
  background: transparent;
  border: 1rem solid #23a2f7;
  border-radius: 50%;
  text-align: center;
  line-height: 13.5rem;
  font-size: 2rem;
  font-weight: 1000;
  color: #23a2f7;
  letter-spacing: 0.3rem;
  box-shadow: 0 0 2rem rgba(0,0,0,.5);
  text-shadow: 0.2rem 0.2rem 0.2rem lightblue;
  :before {
    content: '';
    position: absolute;
    top: -1rem;
    left: -1rem;
    width: 100%;
    height: 100%;
    border: 1rem solid transparent;
    border-top: 1rem solid #002473;
    border-right: 1rem solid #002473;
    border-radius: 50%;
    animation: animateC 3s linear infinite;
}
  span
  {
    display: block;
    position: absolute;
    top: calc(50% - 0.2rem);
    left: 50%;
    width: 50%;
    height: 0.4rem;
    background: transparent;
    transform-origin: left;
    animation: animate 3s linear infinite;
  }
  span:before
  {
    content: '';
    position: absolute;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: #002473;
    top: 0rem;
    right: -1.4rem;
    box-shadow:0 0 2rem #002473;
  }
  @keyframes animateC
  {
    0%
    {
      transform:rotate(0deg);
    }
    100%
    {
      transform:rotate(360deg);
    }
  }
  @keyframes animate
  {
    0%
    {
      transform:rotate(45deg);
    }
    100%
    {
      transform:rotate(405deg);
    }
  }
`

export default LoadingIndicator;

import React from 'react'
import styled from '@emotion/styled'

interface ITemplate {
  children?: React.ReactNode
}

export default function Template({ children }: ITemplate) {
  return (
    <>
      <PageWrapper>{children}</PageWrapper>
    </>
  )
}

const PageWrapper = styled.div`
  margin: 3rem;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: minmax(auto, calc(100vh - 13rem));
  height: 100%;
  grid-gap: 3rem;

  @media (max-width: 768px) {
    display: flex;
    flex-direction: column;
  }
`

좋은 웹페이지 즐겨찾기