Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 6, 2020 07:10 pm GMT

Build a Countdown Timer for Writing

Nanowrimo has started, but its easy to lose motivation. This countdown tool will put a figurative fire under our fingertips and hopefully inspire you to write a tiny draft to get started with that momentous writing project.

Finished project with timer and writing form

Getting Started

In my last article, we built a random plot generator to generate a random plot. But we didnt actually create a place for us to write about that scenario. In order to challenge ourselves, were going to create a timed challenge component which will allow us to get our initial ideas on the page.

Ill be using the Random Plot Generator component, so go ahead and read that article if youd like to follow along.

First, create a component that will render the form well use to write on.

This form will hold information in state, so well make it a class component.

import React from react class ChallengeForm extends React.Component{    state={}    render(){        return(                   <div>form goes here</div>        )    }}export default ChallengeForm 
Enter fullscreen mode Exit fullscreen mode

In order to keep the styling consistent, Ill use the styled components library. If you havent already, install the styled library.

npm install --save styled-components
Enter fullscreen mode Exit fullscreen mode

I know I want a form, so Ill build a Form with styled.

const Form = styled.form`    width: 100%;`
Enter fullscreen mode Exit fullscreen mode

Well also need to build a text field for us to actually write something.

Heres the styling I used. Note that styled components should be OUTSIDE of the class declaration.

const TextField = styled.textarea`    display: block;    border: 1px solid lightgrey;    border-radius: 2px;    width: 750px;    height: 500px;    padding: 8px;    margin: 8px;`
Enter fullscreen mode Exit fullscreen mode

Now, in the render method, render that form and textarea.

<Form>    <TextField/></Form>
Enter fullscreen mode Exit fullscreen mode

Of course, we still cant see the form. In our Random Plot Generator Component we need to import the Challenge Form component and render it.

Rendering the Form

Well work in our Random Plot Generator component for this next part. Refer to the article to get a feel for how its set up.

import ChallengeForm from './ChallengeForm'[]render(){    return(        []        <ChallengeForm/>        )    }
Enter fullscreen mode Exit fullscreen mode

Here is our page so far.

Shows the text area underneath the randomly generated sentence

Conditionally Render the Challenge

We can start writing ideas now, but there is a reason we called it the Challenge Form. To create the challenge aspect, we'll first need to conditionally render this form.

Well change the render in our Random Plot generator to conditionally render the form.

First, lets add the form flag to our state.

class RandomPlotGenerator extends React.Component{    constructor(props){        super(props)        this.state = {            []            form: false        }    }
Enter fullscreen mode Exit fullscreen mode

Then, in the render, write a ternary to render the form if it is true.

{this.state.form ? <ChallengeForm/>: null}
Enter fullscreen mode Exit fullscreen mode

In order to make it true, well need to write a button. Lets add the button to the sentence thats generated.

Create a new styled button.

const Button = styled.button`    margin: 8px;     padding; 8px;    &:hover {        color: blue;        cursor: pointer;      }`
Enter fullscreen mode Exit fullscreen mode

Then, render that button in the renderRandomPlot function.

    renderRandomPlot = () => {        return this.state.sentences.map((sentence, idx) =>              <Container key={idx}>                 {sentence}                 <Button onClick={this.onChallengeClick}>Challenge</Button>             </Container>        )    }
Enter fullscreen mode Exit fullscreen mode

Finally, change the state so that the form toggles between true and false.

  this.setState(prevState => ({            sentences: [...prevState.sentences, sentence],        }))        }
Enter fullscreen mode Exit fullscreen mode

Now we can show and hide the form at the click of a button.

Gif depicting the toggling of the form

Now that the form is conditionally rendered, lets make a timer to count the time we have to write.

Building Countdown Functionality

Well want to make a header to tell us how much time we have left. It would also be nice if, when we run out of time, the header blinks to let us know.

Styling the Countdown Headers

To do this, we need to import keyframes from the styled library.

Do this in the Challenge Form component.

import styled, { keyframes } from 'styled-components'
Enter fullscreen mode Exit fullscreen mode

Then, make a Title h3 styled component.

const Title = styled.h3`    padding: 8px; `
Enter fullscreen mode Exit fullscreen mode

Well also write a function for our component to blink.

function blink() {    return keyframes`      50% {        opacity: 0;      }    `;  }const TimesUp = styled.text`    color: red;    animation: ${blink} 1s linear infinite;`
Enter fullscreen mode Exit fullscreen mode

Both this styled component and the function are outside of our Challenge Form class.

Keep Track of Time in State

Before rendering the title, well add minutes and seconds to our state.

state = {    minutes: 5,     seconds: 0    }
Enter fullscreen mode Exit fullscreen mode

Well use Set Interval to count down the seconds.

I used Charlie Russos Building a Simple Countdown Timer With React to build out this functionality. Check it out!

In the Component Did Mount lifecycle method, use this code to create the timer.

    componentDidMount() {        this.myInterval = setInterval(() => {          const { seconds, minutes } = this.state              if (seconds > 0) {            this.setState(({ seconds }) => ({              seconds: seconds - 1            }))          }          if (seconds === 0) {            if (minutes === 0) {              clearInterval(this.myInterval)            } else {              this.setState(({ minutes }) => ({                minutes: minutes - 1,                seconds: 59              }))            }          }        }, 1000)      }    componentWillUnmount() {        clearInterval(this.myInterval)    }
Enter fullscreen mode Exit fullscreen mode

Conditionally Render the Countdown

Finally, render the countdown timer component. When the timer hits zero, our timer will blink to let us know times up.

   <Title>                       { minutes === 0 && seconds === 0                        ? <TimesUp>Time's Up!</TimesUp>                        : <h1>Time Remaining: {minutes}:{seconds < 10 ? `0${seconds}` : seconds}</h1>                    }</Title>
Enter fullscreen mode Exit fullscreen mode

And our countdown is complete!

When the countdown hits zero, the title flashes

We can be mean and make it impossible to update the form after that, but that probably isnt going to fly with many writers. Instead, lets add an analysis tool that tells us how many words and characters we typed in that time period.

Building an Analysis Button

Well create a simple button style for our analysis button.

const Button = styled.button`    padding: 8px;     margin: 8px;`
Enter fullscreen mode Exit fullscreen mode

Well also render that button underneath our form. Lets also attach an onClick event to it.

<Button onClick={this.analyze}>Analyze!</Button>
Enter fullscreen mode Exit fullscreen mode

Analyze will conditionally render a word and character count, so well need to add a flag to our state.

 analyze: false
Enter fullscreen mode Exit fullscreen mode

Upon clicking the analyze button, well set the state to true.

 analyze = () => {        this.setState({            analyze: true        })    }
Enter fullscreen mode Exit fullscreen mode

In order to count the words, well need to make them part of our state.

words: ''
Enter fullscreen mode Exit fullscreen mode

Our count words function is a simple regex expression that counts words and returns only alpha-numeric characters.

  countWords = () => {        let str = this.state.words        const matches = str.match(/[\w\d\\'-]+/gi);        return matches ? matches.length : 0;    }
Enter fullscreen mode Exit fullscreen mode

Finally, well tie the analyze function to the button and conditionally render the word and character count.

<Button onClick={this.analyze}>Analyze!</Button>                    {this.state.analyze ? <p>{`You wrote ${this.countWords()} words and ${this.state.words.length} characters.`}</p> : null}
Enter fullscreen mode Exit fullscreen mode

This will tell us how many words were written in our challenge.

Shows a word and character count

Summary

Great! We created a timer and text area to challenge ourselves to write a short story. We also created the ability to analyze the amount of words written in that time period.

There are many ways this challenge can be expanded upon. What about creating multiple plot ideas and multiple challenge forms? Or creating a backend for saving our writing projects so we can come back to them later.


Original Link: https://dev.to/kahawaiikailana/build-a-countdown-timer-for-writing-4d31

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To