From a42b2291b00c2ceda7670ce80f24d8a13342ed58 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:22:36 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8step=20status=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/layout.tsx | 5 +---- src/app/timer/page.tsx | 25 ++++++++++++++----------- src/app/timer/useStep.ts | 26 +++++++++++++++++++++++--- src/components/Layout/Header.tsx | 3 +++ 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/app/timer/layout.tsx b/src/app/timer/layout.tsx index c69b896a..5504726c 100644 --- a/src/app/timer/layout.tsx +++ b/src/app/timer/layout.tsx @@ -12,10 +12,7 @@ export default function Layout({ children }: PropsWithChildren) { } const containerCss = css({ - background: 'linear-gradient(136deg, #FFF1F2 4.76%, #E9EFFF 89.58%)', minHeight: '100vh', }); -const mainCss = css({ - padding: '24px 16px', -}); +const mainCss = css({}); diff --git a/src/app/timer/page.tsx b/src/app/timer/page.tsx index 5d2bc498..f75d7ef3 100644 --- a/src/app/timer/page.tsx +++ b/src/app/timer/page.tsx @@ -3,26 +3,29 @@ import TimerView from '@/app/timer/TimerView'; import useStep from '@/app/timer/useStep'; import { css } from '@styled-system/css'; -const STEP_LABEL = { - ready: { - title: '준비 되셨나요?', - desc: '타이머를 눌러서 10분의 미션을 완성해 주세요!', - }, -} as const; - export default function TimerPage() { - const { step } = useStep(); + const { step, stepLabel } = useStep(); return ( -
-

{STEP_LABEL[step].title}

-

{STEP_LABEL[step].desc}

+
+
+

{stepLabel.title}

+

{stepLabel.desc}

); } +const containerCss = { + background: 'linear-gradient(136deg, #FFF1F2 4.76%, #E9EFFF 89.58%)', + padding: '24px 16px', +}; + +const headerBlankCss = { + height: '42px;', +}; + const font24Css = { fontSize: '24px', fontFamily: 'Pretendard', diff --git a/src/app/timer/useStep.ts b/src/app/timer/useStep.ts index fa73394d..06671d35 100644 --- a/src/app/timer/useStep.ts +++ b/src/app/timer/useStep.ts @@ -1,12 +1,32 @@ import { useState } from 'react'; -type StepType = 'ready'; +type StepType = 'ready' | 'progress' | 'stop'; + +const STEP_LABEL = { + ready: { + title: '준비 되셨나요?', + desc: '타이머를 눌러서 10분의 미션을 완성해 주세요!', + }, + progress: { + title: '시작!', + desc: '10분 동안 최선을 다해주세요!', + }, + stop: { + title: '잠시 멈췄어요', + desc: '준비가 되면 타이머를 다시 시작해주세요!', + }, +} as const; function useStep() { const [step, setStep] = useState('ready'); - const onNextStep = () => {}; - return { step, onNextStep }; + const stepLabel = STEP_LABEL[step]; + + const onNextStep = (nextStep: StepType) => { + setStep(nextStep); + }; + + return { step, onNextStep, stepLabel }; } export default useStep; diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 28dda3dd..46660f56 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -20,6 +20,9 @@ function Header({ title }: Props) { const wrapperCss = flex({ padding: '10px 16px', gap: '6px', + background: 'transparent', + position: 'fixed', + margin: '0 auto', }); const headingCss = css({ From a2100a66a1fbf507e1ba18945ff249522e447305 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:30:02 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20timer=20layout=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/layout.tsx | 10 +--------- src/app/timer/page.tsx | 21 ++++++++++++--------- src/components/Layout/Header.tsx | 21 +++++++++++++++------ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/app/timer/layout.tsx b/src/app/timer/layout.tsx index 5504726c..3aadb9f1 100644 --- a/src/app/timer/layout.tsx +++ b/src/app/timer/layout.tsx @@ -1,18 +1,10 @@ import { type PropsWithChildren } from 'react'; -import Header from '@/components/Layout/Header'; import { css } from '@/styled-system/css'; export default function Layout({ children }: PropsWithChildren) { - return ( -
-
-
{children}
-
- ); + return
{children}
; } const containerCss = css({ minHeight: '100vh', }); - -const mainCss = css({}); diff --git a/src/app/timer/page.tsx b/src/app/timer/page.tsx index f75d7ef3..6ae01cf3 100644 --- a/src/app/timer/page.tsx +++ b/src/app/timer/page.tsx @@ -7,23 +7,26 @@ export default function TimerPage() { const { step, stepLabel } = useStep(); return ( -
-
-

{stepLabel.title}

-

{stepLabel.desc}

+
+
+
); } -const containerCss = { - background: 'linear-gradient(136deg, #FFF1F2 4.76%, #E9EFFF 89.58%)', - padding: '24px 16px', +const bgCss = { + minHeight: '100vh', + transition: '1s ease', }; -const headerBlankCss = { - height: '42px;', +const containerCss = { + padding: '24px 16px', }; const font24Css = { diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 46660f56..2afc2c6c 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -8,21 +8,30 @@ interface Props { function Header({ title }: Props) { return ( -
- -

{title}

-
+ <> +
+ +

{title}

+
+
+ ); } +const headerBlankCss = { + height: '42px;', + width: '100%', +}; + const wrapperCss = flex({ padding: '10px 16px', gap: '6px', background: 'transparent', position: 'fixed', margin: '0 auto', + zIndex: 100, }); const headingCss = css({ From 3699d966bf4caf0cb2348b77dd1a0ecb4599a374 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:31:11 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=92=84=20=EC=9D=BC=EC=8B=9C=EC=A0=95?= =?UTF-8?q?=EC=A7=80=20=EC=83=81=ED=83=9C=EC=9D=B4=EB=A9=B4=20gray?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/TimerView.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/timer/TimerView.tsx b/src/app/timer/TimerView.tsx index 9d5488a3..e7ce822d 100644 --- a/src/app/timer/TimerView.tsx +++ b/src/app/timer/TimerView.tsx @@ -4,7 +4,7 @@ import { center } from '@/styled-system/patterns'; interface Props { isActive: boolean; - time: [number, number]; + time: [string, string]; category: string; } export default function TimerView({ category, time, isActive }: Props) { @@ -12,7 +12,11 @@ export default function TimerView({ category, time, isActive }: Props) {
{category}
-
+
{time[0]} : {time[1]} @@ -39,6 +43,5 @@ const timerTextCss = { animation: 'gradient 3s ease-in-out infinite', backgroundSize: '150% 200%!', '-webkit-background-clip': 'text!', - color: 'transparent', background: 'linear-gradient(108deg, #FF8C8C -1.04%, #5D8AFF 101.48%)', }; From bbed18eabc4b088788bcc69d040d6736d07f7f45 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:31:29 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=E2=9C=A8=20=ED=83=80=EC=9D=B4=EB=A8=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/page.tsx | 56 +++++++++++++++++++++++++++++++++++++-- src/app/timer/useStep.ts | 2 +- src/app/timer/useTimer.ts | 30 +++++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/app/timer/useTimer.ts diff --git a/src/app/timer/page.tsx b/src/app/timer/page.tsx index 6ae01cf3..dc114749 100644 --- a/src/app/timer/page.tsx +++ b/src/app/timer/page.tsx @@ -1,10 +1,18 @@ 'use client'; import TimerView from '@/app/timer/TimerView'; import useStep from '@/app/timer/useStep'; +import useTimer from '@/app/timer/useTimer'; +import Header from '@/components/Layout/Header'; import { css } from '@styled-system/css'; export default function TimerPage() { - const { step, stepLabel } = useStep(); + const { step, stepLabel, onNextStep } = useStep(); + const { formattedTime } = useTimer(step); + + const onFinish = () => { + onNextStep('stop'); + alert('정말 끝내시겠습니까?'); + }; return (
+

{stepLabel.title}

+

{stepLabel.desc}

- + +
+ {step === 'ready' && ( + + )} + {step === 'progress' && ( + <> + + + + )} + {step === 'stop' && ( + <> + + + + )} +
+
); } @@ -46,3 +84,17 @@ const font14Css = { const titleCss = css(font24Css, { color: '#333D4B' }); const descCss = css(font14Css, { color: '#6B7684', marginBottom: '84px' }); + +const buttonContainerCss = { + margin: '28px auto', + display: 'flex', + justifyContent: 'center', + gap: '12px', + + '& button': { + backgroundColor: 'white', + borderRadius: '30px', + padding: '16px 24px', + boxSizing: '0px 4px 20px 0px rgba(18, 23, 41, 0.10)', + }, +}; diff --git a/src/app/timer/useStep.ts b/src/app/timer/useStep.ts index 06671d35..6c635d7c 100644 --- a/src/app/timer/useStep.ts +++ b/src/app/timer/useStep.ts @@ -1,6 +1,6 @@ import { useState } from 'react'; -type StepType = 'ready' | 'progress' | 'stop'; +export type StepType = 'ready' | 'progress' | 'stop'; const STEP_LABEL = { ready: { diff --git a/src/app/timer/useTimer.ts b/src/app/timer/useTimer.ts new file mode 100644 index 00000000..cf2325ec --- /dev/null +++ b/src/app/timer/useTimer.ts @@ -0,0 +1,30 @@ +import { useEffect, useState } from 'react'; +import { type StepType } from '@/app/timer/useStep'; + +export default function useTimer(status: StepType, initSeconds = 600) { + const [second, setSecond] = useState(initSeconds); // 남은 시간 (단위: 초) + + const formattedTime = formatMMSS(second); + + useEffect(() => { + let timer: NodeJS.Timeout; + + if (status === 'progress') { + timer = setInterval(() => { + setSecond((prev) => prev - 1); + }, 1000); + } + return () => clearInterval(timer); + }, [second, status]); + + return { formattedTime }; +} + +const formatMMSS = (second: number): [string, string] => { + const minutes = Math.floor(second / 60); // 분 계산 + const seconds = second % 60; // 초 계산 + const formattedMinutes = String(minutes).padStart(2, '0'); // 두 자리로 변환 + const formattedSeconds = String(seconds).padStart(2, '0'); // 두 자리로 변환 + + return [formattedMinutes, formattedSeconds]; +}; From efa00daa2cf7d356bf2bd3302ce8386b7a18e9b8 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:36:31 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=90=9B=200=EC=B4=88=20=EA=B9=8C?= =?UTF-8?q?=EC=A7=80=EB=A7=8C=20=EC=B9=B4=EC=9A=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/useTimer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/timer/useTimer.ts b/src/app/timer/useTimer.ts index cf2325ec..deac5a76 100644 --- a/src/app/timer/useTimer.ts +++ b/src/app/timer/useTimer.ts @@ -9,6 +9,10 @@ export default function useTimer(status: StepType, initSeconds = 600) { useEffect(() => { let timer: NodeJS.Timeout; + if (second <= 0) { + return; + } + if (status === 'progress') { timer = setInterval(() => { setSecond((prev) => prev - 1); From 17661b02f2d78858823d28f571bc121d20e49a45 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 2 Dec 2023 00:39:40 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20step=20to=20timer=20st?= =?UTF-8?q?atus=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/timer/page.tsx | 4 ++-- src/app/timer/useTimer.ts | 2 +- src/app/timer/{useStep.ts => useTimerStatus.ts} | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) rename src/app/timer/{useStep.ts => useTimerStatus.ts} (83%) diff --git a/src/app/timer/page.tsx b/src/app/timer/page.tsx index dc114749..cd14a574 100644 --- a/src/app/timer/page.tsx +++ b/src/app/timer/page.tsx @@ -1,12 +1,12 @@ 'use client'; import TimerView from '@/app/timer/TimerView'; -import useStep from '@/app/timer/useStep'; import useTimer from '@/app/timer/useTimer'; +import useTimerStatus from '@/app/timer/useTimerStatus'; import Header from '@/components/Layout/Header'; import { css } from '@styled-system/css'; export default function TimerPage() { - const { step, stepLabel, onNextStep } = useStep(); + const { step, stepLabel, onNextStep } = useTimerStatus(); const { formattedTime } = useTimer(step); const onFinish = () => { diff --git a/src/app/timer/useTimer.ts b/src/app/timer/useTimer.ts index deac5a76..31018aa2 100644 --- a/src/app/timer/useTimer.ts +++ b/src/app/timer/useTimer.ts @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { type StepType } from '@/app/timer/useStep'; +import { type StepType } from '@/app/timer/useTimerStatus'; export default function useTimer(status: StepType, initSeconds = 600) { const [second, setSecond] = useState(initSeconds); // 남은 시간 (단위: 초) diff --git a/src/app/timer/useStep.ts b/src/app/timer/useTimerStatus.ts similarity index 83% rename from src/app/timer/useStep.ts rename to src/app/timer/useTimerStatus.ts index 6c635d7c..73dc7964 100644 --- a/src/app/timer/useStep.ts +++ b/src/app/timer/useTimerStatus.ts @@ -2,7 +2,7 @@ import { useState } from 'react'; export type StepType = 'ready' | 'progress' | 'stop'; -const STEP_LABEL = { +const TIMER_STATUS = { ready: { title: '준비 되셨나요?', desc: '타이머를 눌러서 10분의 미션을 완성해 주세요!', @@ -17,10 +17,10 @@ const STEP_LABEL = { }, } as const; -function useStep() { +function useTimerStatus() { const [step, setStep] = useState('ready'); - const stepLabel = STEP_LABEL[step]; + const stepLabel = TIMER_STATUS[step]; const onNextStep = (nextStep: StepType) => { setStep(nextStep); @@ -29,4 +29,4 @@ function useStep() { return { step, onNextStep, stepLabel }; } -export default useStep; +export default useTimerStatus;