뽀모도로 구현(3)

차차·2023년 1월 28일
post-thumbnail

디자인

타이머는 완료했지만 아직 Progress bar와 집중타임 밑에 있는 step을 만들지 않았다.

Progress bar 를 쉽게 만들어보기 위해서 라이브러리를 찾았다..!



Progress bar 적용시키기

npm i react-circular-progressbar

https://www.npmjs.com/package/react-circular-progressbar
위 링크에 해당 기능에 대한 설명이 있다.


import { CircularProgressbar } from "react-circular-progressbar";

interface IProgressbar {
  children: JSX.Element | JSX.Element[];
  value: number;
}

const ProgressBar = ({ children, value }: IProgressbar) => {
  const gradientTransform = `rotate(90)`;
  return (
    <div>
      <svg style={{ height: 0, width: 0 }}>
        <defs>
          <linearGradient id={"progress"} gradientTransform={gradientTransform}>
            <stop offset="0%" stopColor={"#ED7868"} />
            <stop offset="100%" stopColor={"#FFB077"} />
          </linearGradient>
        </defs>
      </svg>
      <div className="flex-center relative h-[14rem] w-[14rem]">
        <CircularProgressbar
          value={value}
          strokeWidth={8}
          styles={{
            path: {
              stroke: `url(#${"progress"})`,
              height: "100%",
              strokeLinecap: "round",
              transition: "stroke-dashoffset 1s linear 0s",
            },
            trail: {
              stroke: "white",
            },
          }}
        />

        {children}
      </div>
    </div>
  );
};

export default ProgressBar;

<CircularProgressbar>{children}</CircularProgressbar>
  1. children을 통해서 원형 진행바 안에 들어가는 JSX.Element들을 넣어준다.
  2. value 는 진행률을 의미한다. 0~100
  3. strokeWidth 는 진행바의 두께를 의미한다.
  4. styles 는 진행바의 스타일을 커스텀할 수 있게 해준다.
    - path 진행바의 스타일
    - stroke 진행바의 색상
    - strokeLinecap 진행바의 끝부분 처리 “round”, “butt”
    - transition 진행바의 애니메이션
    - trail 배경바의 스타일
    - 배경바의 색상

  5. 진행바의 색상을 그라디언트로 입히기 위해 svg를 생성하여 id를 정해주었다.
<svg style={{ height: 0, width: 0 }}>
	<defs>
	  <linearGradient id={"progress"} gradientTransform={gradientTransform}>
	    <stop offset="0%" stopColor={"#ED7868"} />
      <stop offset="100%" stopColor={"#FFB077"} />
    </linearGradient>
  </defs>
</svg>

6. 위에서 정한 `id` 를 진행바 `stroke` 색상으로 입힌다.
styles={{
  path: {
		// url을 id 값으로 사용한다.
    stroke: `url(#${"progress"})`,
    height: "100%",
    strokeLinecap: "round",
    transition: "stroke-dashoffset 1s linear 0s",
  },
  trail: {
    stroke: "white",
  },
}}



Step 만들기 (진행률을 원의 갯수로 표현)

사실 진행바와 카운트가 어려울거라고 생각하고 있어서 step 부분은 아주 만만하게 보고 있었다.

하지만 의외로 step 부분에서 애를 먹게 되었는데 이유는 아래와 같다.

// 예를 들어 입력 받은 집중시간과 휴식시간이 있다. 

const 집중시간 = 25; 
const 휴식시간 = 5;

// 그렇다면 총 사이클을 도는 뽀모도로에서의 총시간은 아래와 같다.

const 총시간 = (집중시간+휴식시간)* 3 + 집중시간; // 115

처음에 나는 멍청하게 4사이클이니까 총시간을 4등분을 해서 진행률을 계산하고자 했다.

<ul className="mb-[2.1rem] mt-[2.4rem] flex space-x-[1.4rem]">
  {[100,75,50,25].map((item, idx) => (
    <li
      key={idx}
      className={cls(
        "h-[1.8rem] w-[1.8rem] rounded-full",
        totalTime / (defaultTime.studyTime * 4 + defaultTime.restTime * 3)) *
			  100<item ? "bg-[#D9D9D9]" : "bg-primary-main"
      )}
    />
  ))}
</ul>

// (남은 시간 / 총시간 * 100) < item 일 경우에 공이 하나씩 불이 들어오는 방식. 

이런 방식으로 여러번 코드 수정해가며 적용을 해봐도 왠지 시간이 사이클을 돌 때마다 몇 초씩 밀리는 현상이 발생하였다. 졸려서 그런지 멍청해서 머리가 안돌아가는지 지금 보면 한숨만 나온다.

한숨 자고 나서 코드를 확인해보니 경악을 했다. “4번째 싸이클 때는 휴식시간이 빠지는구나!!”

바로 코드를 수정하였다.

// 시간대별로 스텝을 나눠주는 ProgressTimes 생성
const progressTimes = useMemo(() => {
  const { studyTime, restTime } = defaultTime;
  const sumTime = studyTime + restTime;
  return [
    sumTime * 3 + studyTime,
    sumTime * 2 + studyTime,
    sumTime + studyTime,
    studyTime,
  ];
}, [defaultTime]);
<ul className="mb-[2.1rem] mt-[2.4rem] flex space-x-[1.4rem]">
  {progressTimes.map((item, idx) => (
    <li
      key={idx}
      className={cls(
        "h-[1.8rem] w-[1.8rem] rounded-full",
        item <= totalTime ? "bg-[#D9D9D9]" : "bg-primary-main"
      )}
    />
  ))}
</ul>

정확한 구간을 설정해주니 바로 해결되었다…!


지금까지 만들어본 기능 중에서 가장 어려웠던 뽀모도로였다… 비록 코드는 굉장히 지저분하지만 리팩토링 하다보면은 나아지겠지…? 이후에 여러 부분을 수정한 코드는 아래와 같다.

Frontend/Timer.tsx at dev · M0INDA/Frontend

쓸데 없는 변수들이 너무 많다. 여유가 생길 때 한 번 제대로 수정해야겠다.

profile
나는야 프린이

0개의 댓글