Skip to main content

간단한 토마토 타이머(Tomato Timer) 웹 서비스 만들기

1. 사전 작업: ChatGPT에게 어떤 타이머를 만들지 물어보기

오늘은 ChatGPT와 간단한 토마토 타이머 웹 서비스 만들기를 해보려고 합니다. 원래는 간단한 타이머를 만들어보려고 했는데 토마토 타이머를 만들게된 배경과 과정까지 설명하면서 진행하려고 합니다.

먼저 아래와 같이 어떤 타이머를 만들면 좋을지 ChatGPT에게 물어보았습니다.

ChatGPT프롬프트
I'm trying to build simple timer web service, suggest good timer applications. 

아래와 같이 다양한 타이머 종류를 알려줍니다. ChatGPT프롬프트 응답값 - 타이머 종류

다양한 타이머가 있는데 Tomato Timer 라는게 재미있어 보여 Tomato Timer를 만들어보도록 하겠습니다. 그리고 Tomato Timer에 대한 설명과 사용 방법을 알아보기 위해 아래와 같이 물어보았습니다.

ChatGPT프롬프트
explain about what is and how to use Tomato Timer

아래와 같이 Tomato Timer 에 대한 설명과 사용 방법을 잘 알려줍니다. ChatGPT프롬프트 응답값 - Tomato Timer에 대한 설명과 사용법

위의 결과값은 타이머 웹서비스를 만드는 프롬프트에 Assistant 프롬프트로 지정되어 사용될 예정이기 때문에 잘 기록해두시기 바랍니다.

2. 토마토 타이머를 위한 프롬프트 요청

코드 및 가이드 작성은 ChatGPT대신 동일한 GPT4를 사용하는 Playground 를 통해 진행 합니다. 이유는 system 과 assistant 를 쉽게 지정 할수 있고 길이도 더 길게 설정 할수 있기 때문입니다. gpt4 버전의 OpenAI Playgound에서 아래와 같이 프롬프트를 요청합니다.

Playgound에서는 OpenAI API 와 동일하게 User외에도 System과 Assistant 프롬프트를 지원합니다. System 프롬프트는 상황을 설정해주고 Assistant 프롬프트는 원하는 프롬프트에 필요한 정보를 제공 해주고 학습시키는 보조자 역할을 합니다.

  • System 프롬프트
System
act as a experienced frontend developer
  • Assistant 프롬프트
Assistant
Tomato Timer는 Pomodoro Technique를 기반으로 하는 간단하고 효과적인 타이머 응용 프로그램입니다. Pomodoro 기법은 1980년대 후반에 Francesco Cirillo가 개발한 시간 관리 방법으로, 타이머를 사용하여 작업을 간격(전통적으로 25분 길이)으로 나누고 짧은 휴식 시간으로 구분합니다.

토마토 타이머를 사용하는 방법은 다음과 같습니다.

수행할 작업을 결정합니다.
- 토마토 타이머를 25분으로 설정합니다.
- 타이머가 꺼질 때까지 작업을 수행합니다.
- 짧은 휴식을 취하십시오(보통 5분).
- 이 과정을 반복하여 25분 간격으로 작업하고 또 휴식을 취합니다.
- 포모도로 4주기 후에는 15-30분의 더 긴 휴식을 취하십시오.

Tomato Timer는 휴식 시간을 조정할 수 있는 옵션과 함께 25분 및 5분 휴식 타이머를 자동으로 설정하여 이 프로세스를 단순화합니다. 타이머를 시작하면 25분 간격을 카운트다운한 다음 휴식 시간을 알리는 알람이 울립니다. 그런 다음 다음 작업 간격을 위해 타이머를 다시 시작할 수 있습니다.

Tomato Timer는 생산성을 높이고 업무에 집중하고자 하는 모든 사람에게 유용한 도구입니다. 작업을 관리 가능한 간격으로 나누면 번아웃을 피하고 동기를 유지하는 데 도움이 됩니다. 또한 짧은 휴식을 통해 재충전하고 다시 집중할 수 있으므로 전반적인 생산성과 웰빙이 향상될 수 있습니다.
  • User 프롬프트

User 프롬프트는 아래 요구 사항으로 Tomato Timer를 만들어 줄것을 지시 합니다. 자세한 기능 요구 사항은 유형별 시간 설정

  • Pomodoro(작업시간): 25min
  • Short Break, 5min
  • Long Break: 15min 그리고 사용자 가이드
  • Tomato Timer 설명
  • Tomato Timer 사용법 입니다.
User
I’m trying to build a simple Tomato Timer web service, give me step by step instruction with code example with the following requirements. 
- using html, css, basic javascript
- design & css: modern style design, responsive, material UI (mui)
- Features: 3 Timers Modes(Pomodoro: 25min, Short Break, 5min, Long Break: 15min), Each Timer has actions (Start, Pause/Resume, Stop), User Guide (What is Tomato Timer, How to use)
- output markdown code
- 답변은 한글로

프롬프트를 요청 하면 아래와 같이 코드 작성 하는 방법을 알려줍니다. ChatGPT프롬프트 응답값 - 토마토 타이머 코드 작성 하기

3. 토마토 타이머 코드 작성 하기

간단한 Tomato Timer 웹 서비스를 구축하기 위해 다음과 같은 단계별 지침을 따르십시오.

3.1. HTML 구조 생성하기

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tomato Timer</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://mui.com/legacy/css/material-ui.min.css">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>Tomato Timer</h1>
<div class="timer-modes">
<button class="pomodoro">Pomodoro (25분)</button>
<button class="short-break">짧은 휴식 (5분)</button>
<button class="long-break">긴 휴식 (15분)</button>
</div>
<div class="timer">
<span class="timer-display">25:00</span>
</div>
<div class="timer-controls">
<button class="start">시작</button>
<button class="pause" disabled>일시 정지</button>
<button class="reset" disabled>초기화</button>
</div>
<div class="user-guide">
<h2>Tomato Timer란?</h2>
<p>Tomato Timer는 Pomodoro 기법을 사용하여 시간을 관리하는 웹 서비스입니다.</p>
<h2>사용 방법</h2>
<p>1. 원하는 타이머 모드를 선택하세요 (Pomodoro, 짧은 휴식, 긴 휴식).</p>
<p>2. 시작 버튼을 눌러 타이머를 시작하세요.</p>
<p>3. 필요한 경우 일시 정지/재개 또는 초기화 버튼을 사용하세요.</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

3.2. CSS 스타일링

/* styles.css */
body {
font-family: 'Roboto', sans-serif;
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}

.container {
max-width: 800px;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
padding: 30px;
text-align: center;
border-radius: 5px;
}

h1 {
margin-top: 0;
margin-bottom: 30px;
}

.timer {
font-size: 48px;
margin-bottom: 20px;
}

.timer-controls button,
.timer-modes button {
margin: 5px;
font-size: 16px;
}

.user-guide {
text-align: left;
margin-top: 30px;
}

.user-guide h2 {
margin-bottom: 10px;
}

3.3. JavaScript 로직 구현

// script.js
let timer;
let minutes = 25;
let seconds = 0;
let isRunning = false;

const timerDisplay = document.querySelector(".timer-display");
const startButton = document.querySelector(".start");
const pauseButton = document.querySelector(".pause");
const resetButton = document.querySelector(".reset");
const timerModes = document.querySelectorAll(".timer-modes button");

function updateTimerDisplay() {
timerDisplay.textContent = `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
}

function startTimer() {
if (!isRunning) {
timer = setInterval(() => {
if (seconds === 0) {
if (minutes > 0) {
minutes--;
seconds = 59;
} else {
clearInterval(timer);
isRunning = false;
updateControlsState();
return;
}
} else {
seconds--;
}
updateTimerDisplay();
}, 1000);
isRunning = true;
updateControlsState();
}
}

function pauseTimer() {
clearInterval(timer);
isRunning = false;
updateControlsState();
}

function resetTimer() {
clearInterval(timer);
isRunning = false;
seconds = 0;
updateTimerDisplay();
updateControlsState();
}

function updateControlsState() {
startButton.disabled = isRunning;
pauseButton.disabled = !isRunning;
resetButton.disabled = !isRunning;
}

startButton.addEventListener("click", startTimer);
pauseButton.addEventListener("click", pauseTimer);
resetButton.addEventListener("click", resetTimer);

timerModes.forEach((mode) => {
mode.addEventListener("click", () => {
clearInterval(timer);
isRunning = false;
updateControlsState();

if (mode.classList.contains("pomodoro")) {
minutes = 25;
} else if (mode.classList.contains("short-break")) {
minutes = 5;
} else if (mode.classList.contains("long-break")) {
minutes = 15;
}
updateTimerDisplay();
});
});

updateTimerDisplay();

이제 위 코드를 사용하여 간단한 Tomato Timer 웹 서비스를 구축할 수 있습니다. HTML, CSS 및 기본 JavaScript를 사용하여 모던 스타일의 디자인과 반응형 레이아웃을 적용하였습니다. 또한 3가지 타이머 모드(Pomodoro, 짧은 휴식, 긴 휴식)와 각 타이머에 대한 동작(시작, 일시 정지/재개, 중지) 그리고 사용자 가이드를 구현하였습니다.

4. 코드 개선하기

위의 코드로도 동작을 하지만 아직 부족한 부분이 있어 아래와 같이 코드를 개선해보겠습니다. 눈에 보이는 오류는 모드 변경시 초단위가 초기화 되지 않는 오류가 있습니다.

모드 변경시 초가 초기화 되지 않는다고만 알려줍니다.

User
when change mode, seconds does not reset

프롬프트를 요청 하면 아래와 같이 코드를 작성 해줍니다. ChatGPT프롬프트 응답값 - 모드 변경시 초 변경 안되는 이슈 개선 죄송합니다. 모드 변경시 초를 재설정하지 않는 문제를 수정하겠습니다. script.js에서 timerModes.forEach 부분을 다음과 같이 수정하십시오.

timerModes.forEach((mode) => {
mode.addEventListener("click", () => {
clearInterval(timer);
isRunning = false;
updateControlsState();

if (mode.classList.contains("pomodoro")) {
minutes = 25;
} else if (mode.classList.contains("short-break")) {
minutes = 5;
} else if (mode.classList.contains("long-break")) {
minutes = 15;
}
seconds = 0; // 초를 초기화합니다.
updateTimerDisplay();
});
});

이제 모드를 변경할 때 분과 초가 모두 재설정됩니다.

5. 코드 Codepen에 업로드 및 Netlify를 이용한 배포

완성된 코드를 Codepen에 작성하고 Netlify를 이용하여 배포해보겠습니다. HTML, CSS 및 JavaScript 섹션을 작성 하셨다면 CodePen 저장 및 내보내기Netlify에 배포를 참고 하셔서 배포 하실수 있습니다.

위의 순서로 따라서 만들어보니 정말 간단하게 아래와 같은 토마토 타이머 페이지가 만들어졌습니다. ChatGPT와 함께 만든 간단한 토마토 타이머

7. 마치며

지금까지 간단한 토마토 타이머 웹사이트를 만들어보면서 출시 까지 해보았는데 도움이 되셨나요? 간단한 TodoApp이나 예산 타이머 보다는 조금더 기능이 있는 토마토타이머를 만들어본 경험을 통해 코딩에 더 흥미를 가지는 계기가 되었으면 좋겠습니다.

참고로 완성된 소스 코드는 GitHub 링크에서 확인 하실수 있습니다.