Pomodoro.clock( )

In this example below you will see how to do a Pomodoro.clock( ) with some HTML / CSS and Javascript

Pomodoro challenge from FreeCodeCamp and example of Pomodoro.js library from here : https://github.com/GeorgeGks/Pomodoro.js

Thumbnail
This awesome code was written by georgegkas, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright georgegkas ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Pomodoro.clock( )</title>
  <link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro' rel='stylesheet' type='text/css'>
    <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <div class="wrapper">
  <div class="mainPage">
    <div class="container">
      <header>
        <span style="font-size: 30px;">Pomodoro</span>.clock( )
        <div>
          <p class="author">A project by:</p>
          <p class="author">George G. Gkasdrogkas</p>
        </div>
      </header>
      <div class="description">
        The <a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank" id="wikipedia">Pomodoro Technique</a> is a time management method developed by Francesco Cirillo in the late 1980s. The technique uses a timer to break down work into
        intervals, traditionally 25 minutes in length, separated by short breaks.
      </div>
      <div class="Usage">
        <div class="Ud">Usage</div>
        <div class="des">
          <div class="colLeft">
            <img src="https://cdn0.iconfinder.com/data/icons/creative-business-and-development/512/paper_plane_freelance_planning_start_startup_up_business_launch_solution_creative_idea_flat_design_icon-128.png" height="100px" height="100px">
            <p>Start a new Pomodoro.</p>
          </div>
          <div class="colMiddle">
            <img src="http://www.iconarchive.com/download/i85558/graphicloads/100-flat/clock.ico" height="100px" height="100px">
            <p>Wait the task to finish.</p>
          </div>
          <div class="colRight">
            <img src="http://icons.iconarchive.com/icons/graphicloads/100-flat-2/256/favourite-heart-icon.png" height="100px" height="100px">
            <p>Repeat as many times as you like!</p>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="app">
    <div class="clock">
      <div class="time">
        <span class="digits" id="hours">00 </span>
        <span class="count" style="padding-left: 4px;">HOURS</span>
      </div>
      <div class="time">
        <span class="digits" id="minutes">00 </span>
        <span class="count" style="margin-left: -65px;">MINUTES</span>
      </div>
      <div class="time">
        <span class="digits" id="seconds">00</span>
        <span class="count" style="margin-left: -65px;">SECONDS</span>
      </div>
    </div>
    <div class="options">
      <div class="state">
        <span>Currently State</span>
        <div class="switch">
          <input id="toggle-state" class="switch-toggle switch-state" type="checkbox" autocomplete="off" onclick="return false;">
          <label for="toggle-state" data-on="Active" data-off="Inactive"></label>
        </div>
      </div>
      <div class="settings">
        <p style="font-family: 'Lato',sans-serif;">Start a new timer</p>
        <span id="custom" style="padding-right: 10px; color:rgba(0, 0, 0, 0.75);">Custom</span>
        <div class="switch">
          <input id="toggle-timer" class="switch-toggle switch-round" type="checkbox" checked="checked" autocomplete="off" onclick="changeBasicCustomState(this);">
          <label for="toggle-timer"></label>
        </div>
        <span id="basic" style="padding-left: 20px; color: rgb(39, 174, 96); /*rgb(39, 174, 96);*/">Basic</span>
      </div>
      <div class="menuBasic">
        <p id="head">Basic Pomodoro Clock</p>
        <div class="rules">
          <p>Work for
            <input id="Im" autocomplete="off" /> minutes.</p>
          <p>With
            <input id="Itb" autocomplete="off" /> minutes time break in the meantime.</p>
          <p>Do a long
            <input id="Iltb" autocomplete="off" /> minutes break after
            <input autocomplete="off" id="longrpt" /> repeating works complete.</p>
          <p>Repeat it for only
            <input autocomplete="off" id="lrpt" /> time.</p>
        </div>
      </div>
      <div class="startAction">
        <button onclick="MainButton(this);" id="actionsButton">Start</button>
      </div>
    </div>
  </div>
</div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/georgegkas/pomodoroclock-zqbgWY */
body {
  background-color: rgba(236, 240, 241, 1);
}

.mainPage {
  height: 100%;
  width: 40%;
  background-color: rgb(52, 160, 219);
  /*#47c5da;*/
  outline: #47c5da;
  position: fixed;
  overflow-y: auto;
  overflow-x: hidden;
}

.mainPage .container header {
  font-family: 'Lato', sans-serif;
  //border: 1px solid #000;
  color: #fff;
  font-size: 22px;
  padding: 50px 20px 50px 40px;
  letter-spacing: 2px;
}

.mainPage .container header p {
  margin: 0;
  font-family: 'Source Sans Pro', sans-serif;
  font-size: 15px;
}

.author {
  display: inline-block;
}

.mainPage .description {
  //border-left: 2px solid #fff;
  width: 300px;
  padding-left: 5px;
  margin-left: 35px;
  color: #fff;
  letter-spacing: 1px;
}

#wikipedia {
  text-decoration: none;
  font-weight: bold;
  color: #fff;
  outline: none;
}

#wikipedia:hover {
  color: rgba(0, 0, 0, 0.82);
}

.mainPage .Usage {
  //border: 1px solid #fff;
  min-height: 48%;
  max-width: 100%;
  width: 100%;
  position: absolute;
  padding: 5px 5px 5px 0px;
}

.mainPage .Usage .Ud {
  //border: 1px solid #fff;
  padding: 10px 20px 20px 35px;
  font-size: 22px;
  color: #fff;
  font-family: 'Source Sans Pro', sans-serif;
  font-weight: 600;
  letter-spacing: 1px;
}

.mainPage .Usage .des {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  color: #fff;
  font-family: 'Lato', sans-serif;
  letter-spacing: 2px;
  text-align: center;
}

.mainPage .Usage .des p {
  //border: 1px solid #fff;
  margin-left: 10px;
}

.mainPage .Usage .des img {
  border: 1px solid #fff;
  padding: 5px;
  background-color: rgba(255, 255, 255, 0.91);
  box-shadow: 5px 10px 5px rgba(38, 38, 38, 0.37);
}

.des .colLeft {
  // border-right: 1px solid #fff;
  min-height: 100px;
  width: calc(100% / 3);
  display: inline-block;
  padding-top: 10px;
}

.des .colMiddle {
  // border-right: 1px solid #fff;
  // border-left: 1px solid #fff;
  width: calc(100% / 3);
  display: inline-block;
  padding-top: 10px;
}

.des .colRight {
  // border-left: 1px solid #fff;
  width: calc(100% / 3);
  display: inline-block;
  padding-top: 10px;
}

.app {
  //background: url('../img/wallpaper.jpg') center center  no-repeat;
  //background-size: cover;
  //background-size: 130% 100%;
  outline: #47c5da;
  clear: both;
  min-height: 100%;
  //border: 1px solid #fff;
  right: 0;
  width: 60%;
  position: fixed;
}

.app .clock {
  //border: 1px solid #000;
  font: 50px/1.7 'Lato', sans-serif;
  text-align: center;
  min-height: 40%;
  height: auto;
  width: 100%;
  padding-top: 60px;
  background-color: #16A085;
  color: #fff;
  clear: both;
  overflow: hidden;
}

.app .clock p {
  margin-top: -30px;
  font-size: 20px;
  font-family: 'Source Sans Pro', sans-serif;
}

.digits {
  width: 100%;
  text-align: center;
}

.app .clock .time {
  // border: 3px solid #fff;
  width: 100px;
  display: inline-block;
  padding: 10px;
  height: 140px;
}

.app .clock .time .count {
  font-size: 16px;
  font-family: 'Source Sans Pro', sans-serif;
  position: absolute;
  margin-top: 80px;
  margin-left: -60px;
  letter-spacing: 2px;
}

.app .options {
  border-top: 1px solid rgba(0, 0, 0, 0.55);
  //border-left: 1px solid rgba(0, 0, 0, 0.55);
  height: 60%;
  position: absolute;
  width: 100%;
  overflow-y: auto;
  overflow-x: hidden;
}

.app .options .state {
  // border: 1px solid #000;
  width: 130px;
  padding-top: 10px;
  margin: 0 auto;
  text-align: center;
  font-family: 'Lato', sans-serif;
}

.app .options .state span {
  padding-left: 0px;
  font-size: 18px;
}

.app .options .state .switch {
  padding-top: 5px;
}

.app .options .settings {
  //border: 1px solid #000;
  padding-top: 10px;
  text-align: center;
}

.app .options .settings .switch {
  width: 50px;
  margin: -10px auto;
  display: inline-block;
}

.app .options .menuBasic {
  //border: 1px solid #000;
  margin-top: 10px;
  padding-top: 10px;
}

.app .options .menuBasic p {
  margin: 0;
  padding-top: 5px;
  padding-left: 10px;
}

.app .options .menuBasic #head {
  font-size: 20px;
  font-family: 'Lato', sans-serif;
  color: rgba(0, 0, 0, 0.87);
  font-weight: 700;
}

.app .options .menuBasic .rules {
  padding-left: 10px;
  padding-top: 10px;
}

.app .options .menuBasic .rules p {
  padding-top: 2px;
}

.app .options .menuBasic .rules input {
  width: 50px;
  background: 0;
  border: 0;
  border-bottom: 1px solid #000;
  text-align: center;
}

@media screen and (min-width: 770px) {
  .mainPage .Usage {
    margin-left: -10px;
  }
  .mainPage .Usage .Ud {
    padding-left: 35px;
  }
}

@media screen and (max-width: 768px) {
  .mainPage {
    height: 600px;
    padding-bottom: 10px;
    width: 100%;
    overflow: hidden;
    clear: both;
    position: relative;
  }
  .mainPage .container header {
    text-align: center;
    padding: 50px 15px 50px 35px;
  }
  .mainPage .Usage .Ud {
    text-align: center;
    padding: 10px 0px 20px 0px;
    //border: 1px solid #fff;
  }
  .mainPage .description {
    text-align: center;
    padding: 0;
    max-width: 400px;
    margin: 0 auto;
    border: none;
  }
  .mainPage .Usage .des p {
    max-width: 100%;
  }
  .des .colLeft {
    border: 0;
  }
  .des .colMiddle {
    border: 0;
  }
  .des .colRight {
    border: 0;
  }
  .app {
    position: relative;
    margin: 0 auto;
    width: 100%;
  }
  .app .options {
    border-left: none;
    position: relative;
  }
  .app .options .menuBasic #head {
    text-align: center;
  }
  .startAction {
    padding-bottom: 10px !important;
  }
}

.switch-toggle {
  position: absolute;
  margin-left: -9999px;
  visibility: hidden;
}

.switch-toggle + label {
  display: block;
  position: relative;
  cursor: pointer;
  outline: none;
  user-select: none;
}

.switch-state + label {
  padding: 2px;
  width: 120px;
  height: 40px;
  margin-left: 5px;
}

.switch-state + label:before,
.switch-state + label:after {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  color: #fff;
  font-size: 20px;
  text-align: center;
  line-height: 40px;
}

.switch-state + label:before {
  background-color: rgba(38, 37, 37, 0.9);
  content: attr(data-off);
  transition: transform 0.5s;
  backface-visibility: hidden;
}

.switch-state + label:after {
  background-color: #27ae60;
  content: attr(data-on);
  transition: transform 0.5s;
  transform: rotateY(180deg);
  backface-visibility: hidden;
}

.switch-state:checked + label:before {
  transform: rotateY(180deg);
}

.switch-state:checked + label:after {
  transform: rotateY(0);
}


/**/

.switch-round + label {
  padding: 2px;
  width: 60px;
  height: 30px;
  background-color: #dddddd;
  border-radius: 60px;
  transition: background 0.4s;
}

.switch-round + label:before,
.switch-round + label:after {
  display: block;
  position: absolute;
  content: '';
}

.switch-round + label:before {
  top: 2px;
  left: 2px;
  bottom: 2px;
  right: 2px;
  background-color: #fff;
  border-radius: 60px;
  transition: background 0.4s;
}

.switch-round + label:after {
  top: 4px;
  left: 4px;
  bottom: 4px;
  width: 25px;
  background-color: #dddddd;
  border-radius: 52px;
  transition: margin 0.4s, background 0.4s;
}

.switch-round:checked + label {
  background-color: #8ce196;
}

.switch-round:checked + label:after {
  margin-left: 30px;
  background-color: #8ce196;
}

.app .options .startAction {
  width: 250px;
  margin: 0 auto;
  padding-top: 20px;
  padding-bottom: 0;
}

button {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  outline: 0;
  background-color: #404142;
  border: 0;
  padding: 10px 15px;
  color: #53e3a6;
  border-radius: 3px;
  width: 250px;
  cursor: pointer;
  font-size: 18px;
  -webkit-transition-duration: 0.25s;
  transition-duration: 0.25s;
  outline: none;
  margin: 0 auto;
}

button:hover {
  color: rgb(155, 246, 217);
}

button:active {
  background-color: rgba(35, 34, 34, 0.7);
}

/*Downloaded from https://www.codeseek.co/georgegkas/pomodoroclock-zqbgWY */
// Use of Pomodoro.js library created by me.
// https://github.com/GeorgeGks/Pomodoro.js
var PomodoroClock = (function() {
  'use strict';
  'esversion: 6';

  // Where to output the clock values
  var hOutput = null;
  var mOutput = null;
  var sOutput = null;

  // constructor
  function PomodoroClock(Output) {
    hOutput = Output.hoursOutput;
    mOutput = Output.minutesOutput;
    sOutput = Output.secondsOutput;
  }

  var countdownWorkId = null;

  // Total number of work-break pairs to repeat
  var RepeatsToDo;

  // Number of current repeat
  var currRepeats;

  // Working time length
  var workingTime;

  // Long break time length
  var longBreakTime;

  // Short break time length
  var shortBreakTime;

  // Shows after how many repeats should 
  var repeatsUntilLongBreak;

  // Input:  seconds
  // Return: array of transformed seconds to [H,M,S]
  var beautifySeconds = (secs) => {
    var sec_num = parseInt(secs, 10);
    var hours = Math.floor(sec_num / 3600) % 24;
    var minutes = Math.floor(sec_num / 60) % 60;
    var seconds = sec_num % 60;
    return [hours, minutes, seconds]
      .map(v => v < 10 ? '0' + v : v);
  };

  // Purpose: A visual countdown clock.
  //          Decrease the time one second in
  //          each repeat and update the front end 
  //          with the new time. 
  //          Repeat until time goes to zero.
  var countdownWork = function(timeLenght) {
    var d = $.Deferred();
    var m = timeLenght;
    var doDecreaseTime = function() {
      m--;
      var strOutput = beautifySeconds(m);
      $(hOutput).text(strOutput[0]);
      $(mOutput).text(strOutput[1]);
      $(sOutput).text(strOutput[2]);
      if (m !== 0) {
        countdownWorkId = setTimeout(doDecreaseTime, 1000);
      } else {
        d.resolve();
      }
    };
    doDecreaseTime();
    return d.promise();
  };

  // Purpose: Checks if a parameter was added by the user
  // Return: true/false
  var isParam = (param, obj) => {
    if (obj.hasOwnProperty(param)) {
      if (obj[param].length !== 0) {
        return true;
      }
    }
    return false;
  };

  // Purpose: Checks which parameters was added
  //          by the user and update the appropriate 
  //          variables else it keeps the default values
  var setValues = function(obj) {
    if (obj) {
      if (isParam('workingTime', obj)) {
        workingTime = obj.workingTime * 60;
      } else {
        workingTime = 25 * 60;
      }
      if (isParam('shortBreakTime', obj)) {
        shortBreakTime = obj.shortBreakTime * 60;
      } else {
        shortBreakTime = 5 * 60;
      }
      if (isParam('repeats', obj)) {
        RepeatsToDo = obj.repeats;
      } else {
        RepeatsToDo = 1;
      }
      if (isParam('longBreakTime', obj)) {
        longBreakTime = obj.longBreakTime * 60;
      } else {
        longBreakTime = 15 * 60;
      }
      if (isParam('repeatsUntilLongBreak', obj)) {
        repeatsUntilLongBreak = obj.repeatsUntilLongBreak;
      } else {
        repeatsUntilLongBreak = 4;
      }
    } else {
      workingTime = 25 * 60;
      shortBreakTime = 5 * 60;
      RepeatsToDo = 1;
      longBreakTime = 15 * 60;
      repeatsUntilLongBreak = 4;
    }
    currRepeats = 0;
  };

  // Purpose: Main method that starts the clock
  PomodoroClock.prototype.start = function(clockOptions, callback) {
    setValues(clockOptions); // initialize the values of the clock
    var remainingToLongBreak = 0;

    // Purpose: Check if we need to do another
    //          one repeat or we have finished
    //          our clock so the callback() function
    //          is executed if set.
    var checkWorkState = function() {
      // Has the clock ended yet?
      if (currRepeats != RepeatsToDo) {
        work();
      } else {
        clearTimeout(countdownWorkId);
        typeof callback === "function" && callback();
      }
    };

    // Purpose: This function holds the work time
    //          as well as the break time that needs
    //          to be executed.
    //          It also checks how many times we have
    //          to repeat our process.
    var work = function() {
      currRepeats++;
      remainingToLongBreak++;
      // It's work time!
      countdownWork(workingTime).then(function() {
        if (remainingToLongBreak == repeatsUntilLongBreak) {
          remainingToLongBreak = 0;
          // It's long break time!
          countdownWork(longBreakTime).then(function() {
            checkWorkState();
          });
        } else {
          // It's short break time!
          countdownWork(shortBreakTime).then(function() {
            checkWorkState();
          });
        }
      });
    };

    work();
  };

  // Purpose: Main method that sets the clock to zero values
  //          reseting the clock states
  PomodoroClock.prototype.reset = function() {
    $(hOutput).text('00');
    $(mOutput).text('00');
    $(sOutput).text('00');
    clearTimeout(countdownWorkId);
  };

  return PomodoroClock;
})();

// Start of main js file

var isActive = false;
var Pclock = new PomodoroClock({
  'hoursOutput': '#hours',
  'minutesOutput': '#minutes',
  'secondsOutput': '#seconds'
});

function readOnlyInput(val) {
  document.getElementById("Im").readOnly = val;
  document.getElementById("Itb").readOnly = val;
  document.getElementById("Iltb").readOnly = val;
  document.getElementById("longrpt").readOnly = val;
  document.getElementById("longrpt").readOnly = val;
}

function changeBasicCustomState(slider) {
  if ($(slider).is(":checked")) {
    $('#basic').css({
      'color': 'rgb(39, 174, 96)'
    });
    $('#custom').css({
      'color': 'rgba(0, 0, 0, 0.75)'
    });
    $('#Im').val(25);
    $('#Itb').val(5);
    $('#Iltb').val(15);
    $('#longrpt').val(4);
    $('#lrpt').val(1);
    readOnlyInput(true);
  } else {
    $('#custom').css({
      'color': 'rgb(39, 174, 96)'
    });
    $('#basic').css({
      'color': 'rgba(0, 0, 0, 0.75)'
    });
    $('#Im').val('');
    $('#Itb').val('');
    $('#Iltb').val('');
    $('#longrpt').val('');
    $('#lrpt').val('');
    readOnlyInput(false);
  }
}

function MainButton(btn) {
  if (isActive) {
    Pclock.reset(); // Procedure already is running so we cancel it
    $("#toggle-timer").removeAttr("disabled");
    $("#toggle-state").prop("checked", false);
    $(btn).html('Start');
    isActive = false;
    if (!$('#toggle-timer').is(":checked")) {
      readOnlyInput(false);
    }
  } else {
    $("#toggle-timer").attr("disabled", true);
    $("#toggle-state").prop("checked", true);
    $(btn).html('Reset');
    isActive = true;
    readOnlyInput(true);

    if ($('#toggle-timer').is(":checked")) {
      // start clock with default values
      Pclock.start(function() { // callback on end
        $("#toggle-timer").removeAttr("disabled");
        $("#toggle-state").prop("checked", false);
        $(btn).html('Start');
        isActive = false;
      });
    } else {
      // start custom clock
      Pclock.start({
        'workingTime': $('#Im').val(),
        'shortBreakTime': $('#Itb').val(),
        'longBreakTime': $('#Iltb').val(),
        'repeats': $('#lrpt').val(),
        'repeatsUntilLongBreak': $('#longrpt').val()
      }, function() { // callback on end
        $("#toggle-timer").removeAttr("disabled");
        $("#toggle-state").prop("checked", false);
        $(btn).html('Start');
        isActive = false;
        readOnlyInput(false);
      });
    }
  }
}

$(document).ready(function() {
  $('#Im').val(25);
  $('#Itb').val(5);
  $('#Iltb').val(15);
  $('#longrpt').val(4);
  $('#lrpt').val(1);
  readOnlyInput(true);
});

Comments