Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://kit.fontawesome.com/7f4c657074.js" crossorigin="anonymous"></script>
  <title>Pomodoro Timer</title>
</head>
<body>
 
  <div id="App"></div>
</body>
</html>
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
  

* {
  padding: 0;
  margin: 0;
  
}


/*
dark theme colors 
$primaryColor: #010203;
$shadow2: #040406;
$shadow1: #444446;
  $background: #040406;

  */

:root{
  --primaryColor: #ececec;
  --shadow1: rgba(255, 255, 255, 0.5);
  --shadow2: rgba(70, 70, 70, 0.12);
  --secondaryColor: blue;
  --activeColor: hotpink;
}




@mixin center-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin radius-top {
  border-radius: 15px 15px 0px 0px;
  --webkit-border-radius: 15px 15px 0px 0px;
  -moz-border-radius: 15px 15px 0px 0px;
}

@mixin raised {
  box-shadow: 
    -4px -4px 6px var(--shadow1), 
    4px 4px 6px var(--shadow2);
  border: 4px solid var(--primaryColor);
  outline: none;
}

@mixin sunk-in {
  box-shadow:
  
    inset -4px -4px 6px var(--shadow1), 
    inset 4px 4px 6px var(--shadow2);
}

@mixin sunk-with-edges {
  box-shadow:
   -4px -4px 6px var(--shadow1), 
    4px 4px 6px var(--shadow2),
    inset -4px -4px 6px var(--shadow1), 
    inset 4px 4px 6px var(--shadow2);
  
}

@mixin curved-edges {
  border-radius: 15px;
  --webkit-border-radius: 15px;
  -moz-border-radius: 15px;
}

@mixin circle {
  border-radius: 50%;
  --webkit-border-radius: 50%;
 -moz-border-radius: 50%;
}

@mixin control-btns {
   @include raised;
    @include circle;
    height: 4rem;
    width: 4rem;
    padding: 0;
    margin: 0;
    color: var(--secondaryColor);
    background-color: var(--primaryColor);
  
}



.wrapper {
  @include center-container;
 background: var(--primaryColor);
  height: 100vh;
  width: 100vw;
  min-height: 100vh;
  min-width: 100vw;
}

.timer {
  @include raised;
  @include curved-edges;
  height: 65vh;
  width: 45vw;
  background-color: var(--primaryColor);
 font-family: 'Roboto', sans-serif;
}

.adjustments {
 
  @include radius-top;
 position: relative;
  
  

  width: 100%;
  height: 35%;
  
  background-color: var(--primaryColor);

  .adjustment-btn {
    @include center-container;
    @include raised;
    @include curved-edges;
    border: 2px solid var(--primaryColor);
    height: 3rem;
    width: 3rem;
    margin: 5px 5px;
    color: var(--secondaryColor);
    background-color: var(--primaryColor);
  }

  .adjustment-btn:active {
    @include sunk-with-edges;
    color: var(--activeColor);
  }
  .session-title {
    @include center-container;
    @include sunk-in;
    @include curved-edges;
    border: none;
    position: absolute;
    top: 0;
    left: 1%;
    
    height: 50%;
    width: 48%;
    background-color: var(--primaryColor);

    .session-label {
      @include center-container;

      @include curved-edges;
   
      
      width: 95%;
      height: 2.5rem;
      padding: 0;
      margin: 0;
      color: var(--secondaryColor);
    }
  }

  .break-title {
    @include center-container;
    @include sunk-in;
    @include curved-edges;
    border: none;
    position: absolute;
    top: 0;
    left: 51%;
    height: 50%;
    width: 48%;
    background-color: var(--primaryColor);

    .break-label {
      @include center-container;
      width: 70%;
      height: 2.5rem;
      padding: 0;
      margin: 0;
      color: var(--secondaryColor);
    }
  }

  .session-adjuster {
    @include center-container;
    justify-content: space-evenly;

    position: absolute;
    top: 60%;
    left: 0;
    height: 35%;
    width: 50%;
    background-color: var(--primaryColor);

    .session-length {
      @include center-container;
      @include sunk-in;
      @include curved-edges;
      width: 3rem;
      height: 3rem;
      font-size: 1.5rem;

      padding: 0;
      margin: 0;
      color: var(--secondaryColor);
    }
  }

  .break-adjuster {
    @include center-container;
    justify-content: space-evenly;

    position: absolute;
    top: 60%;
    left: 50%;

    background-color: var(--primaryColor);
    height: 35%;
    width: 50%;

    .break-length {
      @include center-container;
      @include sunk-in;
      @include curved-edges;
      width: 3rem;
      height: 3rem;
      font-size: 1.5rem;
      padding: 0;
      margin: 0;
      color: var(--secondaryColor);
    }
  }
}

.status-container {
  @include center-container;
  @include raised;
  @include sunk-in;
  @include curved-edges;
  flex-wrap: wrap;
  margin: 2.5% 2.5%;
  padding: 0;
  border: 4px solid var(--primaryColor);
  height: 20%;
  width: 95%;
  background-color: var(--primaryColor);
  color: var(--secondaryColor);
 font-size: 2rem;
  .timer-label{
    margin: auto 10px;
  }
}

.countdown {
  @include center-container;
  @include sunk-in;
  @include curved-edges;
  border: 6px solid var(--primaryColor);
  height: 20%;
  width: 95%;
  margin: 0 2.5%;
  background-color: var(--primaryColor);
  color: var(--secondaryColor);
  font-size: 1.25rem;
}

.controls {
  @include center-container;
  justify-content: space-evenly;
  position: relative;
  bottom: 0;
  left: 0;
  height: 20%;
  width: 100%;
  margin: auto auto 5px auto;
  border-radius: 0px 0px 15px 15px;
  --webkit-border-radius: 0px 0px 15px 15px;
  -moz-border-radius: 0px 0px 15px 15px;

  .play {
   @include control-btns;
  
    
  }
  
  .pause {
    @include control-btns;
    @include sunk-with-edges;
    color: var(--activeColor);
  }
  
  .theme-btn {
   @include control-btns;
   
    
  }
  .theme-btn:active {
      @include sunk-with-edges;
    color: var(--activeColor);
  }

  .reset {
   @include control-btns;
  }

  .reset:active {
    @include sunk-with-edges;
    color: var(--activeColor);
  }
}


@media (max-height: 800px) {
  .timer {
    min-height: 95vh;
  }
}

@media (max-width: 800px){
  .timer {
    width: 80vw;
  }
}

@media (max-width: 550px ){
  .timer {
    width: 100vw;
    height: 100vh;
  }
}


              
            
!

JS

              
                import React from "https://cdn.skypack.dev/react@17.0.1";
import ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";


const quotes = [ '“Failure is not the opposite of success: it’s part of success.” -Arianna Huffington', 
    '“If your dreams don’t scare you, they are too small.” -Richard Branson',
    '“Believe you can and you’re halfway there.” -Theodore Roosevelt',
    '“Quality means doing it right when no one is looking.” -Henry Ford', 
   '“The difference between ordinary and extraordinary is that little extra.” -Jimmy Johnson', 
    '“It always seems impossible until it’s done.” -Nelson Mandela',
    '“Progress is impossible without change, and those who cannot change their minds cannot change anything.” -George Bernard Shaw', 
    '“What we fear of doing most is usually what we most need to do.” -Ralph Stripey Guy Emerson', 
    '“You are not your resume, you are your work.” -Seth Godin',
    '“Every accomplishment starts with the decision to try.” -John F Kennedy',
    '“Ability is what you’re capable of doing. Motivation determines what you do. Attitude determines how well you do it.” -Lou Holtz',
    '“If you have built castles in the air, your work need not be lost; that is where they should be. Now put the foundations under them.” -Henry David Thoraeu',
    '“People who wonder if the glass is half empty or half full miss the point. The glass is refillable.” -Unknown',
    '“Those who say it cannot be done should not interrupt those doing it.” -Chinese proverb',
    '“People often say that motivation doesn’t last. Well, neither does bathing; that’s why we recommend it daily.” -Zig Ziglar',
    '“If you think you are too small to make a difference, try sleeping with a mosquito.” -Dalai Lama',
    '“Never put off until tomorrow what you can do the day after tomorrow.” -Mark Twain', 
    '“The best revenge is massive success.” -Frank Sinatra',
        '“Be humble. Be hungry. And always be the hardest worker in the room.” -Dwayne “The Rock” Johnson' 
];




const App = () => {
  return (
  <div id="App">
      <div  id="wrapper" class="wrapper">
             <Timer />
      </div>
  </div>
  )
}





class Timer extends React.Component{
  constructor(props){
    super(props);
    
    
    this.state = {
      sessionLength: 25,
      breakLength: 5,
      timerStatus: "Click Play to Begin",
      countdown: "25:00",
      playPause: "fa-solid fa-play",
      startStopBtn: "play",
      theme: "fa-solid fa-moon",
      running: false,
      breakTime: false
      
    }
    
    
  }
 sessionAdd = this.sessionAdd.bind(this);
 sessionMinus = this.sessionMinus.bind(this);
  breakAdd = this.breakAdd.bind(this);
  breakMinus = this.breakMinus.bind(this); 
  themeSwitch = this.themeSwitch.bind(this);
  reset = this.reset.bind(this);
  playPauseToggle = this.playPauseToggle.bind(this);
  countdownStartStop = this.countdownStartStop.bind(this);
  checkForBreak = this.checkForBreak.bind(this);
 
  
  sessionAdd (){
   
    if(this.state.running === true){
      clearInterval(this.runningClock);
    
      this.playPauseToggle();
    }
    
    if(this.state.sessionLength === 60 ){
      this.setState({sessionLength: 1,countdown: "01:00"}) 
      return 
    }
    
    let newTime = this.state.sessionLength + 1;
    let stringTime = newTime.toString();
    
  
    
    this.setState ({
      sessionLength: newTime
      
    })
    
    
    if(stringTime.length == 1){
      this.setState({
        countdown: "0"+newTime+":"+"00"
      })
    }else{
      this.setState ({
        countdown: newTime+":"+"00"
      })
    }
  
  }
  
  
  sessionMinus (){
    if(this.state.running === true){
      clearInterval(this.runningClock);
   
      this.playPauseToggle();
    }
    
    if(this.state.sessionLength === 1 ){
      this.setState({sessionLength: 60, countdown:"60:00"}) 
      return; 
    }
    
  let newTime = this.state.sessionLength - 1;
    let stringTime = newTime.toString();
    
    
    this.setState ({
      sessionLength: newTime
    })
    
        if(stringTime.length == 1){
      this.setState({
        countdown: "0"+newTime+":"+"00"
      })
    }else{
      this.setState ({
        countdown: newTime+":"+"00"
      })
    }
    
    
  }
  
  
  
   breakAdd (){
     
    if(this.state.running === true && this.state.breakTime === true){
      
        clearInterval(this.runningClock);
      this.playPauseToggle();
    }
     
    if(this.state.breakLength === 60 ){
      this.setState({breakLength: 1}) 
      return 
    }
     
     let newTime = this.state.breakLength + 1;
    
    this.setState ({
      breakLength: newTime
    })
     
     
   
  }
  
  
  breakMinus (){
    
    if(this.state.running === true && this.state.breakTime === true){
      
        clearInterval(this.runningClock);
      this.playPauseToggle();
    }
    
    if(this.state.breakLength === 1 ){
      this.setState({breakLength: 60})
      return 
    }
    
    let newTime = this.state.breakLength - 1;
    
    this.setState ({
      breakLength: newTime
    })
    
 
   
  }
  
  
  
  themeSwitch(){
    
    let background = document.getElementById("wrapper");
    
    if(this.state.theme === "fa-solid fa-moon"){
      this.setState({
        theme: "fa-solid fa-sun"
      })
      
     document.documentElement.style.setProperty("--primaryColor","#010203");
     document.documentElement.style.setProperty("--secondaryColor","hotpink");
     document.documentElement.style.setProperty("--activeColor","blue");
     document.documentElement.style.setProperty("--shadow1","#444446");
     document.documentElement.style.setProperty("--shadow2","#040406");
      
     
      
      background.style.setProperty("background","#040406");
      
     }else if(this.state.theme === "fa-solid fa-sun"){
       
       this.setState({
         theme: "fa-solid fa-moon"
       })
       
       
       document.documentElement.style.setProperty("--primaryColor","#ececec");
     document.documentElement.style.setProperty("--secondaryColor","blue");
     document.documentElement.style.setProperty("--activeColor","hotpink");
     document.documentElement.style.setProperty("--shadow1","rgba(255, 255, 255, 0.5)");
     document.documentElement.style.setProperty("--shadow2","rgba(70, 70, 70, 0.12)");
      
     
      
      background.style.setProperty("background","#ececec");
     }
  }
  
  
  
  playPauseToggle(){
    
 let display = document.getElementById("status-container");
    
    if(this.state.playPause === "fa-solid fa-play"){
     
      display.style.setProperty("font-size","1rem");
      
      this.setState({
        playPause: "fa-solid fa-pause",
        startStopBtn: "pause",
        running: true,
        timerStatus: quotes[ Math.floor(Math.random()*quotes.length)]
       
      })
      
     this.countdownStartStop();
    }else {
      
      this.setState({
         playPause: "fa-solid fa-play",
        startStopBtn: "play",
        running: false,
        timerStatus: "Click Play to Begin"
      })
  display.style.setProperty("font-size","2rem");
    this.countdownStartStop();
   
    }
    
  
  }
  
  
  
  countdownStartStop() {
    
       let breakMin = this.state.breakLength.toString();
      
      breakMin = breakMin.length <= 1 ? "0"+breakMin+":"+"00" : breakMin+":"+"00";
    
    
     if(this.state.breakTime === true){
       
     let breakRemaining = this.state.countdown;
 
  
      
         
       if(this.state.countdown === "00:00" ){
   
       this.setState({
         countdown: breakMin
       })
     }else {
       this.setState({
         countdown: breakRemaining
       })
     }
      
    }
  
  
    

   
    
     let minutes = this.state.countdown.slice(0,2);
    let seconds = this.state.countdown.slice(3,5); 
    let workTime = this.state.sessionLength.toString();
    
    workTime = workTime.length <= 1 ? "0"+workTime+":"+"00" : workTime+":"+"00";
   
    if(this.state.running === false && this.state.breakTime === true && this.state.countdown !== "00:00"){
      minutes = breakMin.slice(0,2);
      seconds = breakMin.slice(3,5); 
    }
  
    clearInterval(this.runningClock);
  this.runningClock = setInterval(()=>{
    
    if(this.state.running === false ){
      clearInterval(this.runningClock);
      
      return;
    }
    
   
    if(this.state.running === true && this.state.countdown === "00:00"){
     let sound = document.getElementById('beep');
      sound.play();
      
      if(this.state.breakTime === true){
        this.setState({
          breakTime: false,
          countdown: workTime,
          timerStatus: quotes[ Math.floor(Math.random()*quotes.length)]
        })
        let display = document.getElementById("status-container");
        display.style.setProperty("font-size","1rem");
        clearInterval(this.runningClock);
        window.alert("Time To Focus");
        this.countdownStartStop();
      }else{
      clearInterval(this.runningClock);
     this.checkForBreak();
      }
      return;
      
    }
    
    
   
    
    
      if(seconds === "00"){
        seconds = "59";
        minutes = (parseInt(minutes)-1).toString();
        if(minutes.length === 1){minutes = "0"+minutes}
        this.setState({
          countdown: minutes+":"+seconds
        })
        
      }else{
        seconds = (parseInt(seconds)-1).toString();
        
        if(minutes.length === 1){minutes = "0"+minutes}
        if(seconds.length === 1){seconds = "0"+seconds}
        
        this.setState({
          countdown: minutes+":"+seconds
        })
      }
    
    
    },1000)
    
   
  }
  

  checkForBreak(){
    
   
   if (window.confirm(
   `    Times Up!!!
    Click OKAY to start your break
    -OR-
    Click Cancel for a few more minutes of work`)) {
     
      let display = document.getElementById("status-container");
     
     
    this.setState({
      breakTime: true,
      timerStatus: "RELAX"
    })
     display.style.setProperty("font-size","2rem");
     this.countdownStartStop();
   }else{
     this.setState({
       countdown: "02:00"
     })
     this.countdownStartStop();
   }
  
  
    
  }
  

  
 
  reset(){
    
    clearInterval(this.runningClock);
    
    this.setState ({
        sessionLength: 25,
      breakLength: 5,
      timerStatus: "Click Play to Begin",
      countdown: "25:00",
      startStopBtn: "play",
      playPause: "fa-solid fa-play",
      running: false
    })
     let sound = document.getElementById('beep');
    sound.currentTime = 0;
  }
  
  
  render(){
    
    return(
      <div id="timer" class="timer">
        <div id="adjustments" class="adjustments">
         
         <div id="session-title" class="session-title">
             <h4 id="session-label" class="session-label">Work Time</h4>
          </div>
           <div id="session-adjuster" class="session-adjuster" >
            <button id="session-increment" class="adjustment-btn" onClick={this.sessionAdd} ><i  class="fa-solid fa-circle-plus"  /></button>
                <p id="session-length" class="session-length">{this.state.sessionLength}</p>
            <button id="session-decrement" class="adjustment-btn" onClick={this.sessionMinus}><i  class="fa-solid fa-circle-minus" /></button>
            </div>
          <div id="break-title" class="break-title">
            <h4 id="break-label" class="break-label">Break Time</h4>
          </div>
           <div id="break-adjuster" class="break-adjuster" >
               <button id="break-increment" class="adjustment-btn" onClick={this.breakAdd}><i  class="fa-solid fa-circle-plus" /></button>
               <p id="break-length" class="break-length">{this.state.breakLength}</p>
               <button id="break-decrement" class="adjustment-btn" onClick={this.breakMinus}><i class="fa-solid fa-circle-minus" /></button>
          </div>
        </div>
         <div id="status-container" class="status-container" >
        <p id="timer-label" class="timer-label">{this.state.timerStatus}</p>
        </div>
        <div id="countdown" class="countdown">
          <h1 id="time-left" class="time-left">{this.state.countdown}</h1>
        </div>
        <div id="controls" class="controls">
          <button id="start_stop" class={this.state.startStopBtn} onClick={this.playPauseToggle}><i id="play-pause" class={this.state.playPause}></i></button>
           <button id="theme-btn" class="theme-btn" onClick={this.themeSwitch}><i id="theme-icon" class={this.state.theme}></i></button>
          <button id="reset" class="reset" onClick={this.reset}><i id="reset-icon" class="fa-solid fa-arrows-rotate" ></i></button>
        </div>
        <audio id="beep" src="https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav"/>
      </div>
     
    
    )
  }
  
  componentDidMount () {
    
  
}

}

ReactDOM.render(<App />,document.getElementById("App"));


              
            
!
999px

Console