XiaoxiaoBR commited on
Commit
db48218
·
verified ·
1 Parent(s): cc31a5c

Faça um website que servirá de controle de tempo! Um menu inicial com 6 botões: 1 botão RELOGIO que mostra a hora, 1 botão TABATA que mostra uma tela de configuração que contém quantas séries, quantos segundos de trabalho e quantos segundos de descanso; 1 botão POR TEMPO, que configura um tempo limite em minutos e segundos e faz a contagem progressiva desse tempo; 1 botão QSP/QRP, que configura um tempo limite em minutos e segundos e faz a contagem regressiva desse tempo; 1 botão EMOM, que configura quantas séries, quantos minutos e segundos de trabalho e quantos minutos e segundos de descanso; 1 botão CUSTOM, que abre uma tela de configuração e tem as opções: -segundos para a contagem regressiva, -de quantas séries serão, -se as séries terão o tempo igual ou cada série tem um tempo diferente, -qual o tempo em minutos e segundos da série, caso as séries tiverem tempos diferentes, um campo de minutos e segundos para configurar cada série, -campo de minuto e segundo para configurar o tempo de descanso da série (ou de cada série, se for o caso) -se o tempo da série (ou de cada série, se for o caso) é progressivo e regressivo. Conforme o cronômetro funciona, uma animação onde há um aro em volta do tempo e esse aro vai se completando até acabar o tempo, mudando de cor de verde (cor inicial) para amarelo quando tiver passado metade do tempo; e para vermelho, quando restar 1/4 do tempo. Nos 3 últimos segundos, tanto da contagem regressiva para início, tanto para o final da série e do final do descanso, emitir um efeito sonoro breve e para o fim desses, um efeito sonoro um pouco mais longo! - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1180 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Timerwod
3
- emoji:
4
- colorFrom: indigo
5
- colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: timerwod
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1180 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="pt-br">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Controle de Tempo</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @keyframes progress {
11
+ 0% {
12
+ stroke-dashoffset: 440;
13
+ }
14
+ 100% {
15
+ stroke-dashoffset: 0;
16
+ }
17
+ }
18
+
19
+ .progress-ring {
20
+ transform: rotate(-90deg);
21
+ transform-origin: 50% 50%;
22
+ }
23
+
24
+ .beep {
25
+ animation: beep 0.5s ease-out;
26
+ }
27
+
28
+ @keyframes beep {
29
+ 0% { transform: scale(1); }
30
+ 50% { transform: scale(1.1); }
31
+ 100% { transform: scale(1); }
32
+ }
33
+
34
+ .long-beep {
35
+ animation: longBeep 1s ease-out;
36
+ }
37
+
38
+ @keyframes longBeep {
39
+ 0% { transform: scale(1); }
40
+ 25% { transform: scale(1.2); }
41
+ 50% { transform: scale(0.9); }
42
+ 75% { transform: scale(1.1); }
43
+ 100% { transform: scale(1); }
44
+ }
45
+ </style>
46
+ </head>
47
+ <body class="bg-gray-900 text-white min-h-screen">
48
+ <audio id="beepSound" src="https://assets.mixkit.co/sfx/preview/mixkit-alarm-digital-clock-beep-989.mp3"></audio>
49
+ <audio id="endSound" src="https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3"></audio>
50
+
51
+ <div class="container mx-auto px-4 py-8">
52
+ <!-- Main Menu -->
53
+ <div id="mainMenu" class="text-center">
54
+ <h1 class="text-4xl font-bold mb-12">Controle de Tempo</h1>
55
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
56
+ <button onclick="showClock()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
57
+ <i class="fas fa-clock mr-2"></i> Relógio
58
+ </button>
59
+ <button onclick="showTabataConfig()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
60
+ <i class="fas fa-stopwatch mr-2"></i> Tabata
61
+ </button>
62
+ <button onclick="showForTimeConfig()" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
63
+ <i class="fas fa-hourglass-start mr-2"></i> Por Tempo
64
+ </button>
65
+ <button onclick="showQspConfig()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
66
+ <i class="fas fa-hourglass-end mr-2"></i> QSP/QRP
67
+ </button>
68
+ <button onclick="showEmomConfig()" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
69
+ <i class="fas fa-sync-alt mr-2"></i> EMOM
70
+ </button>
71
+ <button onclick="showCustomConfig()" class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-6 px-4 rounded-lg text-xl transition-all duration-300 transform hover:scale-105">
72
+ <i class="fas fa-cog mr-2"></i> Custom
73
+ </button>
74
+ </div>
75
+ </div>
76
+
77
+ <!-- Clock Screen -->
78
+ <div id="clockScreen" class="hidden text-center">
79
+ <h2 class="text-3xl font-bold mb-8">Relógio</h2>
80
+ <div class="text-6xl font-mono mb-8" id="currentTime"></div>
81
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-6 rounded-lg mt-4">
82
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
83
+ </button>
84
+ </div>
85
+
86
+ <!-- Tabata Config Screen -->
87
+ <div id="tabataConfigScreen" class="hidden max-w-md mx-auto">
88
+ <h2 class="text-3xl font-bold mb-8 text-center">Configuração Tabata</h2>
89
+ <div class="bg-gray-800 p-6 rounded-lg">
90
+ <div class="mb-4">
91
+ <label class="block text-gray-300 mb-2">Número de Séries</label>
92
+ <input type="number" id="tabataRounds" min="1" max="20" value="8" class="w-full px-3 py-2 bg-gray-700 rounded">
93
+ </div>
94
+ <div class="mb-4">
95
+ <label class="block text-gray-300 mb-2">Tempo de Trabalho (segundos)</label>
96
+ <input type="number" id="tabataWork" min="5" max="300" value="20" class="w-full px-3 py-2 bg-gray-700 rounded">
97
+ </div>
98
+ <div class="mb-6">
99
+ <label class="block text-gray-300 mb-2">Tempo de Descanso (segundos)</label>
100
+ <input type="number" id="tabataRest" min="5" max="300" value="10" class="w-full px-3 py-2 bg-gray-700 rounded">
101
+ </div>
102
+ <div class="flex justify-between">
103
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
104
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
105
+ </button>
106
+ <button onclick="startTabata()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
107
+ <i class="fas fa-play mr-2"></i> Iniciar
108
+ </button>
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <!-- Tabata Timer Screen -->
114
+ <div id="tabataTimerScreen" class="hidden text-center">
115
+ <h2 class="text-3xl font-bold mb-2">Tabata</h2>
116
+ <p class="text-xl mb-8" id="tabataPhase">Preparar</p>
117
+
118
+ <div class="relative w-64 h-64 mx-auto mb-8">
119
+ <svg class="w-full h-full" viewBox="0 0 100 100">
120
+ <circle cx="50" cy="50" r="45" fill="none" stroke="#333" stroke-width="8"/>
121
+ <circle id="tabataProgress" cx="50" cy="50" r="45" fill="none" stroke="#10B981" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="283" class="progress-ring"/>
122
+ </svg>
123
+ <div class="absolute inset-0 flex items-center justify-center">
124
+ <div id="tabataTime" class="text-5xl font-mono">00:20</div>
125
+ </div>
126
+ </div>
127
+
128
+ <div class="mb-4">
129
+ <span id="tabataRound" class="text-xl">Série 1/8</span>
130
+ </div>
131
+
132
+ <button onclick="pauseTabata()" id="tabataPauseBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-2 px-6 rounded mr-2">
133
+ <i class="fas fa-pause mr-2"></i> Pausar
134
+ </button>
135
+ <button onclick="stopTabata()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded">
136
+ <i class="fas fa-stop mr-2"></i> Parar
137
+ </button>
138
+ </div>
139
+
140
+ <!-- For Time Config Screen -->
141
+ <div id="forTimeConfigScreen" class="hidden max-w-md mx-auto">
142
+ <h2 class="text-3xl font-bold mb-8 text-center">Por Tempo</h2>
143
+ <div class="bg-gray-800 p-6 rounded-lg">
144
+ <div class="mb-4">
145
+ <label class="block text-gray-300 mb-2">Minutos</label>
146
+ <input type="number" id="forTimeMinutes" min="0" max="120" value="10" class="w-full px-3 py-2 bg-gray-700 rounded">
147
+ </div>
148
+ <div class="mb-6">
149
+ <label class="block text-gray-300 mb-2">Segundos</label>
150
+ <input type="number" id="forTimeSeconds" min="0" max="59" value="0" class="w-full px-3 py-2 bg-gray-700 rounded">
151
+ </div>
152
+ <div class="flex justify-between">
153
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
154
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
155
+ </button>
156
+ <button onclick="startForTime()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
157
+ <i class="fas fa-play mr-2"></i> Iniciar
158
+ </button>
159
+ </div>
160
+ </div>
161
+ </div>
162
+
163
+ <!-- For Time Timer Screen -->
164
+ <div id="forTimeTimerScreen" class="hidden text-center">
165
+ <h2 class="text-3xl font-bold mb-8">Por Tempo</h2>
166
+
167
+ <div class="relative w-64 h-64 mx-auto mb-8">
168
+ <svg class="w-full h-full" viewBox="0 0 100 100">
169
+ <circle cx="50" cy="50" r="45" fill="none" stroke="#333" stroke-width="8"/>
170
+ <circle id="forTimeProgress" cx="50" cy="50" r="45" fill="none" stroke="#10B981" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="283" class="progress-ring"/>
171
+ </svg>
172
+ <div class="absolute inset-0 flex items-center justify-center">
173
+ <div id="forTimeTime" class="text-5xl font-mono">10:00</div>
174
+ </div>
175
+ </div>
176
+
177
+ <button onclick="pauseForTime()" id="forTimePauseBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-2 px-6 rounded mr-2">
178
+ <i class="fas fa-pause mr-2"></i> Pausar
179
+ </button>
180
+ <button onclick="stopForTime()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded">
181
+ <i class="fas fa-stop mr-2"></i> Parar
182
+ </button>
183
+ </div>
184
+
185
+ <!-- QSP Config Screen -->
186
+ <div id="qspConfigScreen" class="hidden max-w-md mx-auto">
187
+ <h2 class="text-3xl font-bold mb-8 text-center">QSP/QRP</h2>
188
+ <div class="bg-gray-800 p-6 rounded-lg">
189
+ <div class="mb-4">
190
+ <label class="block text-gray-300 mb-2">Minutos</label>
191
+ <input type="number" id="qspMinutes" min="0" max="120" value="15" class="w-full px-3 py-2 bg-gray-700 rounded">
192
+ </div>
193
+ <div class="mb-6">
194
+ <label class="block text-gray-300 mb-2">Segundos</label>
195
+ <input type="number" id="qspSeconds" min="0" max="59" value="0" class="w-full px-3 py-2 bg-gray-700 rounded">
196
+ </div>
197
+ <div class="flex justify-between">
198
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
199
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
200
+ </button>
201
+ <button onclick="startQsp()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
202
+ <i class="fas fa-play mr-2"></i> Iniciar
203
+ </button>
204
+ </div>
205
+ </div>
206
+ </div>
207
+
208
+ <!-- QSP Timer Screen -->
209
+ <div id="qspTimerScreen" class="hidden text-center">
210
+ <h2 class="text-3xl font-bold mb-8">QSP/QRP</h2>
211
+
212
+ <div class="relative w-64 h-64 mx-auto mb-8">
213
+ <svg class="w-full h-full" viewBox="0 0 100 100">
214
+ <circle cx="50" cy="50" r="45" fill="none" stroke="#333" stroke-width="8"/>
215
+ <circle id="qspProgress" cx="50" cy="50" r="45" fill="none" stroke="#10B981" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="283" class="progress-ring"/>
216
+ </svg>
217
+ <div class="absolute inset-0 flex items-center justify-center">
218
+ <div id="qspTime" class="text-5xl font-mono">15:00</div>
219
+ </div>
220
+ </div>
221
+
222
+ <button onclick="pauseQsp()" id="qspPauseBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-2 px-6 rounded mr-2">
223
+ <i class="fas fa-pause mr-2"></i> Pausar
224
+ </button>
225
+ <button onclick="stopQsp()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded">
226
+ <i class="fas fa-stop mr-2"></i> Parar
227
+ </button>
228
+ </div>
229
+
230
+ <!-- EMOM Config Screen -->
231
+ <div id="emomConfigScreen" class="hidden max-w-md mx-auto">
232
+ <h2 class="text-3xl font-bold mb-8 text-center">Configuração EMOM</h2>
233
+ <div class="bg-gray-800 p-6 rounded-lg">
234
+ <div class="mb-4">
235
+ <label class="block text-gray-300 mb-2">Número de Séries</label>
236
+ <input type="number" id="emomRounds" min="1" max="30" value="10" class="w-full px-3 py-2 bg-gray-700 rounded">
237
+ </div>
238
+ <div class="mb-4">
239
+ <label class="block text-gray-300 mb-2">Tempo de Trabalho (minutos:segundos)</label>
240
+ <div class="flex">
241
+ <input type="number" id="emomWorkMinutes" min="0" max="10" value="0" class="w-1/2 px-3 py-2 bg-gray-700 rounded mr-2">
242
+ <input type="number" id="emomWorkSeconds" min="0" max="59" value="30" class="w-1/2 px-3 py-2 bg-gray-700 rounded">
243
+ </div>
244
+ </div>
245
+ <div class="mb-6">
246
+ <label class="block text-gray-300 mb-2">Tempo de Descanso (minutos:segundos)</label>
247
+ <div class="flex">
248
+ <input type="number" id="emomRestMinutes" min="0" max="10" value="0" class="w-1/2 px-3 py-2 bg-gray-700 rounded mr-2">
249
+ <input type="number" id="emomRestSeconds" min="0" max="59" value="30" class="w-1/2 px-3 py-2 bg-gray-700 rounded">
250
+ </div>
251
+ </div>
252
+ <div class="flex justify-between">
253
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
254
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
255
+ </button>
256
+ <button onclick="startEmom()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
257
+ <i class="fas fa-play mr-2"></i> Iniciar
258
+ </button>
259
+ </div>
260
+ </div>
261
+ </div>
262
+
263
+ <!-- EMOM Timer Screen -->
264
+ <div id="emomTimerScreen" class="hidden text-center">
265
+ <h2 class="text-3xl font-bold mb-2">EMOM</h2>
266
+ <p class="text-xl mb-8" id="emomPhase">Preparar</p>
267
+
268
+ <div class="relative w-64 h-64 mx-auto mb-8">
269
+ <svg class="w-full h-full" viewBox="0 0 100 100">
270
+ <circle cx="50" cy="50" r="45" fill="none" stroke="#333" stroke-width="8"/>
271
+ <circle id="emomProgress" cx="50" cy="50" r="45" fill="none" stroke="#10B981" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="283" class="progress-ring"/>
272
+ </svg>
273
+ <div class="absolute inset-0 flex items-center justify-center">
274
+ <div id="emomTime" class="text-5xl font-mono">00:30</div>
275
+ </div>
276
+ </div>
277
+
278
+ <div class="mb-4">
279
+ <span id="emomRound" class="text-xl">Série 1/10</span>
280
+ </div>
281
+
282
+ <button onclick="pauseEmom()" id="emomPauseBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-2 px-6 rounded mr-2">
283
+ <i class="fas fa-pause mr-2"></i> Pausar
284
+ </button>
285
+ <button onclick="stopEmom()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded">
286
+ <i class="fas fa-stop mr-2"></i> Parar
287
+ </button>
288
+ </div>
289
+
290
+ <!-- Custom Config Screen -->
291
+ <div id="customConfigScreen" class="hidden max-w-md mx-auto">
292
+ <h2 class="text-3xl font-bold mb-8 text-center">Configuração Customizada</h2>
293
+ <div class="bg-gray-800 p-6 rounded-lg">
294
+ <div class="mb-4">
295
+ <label class="block text-gray-300 mb-2">Contagem Regressiva Inicial (segundos)</label>
296
+ <input type="number" id="customCountdown" min="0" max="60" value="10" class="w-full px-3 py-2 bg-gray-700 rounded">
297
+ </div>
298
+ <div class="mb-4">
299
+ <label class="block text-gray-300 mb-2">Número de Séries</label>
300
+ <input type="number" id="customRounds" min="1" max="20" value="3" class="w-full px-3 py-2 bg-gray-700 rounded">
301
+ </div>
302
+ <div class="mb-4">
303
+ <label class="block text-gray-300 mb-2">Tempo Igual para Todas as Séries?</label>
304
+ <select id="customEqualTime" class="w-full px-3 py-2 bg-gray-700 rounded">
305
+ <option value="yes">Sim</option>
306
+ <option value="no">Não</option>
307
+ </select>
308
+ </div>
309
+
310
+ <div id="customEqualTimeConfig">
311
+ <div class="mb-4">
312
+ <label class="block text-gray-300 mb-2">Tempo da Série (minutos:segundos)</label>
313
+ <div class="flex">
314
+ <input type="number" id="customWorkMinutes" min="0" max="30" value="1" class="w-1/2 px-3 py-2 bg-gray-700 rounded mr-2">
315
+ <input type="number" id="customWorkSeconds" min="0" max="59" value="0" class="w-1/2 px-3 py-2 bg-gray-700 rounded">
316
+ </div>
317
+ </div>
318
+ <div class="mb-4">
319
+ <label class="block text-gray-300 mb-2">Tempo de Descanso (minutos:segundos)</label>
320
+ <div class="flex">
321
+ <input type="number" id="customRestMinutes" min="0" max="30" value="0" class="w-1/2 px-3 py-2 bg-gray-700 rounded mr-2">
322
+ <input type="number" id="customRestSeconds" min="0" max="59" value="30" class="w-1/2 px-3 py-2 bg-gray-700 rounded">
323
+ </div>
324
+ </div>
325
+ </div>
326
+
327
+ <div id="customDifferentTimeConfig" class="hidden">
328
+ <div class="mb-4">
329
+ <label class="block text-gray-300 mb-2">Configuração por Série</label>
330
+ <div id="customSeriesConfig" class="space-y-4">
331
+ <!-- Will be populated by JavaScript -->
332
+ </div>
333
+ </div>
334
+ </div>
335
+
336
+ <div class="mb-4">
337
+ <label class="block text-gray-300 mb-2">Tipo de Contagem</label>
338
+ <select id="customCountType" class="w-full px-3 py-2 bg-gray-700 rounded">
339
+ <option value="progress">Progressiva</option>
340
+ <option value="regress">Regressiva</option>
341
+ </select>
342
+ </div>
343
+
344
+ <div class="flex justify-between">
345
+ <button onclick="backToMenu()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
346
+ <i class="fas fa-arrow-left mr-2"></i> Voltar
347
+ </button>
348
+ <button onclick="startCustom()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
349
+ <i class="fas fa-play mr-2"></i> Iniciar
350
+ </button>
351
+ </div>
352
+ </div>
353
+ </div>
354
+
355
+ <!-- Custom Timer Screen -->
356
+ <div id="customTimerScreen" class="hidden text-center">
357
+ <h2 class="text-3xl font-bold mb-2">Customizado</h2>
358
+ <p class="text-xl mb-8" id="customPhase">Preparar</p>
359
+
360
+ <div class="relative w-64 h-64 mx-auto mb-8">
361
+ <svg class="w-full h-full" viewBox="0 0 100 100">
362
+ <circle cx="50" cy="50" r="45" fill="none" stroke="#333" stroke-width="8"/>
363
+ <circle id="customProgress" cx="50" cy="50" r="45" fill="none" stroke="#10B981" stroke-width="8" stroke-dasharray="283" stroke-dashoffset="283" class="progress-ring"/>
364
+ </svg>
365
+ <div class="absolute inset-0 flex items-center justify-center">
366
+ <div id="customTime" class="text-5xl font-mono">00:10</div>
367
+ </div>
368
+ </div>
369
+
370
+ <div class="mb-4">
371
+ <span id="customRound" class="text-xl">Série 1/3</span>
372
+ </div>
373
+
374
+ <button onclick="pauseCustom()" id="customPauseBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-2 px-6 rounded mr-2">
375
+ <i class="fas fa-pause mr-2"></i> Pausar
376
+ </button>
377
+ <button onclick="stopCustom()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-6 rounded">
378
+ <i class="fas fa-stop mr-2"></i> Parar
379
+ </button>
380
+ </div>
381
+ </div>
382
+
383
+ <script>
384
+ // Global variables
385
+ let currentScreen = 'mainMenu';
386
+ let clockInterval;
387
+ let tabataInterval;
388
+ let forTimeInterval;
389
+ let qspInterval;
390
+ let emomInterval;
391
+ let customInterval;
392
+
393
+ // Audio elements
394
+ const beepSound = document.getElementById('beepSound');
395
+ const endSound = document.getElementById('endSound');
396
+
397
+ // Initialize the app
398
+ document.addEventListener('DOMContentLoaded', function() {
399
+ updateClock();
400
+ clockInterval = setInterval(updateClock, 1000);
401
+
402
+ // Setup event listeners for custom config
403
+ document.getElementById('customEqualTime').addEventListener('change', function() {
404
+ const equalTime = this.value === 'yes';
405
+ document.getElementById('customEqualTimeConfig').style.display = equalTime ? 'block' : 'none';
406
+ document.getElementById('customDifferentTimeConfig').style.display = equalTime ? 'none' : 'block';
407
+
408
+ if (!equalTime) {
409
+ setupCustomSeriesConfig();
410
+ }
411
+ });
412
+ });
413
+
414
+ // Navigation functions
415
+ function backToMenu() {
416
+ hideAllScreens();
417
+ document.getElementById('mainMenu').classList.remove('hidden');
418
+ currentScreen = 'mainMenu';
419
+
420
+ // Clear any running timers
421
+ clearAllIntervals();
422
+ }
423
+
424
+ function showClock() {
425
+ hideAllScreens();
426
+ document.getElementById('clockScreen').classList.remove('hidden');
427
+ currentScreen = 'clock';
428
+ }
429
+
430
+ function showTabataConfig() {
431
+ hideAllScreens();
432
+ document.getElementById('tabataConfigScreen').classList.remove('hidden');
433
+ currentScreen = 'tabataConfig';
434
+ }
435
+
436
+ function showForTimeConfig() {
437
+ hideAllScreens();
438
+ document.getElementById('forTimeConfigScreen').classList.remove('hidden');
439
+ currentScreen = 'forTimeConfig';
440
+ }
441
+
442
+ function showQspConfig() {
443
+ hideAllScreens();
444
+ document.getElementById('qspConfigScreen').classList.remove('hidden');
445
+ currentScreen = 'qspConfig';
446
+ }
447
+
448
+ function showEmomConfig() {
449
+ hideAllScreens();
450
+ document.getElementById('emomConfigScreen').classList.remove('hidden');
451
+ currentScreen = 'emomConfig';
452
+ }
453
+
454
+ function showCustomConfig() {
455
+ hideAllScreens();
456
+ document.getElementById('customConfigScreen').classList.remove('hidden');
457
+ currentScreen = 'customConfig';
458
+ setupCustomSeriesConfig();
459
+ }
460
+
461
+ function hideAllScreens() {
462
+ const screens = [
463
+ 'mainMenu', 'clockScreen',
464
+ 'tabataConfigScreen', 'tabataTimerScreen',
465
+ 'forTimeConfigScreen', 'forTimeTimerScreen',
466
+ 'qspConfigScreen', 'qspTimerScreen',
467
+ 'emomConfigScreen', 'emomTimerScreen',
468
+ 'customConfigScreen', 'customTimerScreen'
469
+ ];
470
+
471
+ screens.forEach(screen => {
472
+ document.getElementById(screen).classList.add('hidden');
473
+ });
474
+ }
475
+
476
+ function clearAllIntervals() {
477
+ clearInterval(clockInterval);
478
+ clearInterval(tabataInterval);
479
+ clearInterval(forTimeInterval);
480
+ clearInterval(qspInterval);
481
+ clearInterval(emomInterval);
482
+ clearInterval(customInterval);
483
+ }
484
+
485
+ // Clock functions
486
+ function updateClock() {
487
+ const now = new Date();
488
+ const timeString = now.toLocaleTimeString();
489
+ document.getElementById('currentTime').textContent = timeString;
490
+ }
491
+
492
+ // Tabata functions
493
+ function startTabata() {
494
+ const rounds = parseInt(document.getElementById('tabataRounds').value);
495
+ const workTime = parseInt(document.getElementById('tabataWork').value);
496
+ const restTime = parseInt(document.getElementById('tabataRest').value);
497
+
498
+ // Initialize tabata state
499
+ const tabataState = {
500
+ rounds: rounds,
501
+ currentRound: 0,
502
+ workTime: workTime,
503
+ restTime: restTime,
504
+ remainingTime: 3, // 3 second countdown
505
+ phase: 'prepare', // prepare, work, rest
506
+ isRunning: true,
507
+ isPaused: false
508
+ };
509
+
510
+ // Update UI
511
+ document.getElementById('tabataRound').textContent = `Série 0/${rounds}`;
512
+ document.getElementById('tabataPhase').textContent = 'Preparar';
513
+ document.getElementById('tabataTime').textContent = formatTime(tabataState.remainingTime);
514
+
515
+ // Setup progress ring
516
+ const progressRing = document.getElementById('tabataProgress');
517
+ progressRing.style.stroke = '#10B981'; // Green
518
+ progressRing.style.strokeDashoffset = calculateDashOffset(tabataState.remainingTime, tabataState.remainingTime);
519
+
520
+ // Show timer screen
521
+ hideAllScreens();
522
+ document.getElementById('tabataTimerScreen').classList.remove('hidden');
523
+ currentScreen = 'tabataTimer';
524
+
525
+ // Start timer
526
+ clearInterval(tabataInterval);
527
+ tabataInterval = setInterval(() => updateTabataTimer(tabataState), 1000);
528
+ }
529
+
530
+ function updateTabataTimer(state) {
531
+ if (state.isPaused) return;
532
+
533
+ state.remainingTime--;
534
+
535
+ // Update progress ring
536
+ const progressRing = document.getElementById('tabataProgress');
537
+ let totalTime;
538
+
539
+ switch (state.phase) {
540
+ case 'prepare':
541
+ totalTime = 3;
542
+ break;
543
+ case 'work':
544
+ totalTime = state.workTime;
545
+ break;
546
+ case 'rest':
547
+ totalTime = state.restTime;
548
+ break;
549
+ }
550
+
551
+ const dashOffset = calculateDashOffset(state.remainingTime, totalTime);
552
+ progressRing.style.strokeDashoffset = dashOffset;
553
+
554
+ // Change color based on time remaining
555
+ if (state.remainingTime <= totalTime / 4 && state.phase !== 'prepare') {
556
+ progressRing.style.stroke = '#EF4444'; // Red
557
+ } else if (state.remainingTime <= totalTime / 2 && state.phase !== 'prepare') {
558
+ progressRing.style.stroke = '#F59E0B'; // Yellow
559
+ }
560
+
561
+ // Play sounds
562
+ if (state.remainingTime <= 3 && state.remainingTime > 0) {
563
+ playBeep();
564
+ document.getElementById('tabataTime').classList.add('beep');
565
+ setTimeout(() => {
566
+ document.getElementById('tabataTime').classList.remove('beep');
567
+ }, 500);
568
+ }
569
+
570
+ if (state.remainingTime === 0) {
571
+ playEndBeep();
572
+ document.getElementById('tabataTime').classList.add('long-beep');
573
+ setTimeout(() => {
574
+ document.getElementById('tabataTime').classList.remove('long-beep');
575
+ }, 1000);
576
+ }
577
+
578
+ // Update display
579
+ document.getElementById('tabataTime').textContent = formatTime(state.remainingTime);
580
+
581
+ // Handle phase transitions
582
+ if (state.remainingTime <= 0) {
583
+ if (state.phase === 'prepare') {
584
+ state.phase = 'work';
585
+ state.currentRound++;
586
+ state.remainingTime = state.workTime;
587
+ document.getElementById('tabataPhase').textContent = 'Trabalhar';
588
+ document.getElementById('tabataRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
589
+ progressRing.style.stroke = '#10B981'; // Reset to green
590
+ }
591
+ else if (state.phase === 'work') {
592
+ if (state.currentRound < state.rounds) {
593
+ state.phase = 'rest';
594
+ state.remainingTime = state.restTime;
595
+ document.getElementById('tabataPhase').textContent = 'Descansar';
596
+ progressRing.style.stroke = '#10B981'; // Reset to green
597
+ } else {
598
+ // Tabata complete
599
+ clearInterval(tabataInterval);
600
+ document.getElementById('tabataPhase').textContent = 'Concluído!';
601
+ return;
602
+ }
603
+ }
604
+ else if (state.phase === 'rest') {
605
+ state.phase = 'work';
606
+ state.currentRound++;
607
+ state.remainingTime = state.workTime;
608
+ document.getElementById('tabataPhase').textContent = 'Trabalhar';
609
+ document.getElementById('tabataRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
610
+ progressRing.style.stroke = '#10B981'; // Reset to green
611
+ }
612
+ }
613
+ }
614
+
615
+ function pauseTabata() {
616
+ const pauseBtn = document.getElementById('tabataPauseBtn');
617
+ if (pauseBtn.innerHTML.includes('Pausar')) {
618
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Continuar';
619
+ // Pause logic would be handled in the updateTabataTimer function
620
+ } else {
621
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> Pausar';
622
+ // Resume logic would be handled in the updateTabataTimer function
623
+ }
624
+ }
625
+
626
+ function stopTabata() {
627
+ clearInterval(tabataInterval);
628
+ backToMenu();
629
+ }
630
+
631
+ // For Time functions
632
+ function startForTime() {
633
+ const minutes = parseInt(document.getElementById('forTimeMinutes').value);
634
+ const seconds = parseInt(document.getElementById('forTimeSeconds').value);
635
+ const totalSeconds = minutes * 60 + seconds;
636
+
637
+ // Initialize state
638
+ const forTimeState = {
639
+ totalTime: totalSeconds,
640
+ elapsedTime: 0,
641
+ isRunning: true,
642
+ isPaused: false
643
+ };
644
+
645
+ // Update UI
646
+ document.getElementById('forTimeTime').textContent = formatTime(totalSeconds);
647
+
648
+ // Setup progress ring
649
+ const progressRing = document.getElementById('forTimeProgress');
650
+ progressRing.style.stroke = '#10B981'; // Green
651
+ progressRing.style.strokeDashoffset = calculateDashOffset(0, totalSeconds);
652
+
653
+ // Show timer screen
654
+ hideAllScreens();
655
+ document.getElementById('forTimeTimerScreen').classList.remove('hidden');
656
+ currentScreen = 'forTimeTimer';
657
+
658
+ // Start timer
659
+ clearInterval(forTimeInterval);
660
+ forTimeInterval = setInterval(() => updateForTimeTimer(forTimeState), 1000);
661
+ }
662
+
663
+ function updateForTimeTimer(state) {
664
+ if (state.isPaused) return;
665
+
666
+ state.elapsedTime++;
667
+ const remainingTime = state.totalTime - state.elapsedTime;
668
+
669
+ // Update progress ring
670
+ const progressRing = document.getElementById('forTimeProgress');
671
+ const dashOffset = calculateDashOffset(state.elapsedTime, state.totalTime);
672
+ progressRing.style.strokeDashoffset = dashOffset;
673
+
674
+ // Change color based on time remaining
675
+ if (remainingTime <= state.totalTime / 4) {
676
+ progressRing.style.stroke = '#EF4444'; // Red
677
+ } else if (remainingTime <= state.totalTime / 2) {
678
+ progressRing.style.stroke = '#F59E0B'; // Yellow
679
+ }
680
+
681
+ // Play sounds
682
+ if (remainingTime <= 3 && remainingTime > 0) {
683
+ playBeep();
684
+ document.getElementById('forTimeTime').classList.add('beep');
685
+ setTimeout(() => {
686
+ document.getElementById('forTimeTime').classList.remove('beep');
687
+ }, 500);
688
+ }
689
+
690
+ if (remainingTime === 0) {
691
+ playEndBeep();
692
+ document.getElementById('forTimeTime').classList.add('long-beep');
693
+ setTimeout(() => {
694
+ document.getElementById('forTimeTime').classList.remove('long-beep');
695
+ }, 1000);
696
+ }
697
+
698
+ // Update display
699
+ document.getElementById('forTimeTime').textContent = formatTime(remainingTime);
700
+
701
+ // Check if timer is complete
702
+ if (state.elapsedTime >= state.totalTime) {
703
+ clearInterval(forTimeInterval);
704
+ }
705
+ }
706
+
707
+ function pauseForTime() {
708
+ const pauseBtn = document.getElementById('forTimePauseBtn');
709
+ if (pauseBtn.innerHTML.includes('Pausar')) {
710
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Continuar';
711
+ // Pause logic would be handled in the updateForTimeTimer function
712
+ } else {
713
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> Pausar';
714
+ // Resume logic would be handled in the updateForTimeTimer function
715
+ }
716
+ }
717
+
718
+ function stopForTime() {
719
+ clearInterval(forTimeInterval);
720
+ backToMenu();
721
+ }
722
+
723
+ // QSP functions
724
+ function startQsp() {
725
+ const minutes = parseInt(document.getElementById('qspMinutes').value);
726
+ const seconds = parseInt(document.getElementById('qspSeconds').value);
727
+ const totalSeconds = minutes * 60 + seconds;
728
+
729
+ // Initialize state
730
+ const qspState = {
731
+ remainingTime: totalSeconds,
732
+ isRunning: true,
733
+ isPaused: false
734
+ };
735
+
736
+ // Update UI
737
+ document.getElementById('qspTime').textContent = formatTime(totalSeconds);
738
+
739
+ // Setup progress ring
740
+ const progressRing = document.getElementById('qspProgress');
741
+ progressRing.style.stroke = '#10B981'; // Green
742
+ progressRing.style.strokeDashoffset = calculateDashOffset(totalSeconds, totalSeconds);
743
+
744
+ // Show timer screen
745
+ hideAllScreens();
746
+ document.getElementById('qspTimerScreen').classList.remove('hidden');
747
+ currentScreen = 'qspTimer';
748
+
749
+ // Start timer
750
+ clearInterval(qspInterval);
751
+ qspInterval = setInterval(() => updateQspTimer(qspState), 1000);
752
+ }
753
+
754
+ function updateQspTimer(state) {
755
+ if (state.isPaused) return;
756
+
757
+ state.remainingTime--;
758
+
759
+ // Update progress ring
760
+ const progressRing = document.getElementById('qspProgress');
761
+ const totalTime = state.remainingTime + state.elapsedTime; // Need to track initial total time
762
+ const dashOffset = calculateDashOffset(state.remainingTime, totalTime);
763
+ progressRing.style.strokeDashoffset = dashOffset;
764
+
765
+ // Change color based on time remaining
766
+ if (state.remainingTime <= totalTime / 4) {
767
+ progressRing.style.stroke = '#EF4444'; // Red
768
+ } else if (state.remainingTime <= totalTime / 2) {
769
+ progressRing.style.stroke = '#F59E0B'; // Yellow
770
+ }
771
+
772
+ // Play sounds
773
+ if (state.remainingTime <= 3 && state.remainingTime > 0) {
774
+ playBeep();
775
+ document.getElementById('qspTime').classList.add('beep');
776
+ setTimeout(() => {
777
+ document.getElementById('qspTime').classList.remove('beep');
778
+ }, 500);
779
+ }
780
+
781
+ if (state.remainingTime === 0) {
782
+ playEndBeep();
783
+ document.getElementById('qspTime').classList.add('long-beep');
784
+ setTimeout(() => {
785
+ document.getElementById('qspTime').classList.remove('long-beep');
786
+ }, 1000);
787
+ }
788
+
789
+ // Update display
790
+ document.getElementById('qspTime').textContent = formatTime(state.remainingTime);
791
+
792
+ // Check if timer is complete
793
+ if (state.remainingTime <= 0) {
794
+ clearInterval(qspInterval);
795
+ }
796
+ }
797
+
798
+ function pauseQsp() {
799
+ const pauseBtn = document.getElementById('qspPauseBtn');
800
+ if (pauseBtn.innerHTML.includes('Pausar')) {
801
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Continuar';
802
+ // Pause logic would be handled in the updateQspTimer function
803
+ } else {
804
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> Pausar';
805
+ // Resume logic would be handled in the updateQspTimer function
806
+ }
807
+ }
808
+
809
+ function stopQsp() {
810
+ clearInterval(qspInterval);
811
+ backToMenu();
812
+ }
813
+
814
+ // EMOM functions
815
+ function startEmom() {
816
+ const rounds = parseInt(document.getElementById('emomRounds').value);
817
+ const workMinutes = parseInt(document.getElementById('emomWorkMinutes').value);
818
+ const workSeconds = parseInt(document.getElementById('emomWorkSeconds').value);
819
+ const restMinutes = parseInt(document.getElementById('emomRestMinutes').value);
820
+ const restSeconds = parseInt(document.getElementById('emomRestSeconds').value);
821
+
822
+ const workTime = workMinutes * 60 + workSeconds;
823
+ const restTime = restMinutes * 60 + restSeconds;
824
+
825
+ // Initialize emom state
826
+ const emomState = {
827
+ rounds: rounds,
828
+ currentRound: 0,
829
+ workTime: workTime,
830
+ restTime: restTime,
831
+ remainingTime: 3, // 3 second countdown
832
+ phase: 'prepare', // prepare, work, rest
833
+ isRunning: true,
834
+ isPaused: false
835
+ };
836
+
837
+ // Update UI
838
+ document.getElementById('emomRound').textContent = `Série 0/${rounds}`;
839
+ document.getElementById('emomPhase').textContent = 'Preparar';
840
+ document.getElementById('emomTime').textContent = formatTime(emomState.remainingTime);
841
+
842
+ // Setup progress ring
843
+ const progressRing = document.getElementById('emomProgress');
844
+ progressRing.style.stroke = '#10B981'; // Green
845
+ progressRing.style.strokeDashoffset = calculateDashOffset(emomState.remainingTime, emomState.remainingTime);
846
+
847
+ // Show timer screen
848
+ hideAllScreens();
849
+ document.getElementById('emomTimerScreen').classList.remove('hidden');
850
+ currentScreen = 'emomTimer';
851
+
852
+ // Start timer
853
+ clearInterval(emomInterval);
854
+ emomInterval = setInterval(() => updateEmomTimer(emomState), 1000);
855
+ }
856
+
857
+ function updateEmomTimer(state) {
858
+ if (state.isPaused) return;
859
+
860
+ state.remainingTime--;
861
+
862
+ // Update progress ring
863
+ const progressRing = document.getElementById('emomProgress');
864
+ let totalTime;
865
+
866
+ switch (state.phase) {
867
+ case 'prepare':
868
+ totalTime = 3;
869
+ break;
870
+ case 'work':
871
+ totalTime = state.workTime;
872
+ break;
873
+ case 'rest':
874
+ totalTime = state.restTime;
875
+ break;
876
+ }
877
+
878
+ const dashOffset = calculateDashOffset(state.remainingTime, totalTime);
879
+ progressRing.style.strokeDashoffset = dashOffset;
880
+
881
+ // Change color based on time remaining
882
+ if (state.remainingTime <= totalTime / 4 && state.phase !== 'prepare') {
883
+ progressRing.style.stroke = '#EF4444'; // Red
884
+ } else if (state.remainingTime <= totalTime / 2 && state.phase !== 'prepare') {
885
+ progressRing.style.stroke = '#F59E0B'; // Yellow
886
+ }
887
+
888
+ // Play sounds
889
+ if (state.remainingTime <= 3 && state.remainingTime > 0) {
890
+ playBeep();
891
+ document.getElementById('emomTime').classList.add('beep');
892
+ setTimeout(() => {
893
+ document.getElementById('emomTime').classList.remove('beep');
894
+ }, 500);
895
+ }
896
+
897
+ if (state.remainingTime === 0) {
898
+ playEndBeep();
899
+ document.getElementById('emomTime').classList.add('long-beep');
900
+ setTimeout(() => {
901
+ document.getElementById('emomTime').classList.remove('long-beep');
902
+ }, 1000);
903
+ }
904
+
905
+ // Update display
906
+ document.getElementById('emomTime').textContent = formatTime(state.remainingTime);
907
+
908
+ // Handle phase transitions
909
+ if (state.remainingTime <= 0) {
910
+ if (state.phase === 'prepare') {
911
+ state.phase = 'work';
912
+ state.currentRound++;
913
+ state.remainingTime = state.workTime;
914
+ document.getElementById('emomPhase').textContent = 'Trabalhar';
915
+ document.getElementById('emomRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
916
+ progressRing.style.stroke = '#10B981'; // Reset to green
917
+ }
918
+ else if (state.phase === 'work') {
919
+ if (state.currentRound < state.rounds) {
920
+ state.phase = 'rest';
921
+ state.remainingTime = state.restTime;
922
+ document.getElementById('emomPhase').textContent = 'Descansar';
923
+ progressRing.style.stroke = '#10B981'; // Reset to green
924
+ } else {
925
+ // EMOM complete
926
+ clearInterval(emomInterval);
927
+ document.getElementById('emomPhase').textContent = 'Concluído!';
928
+ return;
929
+ }
930
+ }
931
+ else if (state.phase === 'rest') {
932
+ state.phase = 'work';
933
+ state.currentRound++;
934
+ state.remainingTime = state.workTime;
935
+ document.getElementById('emomPhase').textContent = 'Trabalhar';
936
+ document.getElementById('emomRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
937
+ progressRing.style.stroke = '#10B981'; // Reset to green
938
+ }
939
+ }
940
+ }
941
+
942
+ function pauseEmom() {
943
+ const pauseBtn = document.getElementById('emomPauseBtn');
944
+ if (pauseBtn.innerHTML.includes('Pausar')) {
945
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Continuar';
946
+ // Pause logic would be handled in the updateEmomTimer function
947
+ } else {
948
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> Pausar';
949
+ // Resume logic would be handled in the updateEmomTimer function
950
+ }
951
+ }
952
+
953
+ function stopEmom() {
954
+ clearInterval(emomInterval);
955
+ backToMenu();
956
+ }
957
+
958
+ // Custom functions
959
+ function setupCustomSeriesConfig() {
960
+ const rounds = parseInt(document.getElementById('customRounds').value);
961
+ const container = document.getElementById('customSeriesConfig');
962
+ container.innerHTML = '';
963
+
964
+ for (let i = 0; i < rounds; i++) {
965
+ const seriesDiv = document.createElement('div');
966
+ seriesDiv.className = 'bg-gray-700 p-4 rounded';
967
+ seriesDiv.innerHTML = `
968
+ <h3 class="text-lg font-semibold mb-2">Série ${i + 1}</h3>
969
+ <div class="mb-2">
970
+ <label class="block text-gray-300 mb-1">Tempo (minutos:segundos)</label>
971
+ <div class="flex">
972
+ <input type="number" id="customWorkMinutes${i}" min="0" max="30" value="1" class="w-1/2 px-2 py-1 bg-gray-600 rounded mr-2">
973
+ <input type="number" id="customWorkSeconds${i}" min="0" max="59" value="0" class="w-1/2 px-2 py-1 bg-gray-600 rounded">
974
+ </div>
975
+ </div>
976
+ <div>
977
+ <label class="block text-gray-300 mb-1">Descanso (minutos:segundos)</label>
978
+ <div class="flex">
979
+ <input type="number" id="customRestMinutes${i}" min="0" max="30" value="0" class="w-1/2 px-2 py-1 bg-gray-600 rounded mr-2">
980
+ <input type="number" id="customRestSeconds${i}" min="0" max="59" value="30" class="w-1/2 px-2 py-1 bg-gray-600 rounded">
981
+ </div>
982
+ </div>
983
+ `;
984
+ container.appendChild(seriesDiv);
985
+ }
986
+ }
987
+
988
+ function startCustom() {
989
+ const countdown = parseInt(document.getElementById('customCountdown').value);
990
+ const rounds = parseInt(document.getElementById('customRounds').value);
991
+ const equalTime = document.getElementById('customEqualTime').value === 'yes';
992
+ const countType = document.getElementById('customCountType').value;
993
+
994
+ let seriesTimes = [];
995
+ let restTimes = [];
996
+
997
+ if (equalTime) {
998
+ const workMinutes = parseInt(document.getElementById('customWorkMinutes').value);
999
+ const workSeconds = parseInt(document.getElementById('customWorkSeconds').value);
1000
+ const restMinutes = parseInt(document.getElementById('customRestMinutes').value);
1001
+ const restSeconds = parseInt(document.getElementById('customRestSeconds').value);
1002
+
1003
+ const workTime = workMinutes * 60 + workSeconds;
1004
+ const restTime = restMinutes * 60 + restSeconds;
1005
+
1006
+ for (let i = 0; i < rounds; i++) {
1007
+ seriesTimes.push(workTime);
1008
+ restTimes.push(restTime);
1009
+ }
1010
+ } else {
1011
+ for (let i = 0; i < rounds; i++) {
1012
+ const workMinutes = parseInt(document.getElementById(`customWorkMinutes${i}`).value);
1013
+ const workSeconds = parseInt(document.getElementById(`customWorkSeconds${i}`).value);
1014
+ const restMinutes = parseInt(document.getElementById(`customRestMinutes${i}`).value);
1015
+ const restSeconds = parseInt(document.getElementById(`customRestSeconds${i}`).value);
1016
+
1017
+ seriesTimes.push(workMinutes * 60 + workSeconds);
1018
+ restTimes.push(restMinutes * 60 + restSeconds);
1019
+ }
1020
+ }
1021
+
1022
+ // Initialize custom state
1023
+ const customState = {
1024
+ rounds: rounds,
1025
+ currentRound: 0,
1026
+ seriesTimes: seriesTimes,
1027
+ restTimes: restTimes,
1028
+ remainingTime: countdown,
1029
+ phase: 'prepare', // prepare, work, rest
1030
+ countType: countType,
1031
+ isRunning: true,
1032
+ isPaused: false
1033
+ };
1034
+
1035
+ // Update UI
1036
+ document.getElementById('customRound').textContent = `Série 0/${rounds}`;
1037
+ document.getElementById('customPhase').textContent = 'Preparar';
1038
+ document.getElementById('customTime').textContent = formatTime(customState.remainingTime);
1039
+
1040
+ // Setup progress ring
1041
+ const progressRing = document.getElementById('customProgress');
1042
+ progressRing.style.stroke = '#10B981'; // Green
1043
+ progressRing.style.strokeDashoffset = calculateDashOffset(customState.remainingTime, customState.remainingTime);
1044
+
1045
+ // Show timer screen
1046
+ hideAllScreens();
1047
+ document.getElementById('customTimerScreen').classList.remove('hidden');
1048
+ currentScreen = 'customTimer';
1049
+
1050
+ // Start timer
1051
+ clearInterval(customInterval);
1052
+ customInterval = setInterval(() => updateCustomTimer(customState), 1000);
1053
+ }
1054
+
1055
+ function updateCustomTimer(state) {
1056
+ if (state.isPaused) return;
1057
+
1058
+ state.remainingTime--;
1059
+
1060
+ // Update progress ring
1061
+ const progressRing = document.getElementById('customProgress');
1062
+ let totalTime;
1063
+
1064
+ switch (state.phase) {
1065
+ case 'prepare':
1066
+ totalTime = state.remainingTime + 1; // Initial countdown
1067
+ break;
1068
+ case 'work':
1069
+ totalTime = state.seriesTimes[state.currentRound - 1];
1070
+ break;
1071
+ case 'rest':
1072
+ totalTime = state.restTimes[state.currentRound - 1];
1073
+ break;
1074
+ }
1075
+
1076
+ const dashOffset = calculateDashOffset(state.remainingTime, totalTime);
1077
+ progressRing.style.strokeDashoffset = dashOffset;
1078
+
1079
+ // Change color based on time remaining
1080
+ if (state.remainingTime <= totalTime / 4 && state.phase !== 'prepare') {
1081
+ progressRing.style.stroke = '#EF4444'; // Red
1082
+ } else if (state.remainingTime <= totalTime / 2 && state.phase !== 'prepare') {
1083
+ progressRing.style.stroke = '#F59E0B'; // Yellow
1084
+ }
1085
+
1086
+ // Play sounds
1087
+ if (state.remainingTime <= 3 && state.remainingTime > 0) {
1088
+ playBeep();
1089
+ document.getElementById('customTime').classList.add('beep');
1090
+ setTimeout(() => {
1091
+ document.getElementById('customTime').classList.remove('beep');
1092
+ }, 500);
1093
+ }
1094
+
1095
+ if (state.remainingTime === 0) {
1096
+ playEndBeep();
1097
+ document.getElementById('customTime').classList.add('long-beep');
1098
+ setTimeout(() => {
1099
+ document.getElementById('customTime').classList.remove('long-beep');
1100
+ }, 1000);
1101
+ }
1102
+
1103
+ // Update display
1104
+ document.getElementById('customTime').textContent = formatTime(state.remainingTime);
1105
+
1106
+ // Handle phase transitions
1107
+ if (state.remainingTime <= 0) {
1108
+ if (state.phase === 'prepare') {
1109
+ state.phase = 'work';
1110
+ state.currentRound++;
1111
+ state.remainingTime = state.seriesTimes[state.currentRound - 1];
1112
+ document.getElementById('customPhase').textContent = 'Trabalhar';
1113
+ document.getElementById('customRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
1114
+ progressRing.style.stroke = '#10B981'; // Reset to green
1115
+ }
1116
+ else if (state.phase === 'work') {
1117
+ if (state.currentRound < state.rounds) {
1118
+ state.phase = 'rest';
1119
+ state.remainingTime = state.restTimes[state.currentRound - 1];
1120
+ document.getElementById('customPhase').textContent = 'Descansar';
1121
+ progressRing.style.stroke = '#10B981'; // Reset to green
1122
+ } else {
1123
+ // Custom complete
1124
+ clearInterval(customInterval);
1125
+ document.getElementById('customPhase').textContent = 'Concluído!';
1126
+ return;
1127
+ }
1128
+ }
1129
+ else if (state.phase === 'rest') {
1130
+ state.phase = 'work';
1131
+ state.currentRound++;
1132
+ state.remainingTime = state.seriesTimes[state.currentRound - 1];
1133
+ document.getElementById('customPhase').textContent = 'Trabalhar';
1134
+ document.getElementById('customRound').textContent = `Série ${state.currentRound}/${state.rounds}`;
1135
+ progressRing.style.stroke = '#10B981'; // Reset to green
1136
+ }
1137
+ }
1138
+ }
1139
+
1140
+ function pauseCustom() {
1141
+ const pauseBtn = document.getElementById('customPauseBtn');
1142
+ if (pauseBtn.innerHTML.includes('Pausar')) {
1143
+ pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Continuar';
1144
+ // Pause logic would be handled in the updateCustomTimer function
1145
+ } else {
1146
+ pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i> Pausar';
1147
+ // Resume logic would be handled in the updateCustomTimer function
1148
+ }
1149
+ }
1150
+
1151
+ function stopCustom() {
1152
+ clearInterval(customInterval);
1153
+ backToMenu();
1154
+ }
1155
+
1156
+ // Helper functions
1157
+ function formatTime(seconds) {
1158
+ const mins = Math.floor(seconds / 60);
1159
+ const secs = seconds % 60;
1160
+ return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
1161
+ }
1162
+
1163
+ function calculateDashOffset(remaining, total) {
1164
+ const circumference = 283; // 2 * π * r (where r is 45)
1165
+ const progress = remaining / total;
1166
+ return circumference * progress;
1167
+ }
1168
+
1169
+ function playBeep() {
1170
+ beepSound.currentTime = 0;
1171
+ beepSound.play();
1172
+ }
1173
+
1174
+ function playEndBeep() {
1175
+ endSound.currentTime = 0;
1176
+ endSound.play();
1177
+ }
1178
+ </script>
1179
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=XiaoxiaoBR/timerwod" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1180
+ </html>