Ferramenta para auxiliar na aplicação do método Pomodoro. Controle seus ciclos de foco e descanso e aumente sua produtividade.
Acesse a aplicação clicando aqui.
🛠️ Permanência de dados da configuração utilizando localStorage;
⚙️ Animação na engrenagem e na sidebar;
🧐 Sidebar criada com técnica de glassmorphism;
🔊 Aviso sonoro ao fim de cada ciclo;
🎨 Mudança de cor de fundo proporcional ao tempo decorrido;
⏱️ Cronômetro com 3 estágios: foco, pausa e descanso;
#️⃣ Contagem de ciclos concluídos;
🤖 Contador de tempo aparece na aba do navegador;
🖋️ Tipografia fluida
O código estava estruturado em uma sequência de condicionais, o que dificultava a manutenção e mesmo o desenvolvimento em si do projeto. A criação de um objeto com as regras de cada etapa, e uma função que executa essas regras tornou o código mais legível e permitiu enxergar novas possibilidades de melhoria, como a criação da etapa "skip code". O código era assim (ainda em estágio intermediário de desenvolvimento):
if(controlButton.innerText==='START'){
noticeToUser.innerText = "Concentre-se";
controlButton.innerText = 'pause';
timer.innerText = formatTime(timeLeft);
cycleCount++;
cycles.innerText = cycleCount;
clearInterval(counter);
clearTimeout(timeOut);
counter = setInterval(() => {
bodyHue += rate;
body.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
controlButton.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
timeLeft--;
timer.innerText = formatTime(timeLeft);
}, "1000");
setsCountdown();
} else if(controlButton.innerText==='PAUSE'){
noticeToUser.innerText = "Tempo pausado";
controlButton.innerText = 'restart';
clearInterval(counter);
clearTimeout(timeOut);
} else if(controlButton.innerText==='RESTART'){
noticeToUser.innerText = "Concentre-se";
controlButton.innerText = 'pause';
counter = setInterval(() => {
bodyHue += rate;
body.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
controlButton.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
timeLeft--;
timer.innerText = formatTime(timeLeft);
}, "1000");
setsCountdown();
} else if(controlButton.innerText==='REST'){
noticeToUser.innerText = "Começou seu descanso";
controlButton.innerText = 'start';
let totalRestTime = cycleCount % 4 === 0 ? longerRestTime : restTime;
let restTimeLeft = totalRestTime / 1000;
timer.innerText = formatTime(restTimeLeft);
counter = setInterval(() => {
let restRate = 120/(totalRestTime/1000);
bodyHue -= restRate;
body.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
controlButton.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
restTimeLeft--;
timer.innerText = formatTime(restTimeLeft);
}, "1000");
timeOut = setTimeout(() => {
console.log("Acabou o Descanso!");
clearInterval(counter);
noticeToUser.innerText = "Seu descanso acabou. Comece mais um foco"
}, restTimeLeft * 1000);
}
function setsCountdown(){
timeOut = setTimeout(() =>
{
clearInterval(counter);
noticeToUser.innerText = "Seu Pomodoro acabou. Descanse um pouco";
controlButton.innerText = 'rest';
timeLeft = totalTime / 1000;
}, timeLeft * 1000);
}
E foi estruturado como pode ser visto no arquivo pomodoroEngine.js.
A seção de mensagem ao usuário, ainda que vazia, ocupa espaço na tela, permitindo uma quantidade menor de mudança de layout. Para isso utilizei a propriedade white-space com o valor pre-wrap (a classe utilitária whitespace-pre-wrap no Tailwind).
Utilização de input text para os valores numéricos da configuração, tendo em vista os problemas que o input number pode trazer (ver: https://css-tricks.com/what-to-use-instead-of-number-inputs/ ). Para lidar com isso, criei uma validação que impede o usuário de inserir qualquer caracter não numérico:
const allowOnlyNumbers = value => value.replace(/[^0-9]+/, '');
Havia utilizado outra forma de checar se um valor era uma letra, mas símbolos e acentos não eram identificados
const isLetter = (character) => character.toLowerCase() != character.toUpperCase();
A mudança de cores do fundo havia sido estruturada da seguinte forma:
let percentageOfInterval = 100 - (((timeLeft*1000) / totalTime) * 100);
bodyHue = percentageOfInterval *1.2;
Isso funcionava para partir do Hue 0, mas não funcionava para retornar para o ponto inicial. Reestruturei o código utilizanto uma taxa e direção, o que permite lidar com situações como a volta à cor inicial, no caso da etapa 'break' e permitir que a cor final seja sempre a mesma em casos de pausa (em uma etapa do desenvolvimento a pausa reiniciava a mudança de cor, fazendo com que a cor de fundo variasse de acordo com a quantidade de pausas que o usuário fazia):
function changesBg(rate, direction){
direction === 'forward' ? bodyHue += rate : bodyHue -= rate;
body.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
controlButton.style.backgroundColor = `hsl(${bodyHue}, 50%, 25%)`;
}
Precisei ainda criar uma animação que restabelece de forma gradativa a cor de fundo caso o usuário resolva pular o descanso ('skip rest'):
.restore{
animation-name: backToRed;
animation-duration: 1.5s;
animation-timing-function: ease-in-out;
animation-direction: normal;
animation-fill-mode: forwards;
}
@keyframes backToRed{
to{
background-color: hsl(0, 50%, 25%)
}
}
Criei um mecanismo para impedir que o temporizador funcione quando o menu de configurações lateral é aberto.
const handlePomodoroButton = () => {
switch(controlButton.innerText){
case 'START':
break;
case 'PAUSE':
pomodoroEngine('PAUSE')
break;
case 'RESTART':
!sidebarIsOpen && pomodoroEngine('RESTART')
//Prevents pomodoro from restarting when user had paused it before opening configs, and having the time reunning while user was in configs
break;
}
}
Utilização de operadores ternários e short-circuit evaluation para trazer mais concisão e legibilidade para o código.
const toggleTranslate = () => {
sidebar.classList.toggle('translate-x-full');
sidebarIsOpen ? sidebarIsOpen = false : sidebarIsOpen = true;
}
saveButton.addEventListener('click', e => {
e.preventDefault();
setDurations();
controlButton.innerText==="RESTART" && cycleCount--; //if configs ae saved during a cycle, decreases cycle count before increasing in pomodoroEngine
handleSidebar(gear);
pomodoroEngine('START');
});
O objetivo deste projeto foi desenvolver um sistema do Pomodoro em equipe durante o evento Live CoDe.
- Create timeout
- Create Pomodoro activator
- Conect Pomodoro activator through JS
- Create total time controler
- Create countdown per second
- Calculate remaining time
- Create timer element on screen
- Make timer change according to countdown
- Control time, and after 25 minutes let user know time is out
- Button to pause and get back
- Button for interval
- Show count of cycles
- After 4, long pause
- Change bg color according to mode
- Change happens gradually
- Style with Tailwind
- Create Pomodoro Engine
- Gear icon to open modal to setting
- Animate gear
- Style form as sidebar
- Style input in form
- Set time with input
- When hit save sidebar goes away
- When hit save pomodoro restarts
- When engine is hit, pomodoro pauses
- Update tab title with timer
- Setting fluid typography
- Disable button when sidebaer shows
- Restart cycle when hitting save
- Prevent pomodoro from restarting when user had paused it before opening configs
- Save setting to local Storage
- Setting timer on start dinamically
- Sound at end of cycles
- JS Organization