Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <!--  
Made for the Free Code Camp course (https://www.freecodecamp.com/challenges/build-a-pomodoro-clock )

DESIGN & RESEARCH

The basic Free Code camp requirements were:-

1)can start a 25 minute pomodoro, and the timer will go off once 25 minutes has elapsed.
2)can reset the clock for my next pomodoro.
3)can customise the length of each pomodoro.

In addition to the basic Free Code camp requirements, 
professional versions also favoured:

* Dark theme capable
* Charts of achievements of past promodos
* Different screens for promodo and break-time


As this was a learning exercise I also wanted to include

Sass
*****

Variables: widths, heights, colors, z-index's
Google Color Palette, (https://github.com/danlevan/google-material-color) restricted fonts (https://mendel.me/development/using-google-fonts-css-stylesheet)



Event  bubbling
***************
Rather than lots of addEventListers; use the event object and allow the event flow carol built into the browser to ‘bubble’ up to get the element ID clicked

Mini-state machine used
The different states can be be represented in a global variable, then a switch case statement can control the state flow, like a mini-state machine.

d3
******
Using d3 to make an arc for the counter graphic is probably a bit of an overkill as we could use CSS. However if the app were to be used for real, I’d probably add charts to display records of promodos used. Also Im going to have to learn how to use d3.
So for those two reasons I decided to use d3 to make the arc for the countdown.


Input Range Slider
******************
Decided to use a slider to control the primed time rather than 
a button as used in the FCC version.
Input range (https://github.com/darlanrod/input-range-sass)


SVG's id's given and Xlink used
*******************************
By using xlink, we can put in-line svg’s at the top of the HTML, then link them into the appropriate place using <use id=“the_link_id”> 

data attributes on HTML
***********************
We can define an attribute data-state=“on” or off, which will toggle the CSS. This might work better than simply having a class applied

sound
*******
Just for fun, add a couple of sound files that play at the beginning and end of the primed. Decided to mix some free ones found on Freesound.org

-->
<body>
        <!--[if lt IE 8]>
            <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->



<!-- *******************                SVG ID Groups                 *******************
USe gruoup id's with style to display none and reference the svg in main body of HTML -->



<!--  theme button  -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">
<g id="themeButt_svg">
    <path d="M0 0v50h50V0zm23.4 14c1.7 0 2 .2.5 1-5 4-6.2 9.6-4.4 14.8 1 2.5 3 4.7 5.3 6-2.5.7-5.7-.4-7.7-2.3-5.4-5-4.3-15.3 2.4-18.5 1.2-.6 2.4-1 3.7-1z"/>
</g>
</svg>



<!--   whole donut graphic -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  style="display: none;">
<g id="wholeDonutGraphic_svg">
<path d="M171.6 230.5A102.3 102.3 0 0 1 40 170.8 102.3 102.3 0 0 1 99.4 39a102.3 102.3 0 0 1 131.8 59.7 102.3 102.3 0 0 1-59.6 131.8" fill="none" stroke-width="63.9"/>
</g>
</svg>


<!--  teaBreak Graphic  -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">
<g id="teaBreakGraphic_svg">
<path d="M44.4 16.6c-11 1.2-15.3-5-15 10.6C32 79.5 52.6 133 91 162.6c2.7 6.6.5 14.7 1 22v14.6h109v-35c13.3-10 25-23.3 34.2-38.5 18.5 14.5 47.6 7.2 56.8-17.3 11-27-1-62.2-24-74.8-9.3-1 4.5-17-10-16.8-71.2.3-142.4 0-213.5 0v-.2zm.7 14.8h203.5c-3.8 49.5-27 100-67 121.2-34.8 18.6-78.4 5-102.8-28.5C59 99 47.7 65.3 45 31.5zM262 49c19.4 9.3 27.2 44.5 9.4 60.3-7 7-24.2 9-27.3 0 9-18.8 15-39.3 18-60.3z" fill="#aaa"/>
</g>
</svg>



<!--  taskDone button  -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">

<g id="taskdone_svg">
    <path d="M2.2.6v1408.8h1407.3V.6zm992.6 294c65.4 47 118.5 114.3 174.8 172-453 417.8-402.7 438-581.4 619.3C358 855 480.4 961.6 266 794.3c234-272 147.7-221.2 280.6-102.4 28.2 24.6 44.3-7.7 66.3-24C731.2 547 850 426 968.3 304.7c6.8-6.7 16.6-11.6 26.3-10z"/>
</g>
</svg>





<!--  gotoTimer button  -->
<svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">
<g id="gotoTimer_svg">
    <path d="M-1.6-1h1412v1410.5H-1.6V-.8z" fill="none" stroke="#000" stroke-width=".3"/>
    <path d="M0 0v1411h1411V0H0zm705.7 164.5c245.8-6.5 468.4 191.3 510.8 430 44.3 213-48 449-233 566.5-173 116.3-416.7 108.2-581.8-18.8-202.5-147-274-440-168.5-666 80-183.6 270.2-315.6 472.5-311.7zm-5.8 65.7C482.4 229.5 288 407 256 619.8c-39.4 207.3 73.6 435 269.4 519 175.3 81.8 398.6 29 521.4-120 161-179 153-479-17-649.2-84.6-89.3-206.7-141.7-330-139.4zM651.2 305H744l20.7 385.2 238.6 255.4-70 68-303.4-263.3L651.2 305z"/>
</g>
</svg>



<!-- *******************   END of SVG  Groups *******************  -->


<div class="page blueRed_page">
 
  <div class="theme_wrapper">
   
    <div id="themeButt" class="themeSelect blueRed_themeButt">
           <svg viewbox="0 0 50 50">
           <use id="themeButt_svg_use" xlink:href="#themeButt_svg"></use>
           </svg>
    </div>
    
  </div>
<!--
  The three blocks represent three states and seperate screens 
   to be turned off or on depending on state condition -->
    <div id= "mainInfoBlockID" class="mainInfoBlock">
      
    <!--   READY STATE   -->  
       <div id="mainInfo_ready" data-state="on" class="blueRed_mainInfo_ready">
       
              <div id="promodoTimeLength" class="counterPromodo"></div>
              <p id="minutesLabel_readyState_id" data-mins_secs_note="on" class="minuteSecondNote_ready">mins</p> 
              <p id="secondsLabel_readyState_id" data-mins_secs_note="off" class="minuteSecondNote_ready">secs</p>
              <div id="counterGraphic_ready" class="counterGraphic blueRed_counterGraphic_ready">
              <svg viewbox="0 0 270 270"><use id="wholeDonutGraphic" xlink:href="#wholeDonutGraphic_svg"></use></svg>
              </div>
              <div id="pausedNote" class="counterPauseNote">PAUSED</div>
       </div>
       
    <!--   COUNTDOWN STATE   -->   
       <div id="mainInfo_countdown" data-state="off">
              
              <div id="promodoCountingDown" class="counterPromodo"></div>
              <p id="minutesLabel_countdown_id" class="minuteSecondNote_countdown">mins</p> 
              <p id="secondsLabel_countdown_id" class="minuteSecondNote_countdown">secs</p>
              <div id="counterGraphic_counting" class="counterGraphic"></div>
       
       </div>
       
     <!--   TEA-BREAK STATE   -->    
       <div id="mainInfo_teaBreak" data-state="off">
             
              <div id="promodoTeadBreakTime" class="teaBreakCounter"></div>
              <p id="minutesLabel_teaBreak_id" class="minuteSecondNote_teaBreak">mins</p> 
              <p id="secondsLabel_teaBreak_id" class="minuteSecondNote_teaBreak">secs</p>
              <div id="teaBreakGraphic" class="teaBreakGraphic">
             <svg viewbox="0 0 300 200"><use xlink:href="#teaBreakGraphic_svg"></use></svg>
              </div>
              <div id="teaBreakNote" class="teaBreakNote">Take a break!</div>
       
       </div>
    </div>
    
    <!-- The time slider is displayed in the 'ready' state only  -->
    <div class="timeSlider">
       <div id="timerAdjust" data-state="off">
            <input type="range" name="promodoInputName" id="promodoTimeInId" min="5" max="30" step="5" value="20"/>
       </div>
    </div>
    
    
    <!--  for both the countdown and tea-break state an 'option' button exists   -->
    <div class="option">
      
      <!--  skip the countdown and go to tea-break state  -->
       <button id="taskDoneButt" class="button" data-state="off">
           <svg id="taskDoneButt_svg" preserveaspectratio="xMidYMid" viewbox="0 0 1411.1111 1411.1111" fill-rule="evenodd" stroke-width="28.2" stroke-linejoin="round"><use id="taskDoneButt_svg_use" xlink:href="#taskdone_svg"></use></svg>
        </button>
        
      <!--  skip the tea-break and go to ready state   -->    
       <button id="skipBreakButt" class="button" data-state="off">
           <svg id="skipBreakButt_svg" viewbox="0 0 1411.1112 1411.1111" preserveaspectratio="xMidYMid" fill-rule="evenodd" stroke-width="28.2" stroke-linejoin="round"><use id="skipBreakButt_svg_use" xlink:href="#gotoTimer_svg"></use></svg> 
       </button>
    </div>
    
</div>




<!--  **** JS SCRIPTS   -->
        <script src="assets/js/jquery-2.1.4.min.js"></script>
        <script src="assets/js/d3.min.js"></script>
        <script src="assets/js/main.js"></script>

    </body>
            
          
!
            
              @font-face {
  font-family: 'Permanent Marker';
  font-style: normal;
  font-weight: 400;
  src: local("Permanent Marker"), local("PermanentMarker"), url(https://fonts.gstatic.com/s/permanentmarker/v5/9vYsg5VgPHKK8SXYbf3sMmVSxyvLCPm9firj_jMeQtQ.woff) format("woff");
  unicode-range: U+0030-0039;
  /* restrict this font to just 0 - 9 digits  */ }
@font-face {
  font-family: 'Changa One';
  font-style: normal;
  font-weight: 400;
  src: local("Changa One"), local("ChangaOne"), url(https://fonts.gstatic.com/s/changaone/v9/QmTOgNNWM9ly3K3B2X29HL3hpw3pgy2gAi-Ip7WPMi0.woff) format("woff");
  unicode-range: U+0020, U+0021, U+0041-7A; }
@font-face {
  font-family: 'Changa One';
  font-style: italic;
  font-weight: 400;
  src: local("Changa One Italic"), local("ChangaOne-Italic"), url(https://fonts.gstatic.com/s/changaone/v9/wJVQlUs1lAZel-WdTo2U96RDOzjiPcYnFooOUGCOsRk.woff) format("woff");
  unicode-range: U+0020, U+0021, U+0041-7A; }
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
html {
  font-family: sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%; }

body {
  margin: 0; }

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
  display: block; }

audio,
canvas,
progress,
video {
  display: inline-block;
  vertical-align: baseline; }

audio:not([controls]) {
  display: none;
  height: 0; }

[hidden],
template {
  display: none; }

a {
  background-color: transparent; }

a:active,
a:hover {
  outline: 0; }

abbr[title] {
  border-bottom: 1px dotted; }

b,
strong {
  font-weight: bold; }

dfn {
  font-style: italic; }

h1 {
  font-size: 2em;
  margin: 0.67em 0; }

mark {
  background: #ff0;
  color: #000; }

small {
  font-size: 80%; }

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

img {
  border: 0; }

svg:not(:root) {
  overflow: hidden; }

figure {
  margin: 1em 40px; }

hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  height: 0; }

pre {
  overflow: auto; }

code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em; }

button,
input,
optgroup,
select,
textarea {
  color: inherit;
  font: inherit;
  margin: 0; }

button {
  overflow: visible; }

button,
select {
  text-transform: none; }

button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  cursor: pointer; }

button[disabled],
html input[disabled] {
  cursor: default; }

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0; }

input {
  line-height: normal; }

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  padding: 0; }

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto; }

input[type="search"] {
  -webkit-appearance: textfield;
  -moz-box-sizing: content-box;
  -webkit-box-sizing: content-box;
  box-sizing: content-box; }

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none; }

fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em; }

legend {
  border: 0;
  padding: 0; }

textarea {
  overflow: auto; }

optgroup {
  font-weight: bold; }

table {
  border-collapse: collapse;
  border-spacing: 0; }

td,
th {
  padding: 0; }

::selection {
  background: #FFF498; }

::-moz-selection {
  background: #FFF498; }

img::selection {
  background: transparent; }

img::-moz-selection {
  background: transparent; }

body {
  -webkit-tap-highlight-color: #FFF498; }

/*****  VARIABLES */
body {
  background-color: #111;
  color: #fff;
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  flex-direction: row;
  -ms-flex-direction: row;
  -webkit-box-pack: distribute;
  -moz-box-pack: distribute;
  box-pack: distribute;
  -webkit-justify-content: space-around;
  -moz-justify-content: space-around;
  -ms-justify-content: space-around;
  -o-justify-content: space-around;
  justify-content: space-around;
  -ms-flex-pack: distribute;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%; }

a {
  color: #0074D9;
  text-decoration: none;
  outline: 0; }
  a:hover, a:focus {
    color: #40a6ff; }

.gigantic, .huge, .large, .bigger, .big,
h1, h2, h3, h4, h5, h6 {
  color: #222;
  font-weight: bold; }

.gigantic {
  font-size: 110px;
  line-height: 1.09;
  letter-spacing: -2px; }

.huge, h1 {
  font-size: 68px;
  line-height: 1.05;
  letter-spacing: -1px; }

.large, h2 {
  font-size: 42px;
  line-height: 1.14; }

.bigger, h3 {
  font-size: 26px;
  line-height: 1.38; }

.big, h4 {
  font-size: 22px;
  line-height: 1.38; }

.small, small {
  font-size: 10px;
  line-height: 1.2; }

p {
  margin: 0 0 20px 0; }

em {
  font-style: italic; }

strong {
  font-weight: bold; }

hr {
  border: solid #ddd;
  border-width: 1px 0 0;
  clear: both;
  margin: 10px 0 30px;
  height: 0; }

.button,
button,
input[type="submit"],
input[type="reset"],
input[type="button"] {
  display: inline-block;
  height: 50px;
  text-align: center;
  letter-spacing: 0.1rem;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  box-sizing: border-box;
  border: none; }
  .button:hover, .button:active, .button:focus,
  button:hover,
  button:active,
  button:focus,
  input[type="submit"]:hover,
  input[type="submit"]:active,
  input[type="submit"]:focus,
  input[type="reset"]:hover,
  input[type="reset"]:active,
  input[type="reset"]:focus,
  input[type="button"]:hover,
  input[type="button"]:active,
  input[type="button"]:focus {
    border-color: none;
    outline: 0; }

[type=range] {
  -webkit-appearance: none;
  margin: 23px 0;
  width: 100%;
  background-color: #1976D2;
  /*****  Background colour of slider, typically same as page colour  *****/ }
input[type=range]::-moz-focus-outer {
    border: 0;
    }
/*  http://stackoverflow.com/questions/18794026/remove-dotted-outline-from-range-input-element-in-firefox */
  [type=range]:focus {
    outline: none; }
  [type=range]::-webkit-slider-runnable-track {
    width: 100%;
    height: 15px;
    cursor: pointer;
    transition: all .2s ease;
    box-shadow: 0px 0px 0px #ffffff, 0 0 0px white;
    background: #ffffff;
    border: 0px solid #4CAF50;
    border-radius: 25px; }
  [type=range]::-webkit-slider-thumb {
    box-shadow: 4px 4px 10px #212121, 0 0 4px #2e2e2e;
    border: 0px solid #E91E63;
    height: 46px;
    width: 46px;
    border-radius: 23px;
    background: #F44336;
    cursor: pointer;
    -webkit-appearance: none;
    margin-top: -15.5px; }
  [type=range]:focus::-webkit-slider-runnable-track {
    background: #ffffff; }
  [type=range]::-moz-range-track {
    width: 100%;
    height: 15px;
    cursor: pointer;
    transition: all .2s ease;
    box-shadow: 0px 0px 0px #ffffff, 0 0 0px white;
    background: #ffffff;
    border: 0px solid #4CAF50;
    border-radius: 25px; }
  [type=range]::-moz-range-thumb {
    box-shadow: 4px 4px 10px #212121, 0 0 4px #2e2e2e;
    border: 0px solid #E91E63;
    height: 46px;
    width: 46px;
    border-radius: 23px;
    background: #F44336;
    cursor: pointer; }
  [type=range]::-ms-track {
    width: 100%;
    height: 15px;
    cursor: pointer;
    transition: all .2s ease;
    background: transparent;
    border-color: transparent;
    border-width: 46px 0;
    color: transparent; }
  [type=range]::-ms-fill-lower {
    box-shadow: 0px 0px 0px #ffffff, 0 0 0px white;
    background: #bfbfbf;
    border: 0px solid #4CAF50;
    border-radius: 50px; }
  [type=range]::-ms-fill-upper {
    box-shadow: 0px 0px 0px #ffffff, 0 0 0px white;
    background: #ffffff;
    border: 0px solid #4CAF50;
    border-radius: 50px; }
  [type=range]::-ms-thumb {
    box-shadow: 4px 4px 10px #212121, 0 0 4px #2e2e2e;
    border: 0px solid #E91E63;
    height: 46px;
    width: 46px;
    border-radius: 23px;
    background: #F44336;
    cursor: pointer; }
  [type=range]:focus::-ms-fill-lower {
    background: #ffffff; }
  [type=range]:focus::-ms-fill-upper {
    background: #ffffff; }

.page {
  text-align: center;
  height: 640px;
  width: 360px;
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -moz-box-orient: vertical;
  box-orient: vertical;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: column;
  -moz-flex-direction: column;
  flex-direction: column;
  -ms-flex-direction: column; }

.theme_wrapper {
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  flex-direction: row;
  -ms-flex-direction: row;
  -webkit-box-pack: start;
  -moz-box-pack: start;
  box-pack: start;
  -webkit-justify-content: flex-start;
  -moz-justify-content: flex-start;
  -ms-justify-content: flex-start;
  -o-justify-content: flex-start;
  justify-content: flex-start;
  -ms-flex-pack: start;
  -webkit-align-content: center;
  -moz-align-content: center;
  align-content: center;
  -ms-flex-line-pack: center;
  height: 100px;
  width: 360px; }
  .theme_wrapper .themeSelect {
    position: relative;
    top: 20%;
    left: 5%;
    z-index: 1000;
    height: 50px;
    width: 50px;
    background-color: none;
    fill: #9E9E9E; }
    .theme_wrapper .themeSelect svg {
      border-radius: 25px;
      height: 30px;
      width: 30px; }

.blueRed_page {
  background-color: #1976D2; }

.blueRed_mainInfo_ready,
.blueRed_mainInfo_countdown,
.blueRed_mainInfo_teaBreak {
  background-color: none; }

.blueRed_taskDoneButt,
.blueRed_skipBreakButt {
  height: 50px;
  width: 50px;
  background-color: #1976D2; }
  .blueRed_taskDoneButt svg,
  .blueRed_skipBreakButt svg {
    border-radius: 25px;
    height: 50px;
    width: 50px;
    background-color: #fff;
    fill: #F44336; }

.dark_page {
  background-color: #111; }

.dark_mainInfo_ready,
.dark_mainInfo_countdown,
.dark_mainInfo_teaBreak {
  background-color: none; }

.dark_taskDoneButt,
.dark_skipBreakButt {
  height: 50px;
  width: 50px;
  background-color: #111; }
  .dark_taskDoneButt svg,
  .dark_skipBreakButt svg {
    border-radius: 25px;
    height: 50px;
    width: 50px;
    background-color: #fff;
    fill: #9E9E9E; }

.mainInfoBlock {
  position: relative;
  top: 5%;
  left: 23%;
  z-index: 0;
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  flex-direction: row;
  -ms-flex-direction: row;
  -webkit-box-pack: distribute;
  -moz-box-pack: distribute;
  box-pack: distribute;
  -webkit-justify-content: space-around;
  -moz-justify-content: space-around;
  -ms-justify-content: space-around;
  -o-justify-content: space-around;
  justify-content: space-around;
  -ms-flex-pack: distribute;
  height: 200px;
  width: 200px; }

#mainInfo_ready[data-state="off"] {
  display: none; }

#mainInfo_countdown[data-state="off"] {
  display: none; }

#mainInfo_teaBreak[data-state="off"] {
  display: none; }

.minuteSecondNote_ready[data-mins_secs_note="on"],
.minuteSecondNote_countdown[data-mins_secs_note="on"],
.minuteSecondNote_teaBreak[data-mins_secs_note="on"] {
  position: relative;
  height: 21px;
  width: 77px;
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  flex-direction: row;
  -ms-flex-direction: row;
  -webkit-box-pack: centre;
  -moz-box-pack: centre;
  box-pack: centre;
  -webkit-justify-content: centre;
  -moz-justify-content: centre;
  -ms-justify-content: centre;
  -o-justify-content: centre;
  justify-content: centre;
  -ms-flex-pack: centre;
  font-family: "Changa One", "Arial";
  font-style: italic;
  top: 50px;
  left: 20px;
  z-index: 1000;
  font-size: 24px;
  font-weight: 300;
  letter-spacing: 0.5px;
  line-height: 1.2em; }

.minuteSecondNote_ready[data-mins_secs_note="off"],
.minuteSecondNote_countdown[data-mins_secs_note="off"],
.minuteSecondNote_teaBreak[data-mins_secs_note="off"] {
  display: none; }

.counterPromodo,
.teaBreakCounter {
  position: relative;
  height: 90px;
  width: 95px;
  display: -webkit-box;
  display: -moz-box;
  display: box;
  display: -webkit-flex;
  display: -moz-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  box-direction: normal;
  -webkit-flex-direction: row;
  -moz-flex-direction: row;
  flex-direction: row;
  -ms-flex-direction: row;
  -webkit-box-pack: distribute;
  -moz-box-pack: distribute;
  box-pack: distribute;
  -webkit-justify-content: space-around;
  -moz-justify-content: space-around;
  -ms-justify-content: space-around;
  -o-justify-content: space-around;
  justify-content: space-around;
  -ms-flex-pack: distribute;
  top: 55px;
  left: 0px;
  z-index: 1000;
  margin: 0;
  font-size: 80px;
  font-weight: 300;
  letter-spacing: 0px;
  line-height: 1.15em;
  font-family: "Permanent Marker", "Arial"; }

.counterGraphic {
  position: absolute;
  top: -28px;
  left: -36px;
  z-index: -500; }
  .counterGraphic svg {
    height: 270px;
    width: 270px; }

.dark_counterGraphic_ready > * {
  stroke: #9E9E9E; }

.blueRed_counterGraphic_ready > * {
  stroke: #F44336; }

.teaBreakGraphic {
  position: absolute;
  top: -28px;
  left: -36px;
  z-index: -500; }
  .teaBreakGraphic svg {
    height: 290px;
    width: 277px;
    fill: #9E9E9E; }

.teaBreakNote {
  position: absolute;
  z-index: 2000;
  top: 230px;
  left: 0px;
  font-size: 55px;
  font-weight: 400;
  line-height: 0.9em;
  font-style: italic;
  font-family: "Changa One", "Arial"; }

#pausedNote {
  position: absolute;
  top: 5.3em;
  right: 0.9em;
  height: 1em;
  width: 4em;
  top: 180px;
  left: 21px;
  z-index: 1000;
  font-family: "Changa One", "Arial";
  font-size: 2.5em;
  letter-spacing: 2px;
  line-height: 1.15em;
  font-weight: 300; }

.timeSlider {
  position: relative;
  top: 27%;
  left: 22%; }

#timerAdjust[data-state="on"] {
  height: 30px;
  width: 200px; }

#timerAdjust[data-state="off"] {
  display: none; }

.option {
  position: relative;
  top: 28%;
  left: 70%;
  height: 70px;
  width: 70px; }

#taskDoneButt[data-state="off"] {
  display: none; }

#skipBreakButt[data-state="off"] {
  display: none; }

#taskDoneButt[data-state="on"] {
  height: 60px;
  width: 60px; }

#skipBreakButt[data-state="on"] {
  height: 60px;
  width: 60px; }
/* width=50 height=50 works in Chrome and Firefox but not Safari. */
/* Box definition appears to be slightly different in Safari*/
            
          
!
            
              "use strict";

var state, theme, lengthOfPromodo, lengthOfteaBreak, minsLeft, secsLeft;

/****    Google Colors defined in Javascript   ******/
var googleRed500 = "#F44336";
var googleRed700 = "#D32F2F";
var myRed ="#ff2b33";
       
var googleGrey500 = "#9E9E9E";
var googleGrey700 = "#616161";
       
var dialColor = googleRed500;




/****************   DEFINE SOUND FILES    ******************/
/*
breakSound a mix of:
http://www.freesound.org/people/JasonElrod/sounds/85475/
http://www.freesound.org/people/stijn/sounds/22890/

*/
var breakTimeSound = new
Audio("https://dl.dropboxusercontent.com/s/hl3kqpxnx65chic/tea-kettle-whistle%20-%20stirr%20v2.mp3?dl=0");

/*
startSound a mix of:
https://www.freesound.org/people/AlienXXX/sounds/168560/
https://www.freesound.org/people/Spol/sounds/337671/
http://www.freesound.org/people/Puniho/sounds/165912/
*/
var startSound = new Audio("https://dl.dropboxusercontent.com/s/07f52tjp7vc7h91/funky-beat_with%20here_we_go.mp3?dl=0");

/********************************************************************************************/
/*************************                 DEFINE ID's          *****************************/
var promodiInput = document.querySelector("input");
var promodoTimeLength = document.getElementById("promodoTimeLength");
var promodoCountingDown = document.getElementById("promodoCountingDown");
var promodoTeadBreakTime = document.getElementById("promodoTeadBreakTime");
var minutesLabel_readyState_id = document.getElementById("minutesLabel_readyState_id");
var secondsLabel_readyState_id = document.getElementById("secondsLabel_readyState_id");
var minutesLabel_countdown_id = document.getElementById("minutesLabel_countdown_id");
var secondsLabel_countdown_id = document.getElementById("secondsLabel_countdown_id");
var minutesLabel_teaBreak_id = document.getElementById("minutesLabel_teaBreak_id");
var secondsLabel_teaBreak_id = document.getElementById("secondsLabel_teaBreak_id");
var mainInfo_countdown = document.getElementById("mainInfo_countdown");
var mainInfo_teaBreak = document.getElementById("mainInfo_teaBreak");
var timerAdjust = document.getElementById("timerAdjust");
var skipBreakButt = document.getElementById("skipBreakButt");





/********************************************************************************************/
/******************       CHANGE THEME  blueREd to dark and vice versa      *****************/
/*
Note how the 'dark' and 'blueRed' themes are labled so that there classes are easy to add and rtemove with a more 'dry' function i.e.  theTheme + "_classLabelHere"
*/
function change_theme(theTheme){
    
    $( ".page" ).addClass( theTheme + "_page" );
    $( "#themeButt" ).addClass( theTheme + "_themeButt" );
    $( "#mainInfo_ready" ).addClass( theTheme + "_mainInfo_ready" );
    $( "#mainInfo_countdown" ).addClass( theTheme + "_mainInfo_countdown" );
    $( "#mainInfo_teaBreak" ).addClass( theTheme + "_mainInfo_teaBreak" );
    $( "#taskDoneButt" ).addClass( theTheme + "_taskDoneButt" );
    $( "#skipBreakButt" ).addClass( theTheme + "_skipBreakButt" );
    $( "#counterGraphic_ready" ).addClass( theTheme + "_counterGraphic_ready" );
}



function remove_theme(theTheme){
    $( ".page" ).removeClass( theTheme + "_page" );
    $( "#themeButt" ).removeClass( theTheme + "_themeButt" );
    $( "#mainInfo_ready" ).removeClass( theTheme + "_mainInfo_ready" );
    $( "#mainInfo_countdown" ).removeClass( theTheme + "_mainInfo_countdown" );
    $( "#mainInfo_teaBreak" ).removeClass( theTheme + "_mainInfo_teaBreak" );
    $( "#taskDoneButt" ).removeClass( theTheme + "_taskDoneButt" );
    $( "#skipBreakButt" ).removeClass( theTheme + "_skipBreakButt" );
    $( "#counterGraphic_ready" ).removeClass( theTheme + "_counterGraphic_ready" );
}


function blueRed_theme(){
    change_theme("blueRed");
}



function remove_blueRed_theme(){
    remove_theme("blueRed");
}



function dark_theme(){
    change_theme("dark");
}



function remove_dark_theme(){
    remove_theme("dark");
}


/********************************************************************************************/
/******************      SET THE STATES ON SCREEN BY CONTROLING THE CSS     *****************/

function readyState(){
    mainInfo_ready.setAttribute('data-state', "on");
    mainInfo_countdown.setAttribute('data-state', "off");
    mainInfo_teaBreak.setAttribute('data-state', "off");
    timerAdjust.setAttribute('data-state', "on");
    taskDoneButt.setAttribute('data-state', "off");
    skipBreakButt.setAttribute('data-state', "off");
    secondsLabel_readyState_id.setAttribute('data-mins_secs_note', "off");
    minutesLabel_readyState_id.setAttribute('data-mins_secs_note', "on");
    lengthOfPromodo = promodiInput.value;
}


function countdownState(){
    mainInfo_ready.setAttribute('data-state', "off");
    mainInfo_countdown.setAttribute('data-state', "on");
    mainInfo_teaBreak.setAttribute('data-state', "off");
    timerAdjust.setAttribute('data-state', "off");
    taskDoneButt.setAttribute('data-state', "on");
    skipBreakButt.setAttribute('data-state', "off");
    secondsLabel_countdown_id.setAttribute('data-mins_secs_note', "off");
    minutesLabel_countdown_id.setAttribute('data-mins_secs_note', "on");
}
            


function teaBreakState(){
    mainInfo_ready.setAttribute('data-state', "off");
    mainInfo_countdown.setAttribute('data-state', "off");
    mainInfo_teaBreak.setAttribute('data-state', "on");
    timerAdjust.setAttribute('data-state', "off");
    taskDoneButt.setAttribute('data-state', "off");
    skipBreakButt.setAttribute('data-state', "on");
    secondsLabel_readyState_id.setAttribute('data-mins_secs_note', "off");
    minutesLabel_readyState_id.setAttribute('data-mins_secs_note', "on");
}



/********************************************************************/
/******************      COUNTER  DIAL  GRAPHIC     *****************/
/* 
see https://www.youtube.com/watch?v=oOu8y51VwMM 
and https://youtu.be/8jvoTV54nXw
*/

var r =135; // radius of dial

 
        //create svg canvas  and attach it to the counterGraphic_ready id     
        var canvas = d3.select("#counterGraphic_counting").append("svg")  
            .attr("width", 270)
            .attr("height", 270);
       
        /* re-centre the circle to be in the middle of the svg i.e. 270/2 = 135
            note how the ; isn't on the end as this is infact an chain of objects. 
            This is common in d3 */
        var group = canvas.append("g") 
            .attr("transform", "translate(135, 135)");

// the dial function creates the arc
    function theDial(dialAngle, theColor){

        
        var arc = d3.svg.arc()
        .innerRadius(70)   
        .outerRadius(r)
        .startAngle(0)
        .endAngle(dialAngle); 
    
    
    group.append("path")
        .attr("d", arc)    //  'd' is a path data in svg
        .attr("fill", theColor);   /// theColor depends on the theme
    
       }
       

/********************************************************************/
/***********************      SWITCH  STATE        *****************/
/*  Switch staet checks the sate flag and make sure the next state is called.
Its creates a mini-state machine flow
WE could have stored 'state' in a data attribute in the HTML,
but I decided to use a global variable to keep everything inside JS
*/

function switchState(){

    switch(state) {
    case "ready":
        console.log("the state is = " + state + "\n");
        readyState();
        console.log("**  end of ready state\n");
        break;
            
    case "countdown":
        console.log("the state is = " + state + "\n");
        countdownState();
        minuteCount();
        console.log("**  end of countdown state\n");
        break;
            
     case "teaBreak":
        console.log("the state is = " + state + "\n");    
        teaBreakState();
        teaBreakCountDown(lengthOfteaBreak -1);  // -1 second to round minute down slightly
        console.log("**  end of teaBreak state\n");
        break;       
            
    default:
        alert("ERROR in switchState");
    }
    
    
}


/********************************************************************/
/***********************     FLIP THE THEME        *****************/
function changeTheme(){
    
    if(theme=="blueRed"){
        remove_blueRed_theme();
        dark_theme();
        theme="dark";
    }
    else if(theme=="dark"){
        remove_dark_theme();
        blueRed_theme();
        theme="blueRed";
    }
    
}




/************************************************************************/
/****************    CALCULATE MINS & SECONDS LEFT     ******************/
/*
Both minutes and secods left are calculated twice for countdown and teaBreak
so they have been made into seperate functions
*/
    function minsLeft(seconds){
        return Math.floor(seconds/60);
    }
     
     
    function secsLeft(seconds){
        var wholeMin = Math.floor(seconds/60);
        return seconds - (wholeMin)*60;
    } 
     
     


/**********************************************************************/
/***************     COUNTDOWN & TEA BRAEK TIMERS      ****************/
/*
Idealy this and the teabreak counter should be merged to make the code
more 'dry' (don't repeate yourself).
I'd probaly do this on a future update but since there isn't too much code,
however for simplisity for now I've kept ech timer seperate.
*/

/***  Promodo Countdown *****/
    function countDown(secs){
        
        console.log("seconds count " + secs + "\n");
        // remember 'secs' is seconds remaining
        
        var angleOfTimeUsed = 6.283 - (secs/(lengthOfPromodo*9.55));
        // Calculate angles for time used so far, in radians
         
        console.log("angleOfTimeUsed = " + angleOfTimeUsed + "\n");
        
         theDial(angleOfTimeUsed, function(){ return((theme=="dark")?googleGrey500:googleRed500);});  /// draw dial svg
        
        if(secs < 60){
            secondsLabel_countdown_id.setAttribute('data-mins_secs_note', "on");
            minutesLabel_countdown_id.setAttribute('data-mins_secs_note', "off");
            promodoCountingDown.innerHTML = secsLeft(secs);
            }
        
        if(secs > 60){
            secondsLabel_countdown_id.setAttribute('data-mins_secs_note', "off");
            minutesLabel_countdown_id.setAttribute('data-mins_secs_note', "on");
            promodoCountingDown.innerHTML = minsLeft(secs)+1;  // +1 so rounded up to the nearest whole minute
            }
        
        
        if((secs < 1) || (state!="countdown")) {
		  clearTimeout(timer);
            
          breakTimeSound.play();
        
          d3.select("#counterGraphic_counting").selectAll("svg > g > *").remove(); // remove the paths drawn but nothing else
          state = "teaBreak";
            
          console.log("TIMER FINISHED");
          
          switchState(); /* this dosn't feel right but can't see another way */
       }
        
        
	   else if(secs >= 1){ 
           secs--;
           var timer = setTimeout('countDown('+ secs +')',1000);
           }

        
 }


/***  teaBreak Countdown *****/

    function teaBreakCountDown(secs){
        
        console.log("teaBreak seconds count " + secs + "\n");
        
        if((secs < 60)){
            secondsLabel_teaBreak_id.setAttribute('data-mins_secs_note', "on");
            minutesLabel_teaBreak_id.setAttribute('data-mins_secs_note', "off");
            promodoTeadBreakTime.innerHTML = secsLeft(secs);
            }
        
        if((secs > 60)){
            secondsLabel_teaBreak_id.setAttribute('data-mins_secs_note', "off");
            minutesLabel_teaBreak_id.setAttribute('data-mins_secs_note', "on");
            promodoTeadBreakTime.innerHTML = minsLeft(secs)+1;  // +1 so rounded up to the nearest whole minute
            }
        
        
        if((secs < 1) || (state!="teaBreak")) {
		  clearTimeout(timer);
          state = "ready";
          console.log("TIMER FINISHED");
          console.log("the state is = " + state + "\n");
            switchState(); /* this dosn't feel right but can't see another way */
       }
        
        
	   else if(secs >= 1){ 
           secs--;
           var timer = setTimeout('teaBreakCountDown('+ secs +')',1000); 
           }
  
 }



/****** Minute Count *************/
/*
Part of the countdown sate. 
The minute count finds the number of second required 
to countdown, then counts down
*/


    function minuteCount() {
        var secondsCount = (lengthOfPromodo * 60) - 1;  // take off one second
        startSound.play();
        countDown(secondsCount);
        console.log("minute count finished **\n");
   }



/**********************************************************************/
/***************     COUNTDOWN & TEA BREAK TIMERS      ****************/
/*
Rather than having lots od addEvenListers, the event bubbling handling technique was employed.
see page  260 and 331 of "JavaScript and JQuery: Interactive Front-End Web Development" 

http://javascriptbook.com/code/c07/event-delegation.html
http://javascriptbook.com/code/c07/js/event-delegation.js

and also
http://javascriptbook.com/code/c07/event-delegation.html
http://javascriptbook.com/code/c07/js/event-delegation.js
*/

function checkInput(theID){
    
    console.log("theLabel  " + theID + "\n");
    
    switch(theID) {
            
    /********** Ready state  **********/        
    case "mainInfo_ready":
        state="countdown";
        switchState();
        break; 
            
    case "promodoTimeLength":
        state="countdown";
        switchState();
        break;     
            
    case "pausedNote":
        state="countdown";
        switchState();
        break;   
            
            
    case "wholeDonutGraphic":
        state="countdown";
        switchState();
        break;   

            
    /********** countdown state  **********/
    case "taskDoneButt":
        state="teaBreak";
        switchState();
        break;  
            
    case "taskDoneButt_svg":
        state="teaBreak";
        switchState();
        break;  
            
    case "taskDoneButt_svg_use":
        state="teaBreak";
        switchState();
        break;  
                   
            
    /********** teaBreak state  **********/   
    case "skipBreakButt":
        state="ready";
        switchState();
        break;                        
    
            
    case "skipBreakButt_svg":
        state="ready";
        switchState();
        break;     
            
            
    case "skipBreakButt_svg_use":
        state="ready";
        switchState();
        break;     
            
    /********** teaBreak state  **********/                  
    case "themeButt":
         changeTheme();  
         break;
            
     case "themeButt_svg":
         changeTheme();  
         break;                 
            
     case "themeButt_svg_use":
         changeTheme();  
         break;           
            
            
    default:
        break;
    }
    
    
}




            
function initialize(){

    /* Initalise the 'theme' global variable 'blueRed' */
    
    theme="blueRed";
    change_theme(theme); // make sure taskDone and skipBreak buttons set properly
    
    //Initialise the data-state attribute to READY state
    state = "ready";
    switchState();
    
    lengthOfPromodo = 20;
    
    lengthOfteaBreak = 4 * 60;   /* tea break length in seconds to reduce functions usage */
    
    promodoTimeLength.innerHTML =  lengthOfPromodo;
    
}





/******
Reference for make range input work in js
http://stackoverflow.com/questions/18544890/onchange-event-on-input-type-range-is-not-triggering-in-firefox-while-dragging
*******/

var rangeListener = function() {
    window.requestAnimationFrame(function() {
        promodoTimeLength.innerHTML = promodiInput.value;
        lengthOfPromodo = promodiInput.value;
        });
    };

    promodiInput.addEventListener("mousedown", function() {
        rangeListener();
        promodiInput.addEventListener("mousemove", rangeListener);
    });
    
    promodiInput.addEventListener("mouseup", function() {
        promodiInput.removeEventListener("mousemove", rangeListener);
    });




/*********   EVENT ID BUBBLING   *****************/
/*
This function identifies click events and uses the 
event object 'e' built into the web browser.
The ID is checked using a switch case statement above
*/
$('.page').on('click',function(e) {
      
    console.log(e.target.id);
    
    checkInput(e.target.id);
    
    
    }
);


/*******  INITALISE when all code has downloaded  ********/

window.onload = function() {
    
  initialize();
};
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console