디자인
타이머는 완료했지만 아직 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>
children
을 통해서 원형 진행바 안에 들어가는 JSX.Element들을 넣어준다.value
는 진행률을 의미한다. 0~100strokeWidth
는 진행바의 두께를 의미한다. styles
는 진행바의 스타일을 커스텀할 수 있게 해준다.path
진행바의 스타일stroke
진행바의 색상strokeLinecap
진행바의 끝부분 처리 “round”, “butt”transition
진행바의 애니메이션trail
배경바의 스타일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>
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
<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
쓸데 없는 변수들이 너무 많다. 여유가 생길 때 한 번 제대로 수정해야겠다.