React Progress Bar 코드와 디자인

리액트 프로그레스 바를 어떤 식으로 작동 시키고, 또 어떤 식으로 디자인을 하면 좋을지 알아보겠습니다.

최종적으로 ProgressBar 컴포넌트와 이 컴포넌트를 상위 컴포넌트에서 어떻게 사용하면 되는지 정리하겠습니다. 

ProgressBar 컴포넌트 코드

				
					const ProgressButton = ({ pageInfo, setCurrentPage, currentpage }) => {
  return (
    <div className="progress-container">
      {Object.entries(pageInfo).map(([pageNumber, pageName]) => (
        <button
          key={pageNumber}
          type="button"
          className={`progress_button ${
            parseInt(currentpage) === parseInt(pageNumber) ? "active" : ""
          }`}
          onClick={() => setCurrentPage(parseInt(pageNumber))}
        >
          {pageName}
        </button>
      ))}
    </div>
  );
};

export default ProgressButton;

				
			

우선 ProgressBar 에 관한 코드입니다.

pageInfo 라는 객체를 가지고 구성이 됩니다. 

Object.entries 를 통해서 객체를 key 와 value 를 한 쌍으로 순회 가능하도록 합시다.

객체의 key 값이 pageNumber 으로 value 가 pageName 으로 차근차근 순회합니다.

이때 props 로 받은 currentpage 와 현재 pageNumber 와 동일하다면 Button 의 className 뒤에 “active” 가 붙게 됩니다.

그리고 버튼을 클릭하면, 해당 버튼의 pageNumber을 setCurrnetPage라는 함수를 통해서 상위 컴포넌트로 전달할 계획입니다.

그리고 이 코드를 꾸미기 위한 CSS 는 다음과 같이 작업했습니다. 

				
					/* ProgressBar 기준 */
@font-face {
    font-family: 'maple';
    src: url('../Font/SOYO Maple Regular.ttf') format('truetype');
  }

/* 폼 상단에 위치한 Progress 버튼에 관한 내용입니다. */
    
  /* 프로그레스 버튼이 담긴 상자이며, 이것을 중앙으로 오도록 설정하고 있습니다. */
  .progress-container{
    margin-top: 5px;
    display: flex;
    justify-content: center;
    margin-bottom: 1rem;
  }

  .progress-container button:first-child {
    border-top-left-radius: 10px; /* 왼쪽 상단 모서리 둥글게 */
    border-bottom-left-radius: 10px; /* 왼쪽 하단 모서리 둥글게 */
  }
  
  .progress-container button:last-child {
    border-top-right-radius: 10px; /* 오른쪽 상단 모서리 둥글게 */
    border-bottom-right-radius: 10px; /* 오른쪽 하단 모서리 둥글게 */
  }
  

  .progress_button{
    width: 150px;
    height: 60px;
    text-align: center;
    padding: 5px 0;
    border: none;
    background-color: #D3D3D3;
    color: white;
    cursor: pointer;
    transition: all 0.3s;
    transform-style: preserve-3d;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    position: relative;
    font-weight: bold;
    font-family: "maple";

  }
  
  
  .progress_button:hover {
    background-color: #FFB6C1;
    box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
    transform: translateY(-2px);
  }
  
  .progress_button.active {
    background-color: #AAF0D1;
    box-shadow: 0 6px 8px rgba(0, 0, 0, 0.2);
    transform: translateY(-2px);
  }
				
			

위와 같이 작업했습니다.

혹시 font-family 에 maple 폰트체가 없을 경우 오류가 발생할 수 있습니다.

폰트를 넣고 싶은데 방법을 모른다면 아래 포스팅을 참고해주세요. 

상위 컴포넌트 코드

				
					const Script = () => {

  //해당 Form을 구성하기 위한 변수 설정입니다.
  const pageInfo = { 1: "애니 정보", 2: "애니 감상", 3: "애니 평가" };

  //ProgressBar 에서 선택되는 페이지 (기본적으로는 1이 설정)
  const [currentpage, setCurrentPage] = useState(1);

  return (
    <>

      <div className="page-0" style={{ marginTop: "5rem" }}>
        <form>
          <ProgressButton
            pageInfo={pageInfo}
            setCurrentPage={setCurrentPage}
            currentpage={currentpage}
          />
        </form>
      </div>
    </>
  );
};

export default Script;
				
			

아까 만들었던 자식 컴포넌트인 ProgressButton 을 가져와서 다음과 같이 사용할 겁니다.

기본적으로 객체 형태의 PageInfo 를 사용할 것이며, 이 객체의 key 값은 int 입니다. 

가장 처음에는 currentPage를 원하는 key 값으로 선택을 해주면 가장 처음 페이지를 생성할 때 해당 버튼이 activate 됩니다.

위와 같이 CSS가 적용되어 나타나는 모습을 볼 수 있습니다.

괜찮죠?

위와 같이 여러 개를 왔다갔다 누를 수 있습니다.

색깔의 경우는 기존 CSS 코드에서 색깔 코드를 변경하여 원하는 색깔을 입힐 수 있습니다. 

약간의 디자인 추가

				
					import React from "react";

const ProgressBar = ({ currentpage, pageInfo }) => {
  return (
    <div className="progress">
      <div className="progress-label">
        {Math.round(
          (100 * parseInt(currentpage, 10)) / Object.entries(pageInfo).length
        )}
        %
      </div>

      <div
        className="progress-bar"
        style={{
          width: `${(100 * currentpage) / Object.entries(pageInfo).length}%`,
          backgroundColor:
            (100 * currentpage) / Object.entries(pageInfo).length <= 50
              ? "#E6D1FF"
              : (100 * currentpage) / Object.entries(pageInfo).length < 100
              ? "#FFFFD1"
              : "#FFD1DC",
        }}
      ></div>
    </div>
  );
};

export default ProgressBar;

				
			

위에 있는 버튼만으로도 좋지만, 조금 더 꾸미기 위해 만든 코드입니다.

이 코드의 주요적 특징은 현재의 패이지 값과, 페이지 구성 정보를 사용하여 막대를 생성하기 위함입니다.

먼저 progress-label 부분에 있는 내용을 볼까요?

				
					      <div className="progress-label">
        {Math.round(
          (100 * parseInt(currentpage, 10)) / Object.entries(pageInfo).length
        )}
        %
      </div>
				
			

parseInt 는 () 내부에 있는 값을 정수로 변환하는 방법입니다.

뒤에 있는 10은 10진수 형식으로 내보내겠다는 뜻입니다. 

Object.entries().length 를 하면 객체의 Key : value 쌍의 개수와 같은 값이 들어가겠죠.

객체의 key: value 쌍이 전체 3개고, 현재 페이지의 값이 1이라면 100에 1/3 을 곱한 33.333333 이 결과가 됩니다.

이 결과를 Math.round 를 통해서 반올림 해줍니다.

				
					      <div
        className="progress-bar"
        style={{
          width: `${(100 * currentpage) / Object.entries(pageInfo).length}%`,
          backgroundColor:
            (100 * currentpage) / Object.entries(pageInfo).length <= 50
              ? "#E6D1FF"
              : (100 * currentpage) / Object.entries(pageInfo).length < 100
              ? "#FFFFD1"
              : "#FFD1DC",
        }}
      ></div>
				
			

그리고 이제 유동적으로 디자인을 변경하는 부분입니다.

우선은 해당 div 의 width 가 유동적이죠? 원리는 위와 같습니다. 

전체 객체의 길이가 3, 현재 페이지가 1이라면 100에 1/3을 곱한 값이 width로 됩니다. 

또한 색깔은 이 결과의 값이 50 아래냐, 50~100 사이냐, 그 이외이냐에 따라서 결정이 됩니다.

				
					
/*Progress 의 막대 디자인 */
.progress-bar {
    height: 30px;
    border-radius: 10px; /* 원하는 값으로 조절하세요. */
    box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; /* 원하는 값으로 조절하세요. */
    transition: width 0.5s, background-color 0.5s, box-shadow 0.5s; 
}



.progress-label {
    position: absolute;
    padding: 5px 10px;
    color: black;
    font-weight: bold;
    
}

.progress {
    margin-left: auto;
    margin-right: auto;
    width: 95%;
    background-color: lightgrey;
    position: relative;
    border-radius: 10px;
}

.progress-bar {
    height: 30px;
    border-radius: 10px; /* 원하는 값으로 조절하세요. */
    box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; /* 원하는 값으로 조절하세요. */
}

.progress-bar {
  transition: width 0.5s, background-color 0.5s, box-shadow 0.5s; 
  border-radius: 10px;/* 원하는 지속 시간을 사용하세요. */
}
				
			

디자인을 요렇게 해줍시다.

상위 컴포넌트인 progress 는 넓이가 95%로 고정이 되어 있으며, 

그 내부에서 막대의 width가 변하며 애니메이션 효과를 줄 겁니다.

마치며...

이런 식으로 Progress Bar 부분을 꾸며봤습니다.

색깔 등을 원하는 색으로 변형해서 사용해보세요.