Late Night
A productivity tool based on the Pomodoro technique with work and break intervals.
<!DOCTYPE html>
<html>
<head>
<title>Pomodoro</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/ico" href="/favicon.ico" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.0/animate.compat.css"
integrity="sha512-5m1+8f8jC4ePfYvS39HmjqsYkkragJZaXV7kfreb5pytmTlDnZgXZ73JlYC0Ui25beVJMWLJq8AzDv4ZeXC9mg=="
crossorigin="anonymous" />
<script src="https://kit.fontawesome.com/c42ac314bc.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="main">
<div class="turns animated slideInDown">1/5</div>
<div class="time-container animated rotateIn">
<svg width="200" height="200" class="circle-container">
<circle class="background-circle" r="90" cx="100" cy="100" />
<circle class="circle" r="90" cx="100" cy="100" />
</svg>
<div class="time">00:00</div>
<div class="config">
<i class="fas fa-cog" data-toggle="collapse" data-target="#drop-content"></i>
<span class="config-tooltip-text">Settings</span>
</div>
</div>
<div id="drop-content" class="collapse dropdown-content">
<div class="select-options">
<label for="work-time-options">Time:</label>
<select id="work-time-options" name="work-options" onchange="showResetMessage()">
<option value="5" >5 minutes</option>
<option value="10">10 minutes</option>
<option value="25">25 minutes</option>
<option value="30">30 minutes</option>
<option value="35">35 minutes</option>
<option value="40">40 minutes</option>
<option value="45">45 minutes</option>
<option value="60">60 minutes</option>
</select>
<label for="total-turns-options">Turns:</label>
<select id="total-turns-options" name="qtde-turns" onchange="showResetMessage()">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>
<div class="config-message">
<span>
<a href="javascript:reset()">Update</a> the timer
</span>
</div>
</div>
<div class="time-mode animated zoomIn"><button>Start</button></div>
<div>
<button class="timer-control animated slideInLeft">Pause
</button>
<button class="reset-button animated slideInRight">Reset</button>
</div>
</div>
<audio id="notification">
<source src="notification.mp3">
</audio>
<script src="scripts.js"></script>
</body>
</html>
scripts.js
const circleElement = document.querySelector('.circle');
const timeElement = document.querySelector('.time');
const timeModeElement = document.querySelector('.time-mode');
const turnElement = document.querySelector('.turns');
const controlButton = document.querySelector('.timer-control');
const resetButton = document.querySelector('.reset-button');
const notificationSound = document.querySelector('#notification');
const timeContainerElement = document.querySelector('.time-container');
let isRunning,
isBreakTime,
workTime,
breakTime,
longBreakTime,
totalTurns,
currentTurn,
totalTime,
timeRemaining,
timer;
controlButton.addEventListener('click', toggleStartPause);
resetButton.addEventListener('click', reset);
Notification.requestPermission();
function startValues() {
let workTimeElement = document.querySelector('#work-time-options');
let totalTurnsElement = document.querySelector('#total-turns-options');
isRunning = false;
isBreakTime = false;
workTime = (workTimeElement.options[workTimeElement.selectedIndex].value) * 60;
breakTime = ((workTimeElement.options[workTimeElement.selectedIndex].value) / 5) * 60;
longBreakTime = ((workTimeElement.options[workTimeElement.selectedIndex].value) - 10) * 60;
totalTurns = totalTurnsElement.options[totalTurnsElement.selectedIndex].value;
currentTurn = 1;
totalTime = workTime;
timeRemaining = totalTime;
timer = null;
}
function toggleStartPause() {
isRunning ? pause() : start();
}
function start() {
isRunning = true;
controlButton.innerText = 'Pause';
timer = setInterval(updateTimer, 1000);
timeContainerElement.classList.remove('rotateIn');
}
function pause() {
isRunning = false;
controlButton.innerText = 'Start';
clearInterval(timer);
}
function reset() {
pause();
startValues();
drawTime();
drawTurn();
runAnimation('rotateIn');
document.querySelector('.config-message').style.display = 'none';
}
function updateTimer() {
if (timeRemaining > 0) {
timeRemaining--;
}
else {
finishTurn();
}
drawTime();
}
function finishTurn() {
notificationSound.play();
runAnimation('swing');
nextTurn();
drawTurn();
}
function runAnimation(animation) {
timeContainerElement.classList.add(animation);
timeContainerElement.addEventListener('animationend', () => {
timeContainerElement.classList.remove(animation);
});
}
function nextTurn() {
isBreakTime = !isBreakTime;
if (!isBreakTime) {
currentTurn++;
}
if (currentTurn <= totalTurns) {
if (isBreakTime) {
totalTime = currentTurn < totalTurns ? breakTime : longBreakTime;
showNotification("Hora de descansar", "Parabéns pelo trabalho, aproveite os próximos minutos para descansar");
} else {
totalTime = workTime;
showNotification("Voltar ao trabalho", "Você está quase lá, só mais alguns minutos de trabalho");
}
timeRemaining = totalTime;
} else {
reset();
}
}
function drawTime() {
const minutes = Math.floor(timeRemaining / 60).toString().padStart(2, '0');
const seconds = Math.floor(timeRemaining % 60).toString().padStart(2, '0');
timeElement.innerText = `${minutes}:${seconds}`;
setCirclePercent(timeRemaining / totalTime * 100);
}
function drawTurn() {
let timeMode = 'Timer';
if (isBreakTime) {
timeMode = currentTurn < totalTurns ? 'Break' : 'Finished';
}
timeModeElement.innerText = timeMode;
turnElement.innerText = `${currentTurn}/${totalTurns}`;
}
function setCirclePercent(percent) {
const circlePerimeter = 597;
const dashOffset = (circlePerimeter * (percent / 100));
circleElement.style.setProperty('--dash-offset', circlePerimeter - dashOffset);
}
function showNotification(messageHeader, messageBody) {
const notification = new Notification(messageHeader, { body: messageBody });
setTimeout(notification.close.bind(notification), 4000);
}
function showResetMessage() {
document.querySelector('.config-message').style.display = 'inline';
}
reset();
styles.css
:root {
--timer-color: #d10e08;
}
html, body {
height: 100%;
}
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
color: #e7e7e7;
background: #3023ae;
background: -moz-linear-gradient(60deg, #ce2616 0%, #f6a207 100%);
background: -webkit-linear-gradient(60deg, #ce2616 0%, #f6a207 100%);
background: linear-gradient(60deg, #ce2616 0%, #f6a207 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorsrt='#3023ae', endColor='#c86dd7');
}
button {
padding: 16px 32px;
font-size: 1em;
background-color: transparent;
border: 1px solid rgba(255, 255, 255, .1);
color: #e7e7e7;
border-radius: 5px;
cursor: pointer;
outline: none;
opacity: 100%;
transition: opacity 0.6s;
}
button:hover {
opacity: 50%;
transition: opacity 0.6s;
}
.main {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
height: 100%;
}
.turns {
background-color: rgba(255, 255, 255, .2);
font-size: 1.5em;
padding: 12px 24px;
border-radius: 5px;
}
.time-container {
position: relative;
}
.time, .config, .config-tooltip-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 3.2em;
}
.config {
top: 80%;
display: inline-block;
font-size: 1.3em;
cursor: pointer;
opacity: 30%;
transition: opacity 0.6s;
}
.config-tooltip-text {
font-size: 0.6em;
font-weight: 600;
top: -7px;
opacity: 0%;
transition: opacity 0.6s;
}
.config:hover, .config:hover .config-tooltip-text {
opacity: 80%;
transition: opacity 0.6s;
}
.time-mode {
padding: 24px;
font-size: 1.5em;
}
.circle-container {
transform: rotate(-90deg);
}
.background-circle, .circle {
fill: none;
}
.background-circle {
stroke: rgba(255, 255, 255, .2);
stroke-width: 5;
}
.circle {
stroke: var(--timer-color);
stroke-width: 10;
stroke-dasharray: 597;
stroke-dashoffset: var(--dash-offset, 0);
transition: stroke-dashoffset 1s linear;
}
.dropdown-content {
display: flex;
flex-flow: column;
align-items: center;
margin-top: 10px;
}
.select-options > select {
background-color: var(--timer-color);
border: 1px solid rgba(255, 255, 255, .1);
border-radius: 5px;
cursor: pointer;
outline: none;
opacity: 60%;
transition: opacity 0.6s;
}
.select-options > select:hover {
opacity: 100%;
transition: opacity 0.6s;
}
.config-message {
font-size: 0.6em;
font-weight: 600;
display: none;
}
.config-message > span {
position: absolute;
transform: translate(-50%, -50%);
}
.config-message > span > a {
color: tomato;
}
password strength checker
<!DOCTYPE html>
<html lang="en">
<head>
<title>Password Strength</title>
<!-- FontAwesome Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<!-- Google Font -->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap" rel="stylesheet">
<!--Stylesheet-->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="wrapper">
<p>Enter the password</p>
<div class="container">
<input type="password" id="password" oninput="strengthChecker()">
<span id="toggle" onclick="toggle()">
<i class="fas fa-eye"></i>
</span>
<div id="strength-bar"></div>
</div>
<p id="msg"></p>
</div>
<!--Script-->
<script src="script.js"></script>
</body>
</html>
changed the color of the layout and background in the style CSS of the pomodoro timer
added additional HTML code in Pomodoro timer for time options and times of running
Made a book review website with the help of GitHub and edited the code to add changes
created password strength checker
created a quote generator and added new quotes and changes
Pomodoro timer project made edits
Project created by AH