h1 FreeCodeCamp
main(ng-app='PomodoroApp' ng-controller='MainCtrl')
  header
    .session
      .breakCtrl
        p break length
        button(ng-click='breakLengthChange(-1)').minus -
        span.time {{breakLength}}
        button(ng-click='breakLengthChange(1)').plus +
      .sessionCtrl
        p session length
        button(ng-click='sessionLengthChange(-1)').minus -
        span.time {{sessionLength}}
        button(ng-click='sessionLengthChange(1)').plus +
  section(ng-click='toggleTimer()')
    .timer
      p.title {{sessionName}}
      p {{timeLeft}}
      span.fill(ng-style="{'height':fillHeight, 'background':fillColor }")
      
View Compiled
@import "bourbon";

@import url(https://fonts.googleapis.com/css?family=Pacifico|Open+Sans:300);

// colors
$green: #99CC00;
$black: #333333;
$white: #fff;

// variables
$font: Open Sans, Arial;
  
* {
  margin: 0;
  font-family: $font;
}

html, body, main {
  height: 100%;
  overflow: hidden;
  background-color: $black;
}

h1 {
  display: block;
  background-color: $black;
  margin: 0 auto;
  color: white;
  text-align: center;
  font-family: 'Pacifico';
  font-size: 5em;
}

header {
  display: flex;
  justify-content: center;
  text-align: center;
  margin: 0 auto;
  color: $white;
  text-transform: uppercase;
  padding: 20px;
  
  .session {
    font-size: .8em;
    display: flex;
    .breakCtrl, .sessionCtrl {
      display: inline;
      padding-left: 30px;
      padding-right: 30px;
    }
    .minus, .plus {
      background-color: $black;
      color: $white;
      border: none;
      cursor: pointer;
      font-size: 2em;
      outline: none;
    }
    
    .time {
      font-size: 2.5em;
      padding-left: 10px;
      padding-right: 10px;
    }
  }
}

section {
  background-color: $black;
  height: 100%;
  color: $white;
  .title {
    text-align: center;
    line-height: 180px;
    font-size: .8em;
  }
  .timer {
    margin: 0 auto;
    text-align: center;
    width: 300px;
    height: 300px;
    font-size: 4em;
    border: 2px solid $green;
    border-radius: 50%;
    cursor: pointer;
    position: relative;
    z-index: 20;
    overflow: hidden;
    &:before {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      border-radius: 50%;
      z-index: 2;
      border: 4px solid $black;
    }
  }
  .fill {
    content: '';
    position: absolute;
    background: $green;
    bottom: 0;
    right: 0;
    left: 0;
    z-index: -1;
  }
}
View Compiled
var app = angular.module('PomodoroApp', []);
app.controller('MainCtrl', function($scope, $interval) {
  $scope.breakLength = 5;
  $scope.sessionLength = 25;
  $scope.timeLeft = $scope.sessionLength;
  $scope.fillHeight = '0%';
  $scope.sessionName = 'Session';
  $scope.currentTotal;
  
  var runTimer = false;
  var secs = 60 * $scope.timeLeft;
  $scope.originalTime = $scope.sessionLength;
  
  function secondsToHms(d) {
    d = Number(d);
    var h = Math.floor(d / 3600);
    var m = Math.floor(d % 3600 / 60);
    var s = Math.floor(d % 3600 % 60);
    return (
      (h > 0 ? h + ":" + (m < 10 ? "0" : "") : "") + m + ":" + (s < 10 ? "0" : "") + s
    ); 
  }
  
  // Change default session length
  $scope.sessionLengthChange = function(time) {
    if (!runTimer){
      if ($scope.sessionName === 'Session') {
        $scope.sessionLength += time;
        if ($scope.sessionLength < 1) {
          $scope.sessionLength = 1;
        }
        $scope.timeLeft = $scope.sessionLength;
        $scope.originalTime = $scope.sessionLength;
        secs = 60 * $scope.sessionLength;
      }
    }
  }
  
  // Change default break length
  $scope.breakLengthChange = function(time) {
    if (!runTimer){
      $scope.breakLength += time;
      if ($scope.breakLength < 1) {
        $scope.breakLength = 1;
      }
      if ($scope.sessionName === 'Break!') {
        $scope.timeLeft = $scope.breakLength;
        $scope.originalTime = $scope.breakLength;
        secs = 60 * $scope.breakLength;
      }
    }
  }
  
  $scope.toggleTimer = function() {
    if (!runTimer) {
      if ($scope.currentName === 'Sesson') {
        $scope.currentLength = $scope.sessionLength;
      } else {
        $scope.currentLength = $scope.breakLength;
      }
      
      updateTimer();
      runTimer = $interval(updateTimer, 1000);
    } else {
      $interval.cancel(runTimer);
      runTimer = false;
    }
  }
  
  function updateTimer() {
    secs -= 1;
    if (secs < 0) {
      // countdown is finished
      
      // Play audio
      var wav = 'http://www.oringz.com/oringz-uploads/sounds-917-communication-channel.mp3';
      var audio = new Audio(wav);
			audio.play();
      
      // toggle break and session
      $scope.fillColor = '#333333';
      if ($scope.sessionName === 'Break!') {
        $scope.sessionName = 'Session';
        $scope.currentLength = $scope.sessionLength;
        $scope.timeLeft = 60 * $scope.sessionLength;
        $scope.originalTime = $scope.sessionLength;
        secs = 60 * $scope.sessionLength;
      } else {
        $scope.sessionName = 'Break!';
        $scope.currentLength = $scope.breakLength;
        $scope.timeLeft = 60 * $scope.breakLength;
        $scope.originalTime = $scope.breakLength;
        secs = 60 * $scope.breakLength;
      }
    } else {
      if ($scope.sessionName === 'Break!') {
        $scope.fillColor = '#FF4444';
      } else {
        $scope.fillColor = '#99CC00';
      }
	    $scope.timeLeft = secondsToHms(secs);
      
      var denom = 60 * $scope.originalTime;
      var perc = Math.abs((secs / denom) * 100 - 100);
      $scope.fillHeight = perc + '%';
    }
  }
  
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js