An Interest In:
Web News this Week
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
- April 20, 2024
- April 19, 2024
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.
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
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
I know I want a form, so Ill build a Form with styled.
const Form = styled.form` width: 100%;`
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;`
Now, in the render method, render that form and textarea.
<Form> <TextField/></Form>
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/> ) }
Here is our page so far.
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 } }
Then, in the render, write a ternary to render the form if it is true.
{this.state.form ? <ChallengeForm/>: null}
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; }`
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> ) }
Finally, change the state so that the form toggles between true and false.
this.setState(prevState => ({ sentences: [...prevState.sentences, sentence], })) }
Now we can show and hide the form at the click of a button.
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'
Then, make a Title h3 styled component.
const Title = styled.h3` padding: 8px; `
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;`
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 }
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) }
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>
And our countdown is complete!
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;`
Well also render that button underneath our form. Lets also attach an onClick event to it.
<Button onClick={this.analyze}>Analyze!</Button>
Analyze will conditionally render a word and character count, so well need to add a flag to our state.
analyze: false
Upon clicking the analyze button, well set the state to true.
analyze = () => { this.setState({ analyze: true }) }
In order to count the words, well need to make them part of our state.
words: ''
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; }
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}
This will tell us how many words were written in our challenge.
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
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To