JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

HTML

<!--
  Create timer that keeps you on track to do n questions in m minutes
  (default 23 questions in 35 minutes)
-->

CSS

* {
  box-sizing: border-box;
}

h1 {
  text-align: center;
}

label {
  display: block;
  margin-bottom: 16px;
}

label div {
  font-size: 20px;
  margin-bottom: 4px;
}

input[type="number"] {
  font-size: 24px;
  padding: 8px 16px;
  text-align: center;
  width: 100%;
}

button,
input[type="submit"] {
  font-size: 24px;
  padding: 8px 16px;
}

.mainButtonWrapper {
  text-align: center;
}

JavaScript

import { html, render, useState, useReducer, useEffect, useCallback } from "https://unpkg.com/htm/preact/standalone.module.js";

function App() {
	const [settings, setSettings] = useState(null);

	const { time, status, start, pause, reset } = useStopwatch();
  
  useEffect(() => {
  	if (settings === null) {
    	document.title = "LSAT Timer";
    } else {
      const durationPerQuestion = settings.totalTime / settings.questions;
    	const currentQuestion = 1 + Math.floor(time / durationPerQuestion);
      const done = time > settings.totalTime;
      
      if (done) {
        document.title = "Done! | LSAT Timer";
      } else {
        document.title = `Q ${currentQuestion} | LSAT Timer`
      }
    }
  }, [settings]);
  
  if (settings === null) {
  	const onSubmit = (event) => {
    	event.preventDefault();
      
      const data = new FormData(event.target);
      reset();
      setSettings({
      	totalTime: 60 * Number(data.get("totalTime")),
        questions: Number(data.get("questions"))
      });
    }
  
    return html`
    	<h1>LSAT Timer</h1>
      <form onSubmit=${onSubmit}>
        <label>
          <div>Number of questions:</div>
          <input type="number" name="questions" defaultValue=${23} min=${1} />
        </label>
        <label>
          <div>Total time (minutes):</div>
          <input type="number" name="totalTime" defaultValue=${35} step="any" min=${0} />
        </label>
        <div>
          <input type="submit" value="Confirm" />
        </div>
      </form>
    `;
  }
  
  const durationPerQuestion = settings.totalTime / settings.questions;
  
  const currentQuestion = 1 + Math.floor(time / durationPerQuestion);
	const timeSpentOnQuestion = (time % durationPerQuestion) / durationPerQuestion;

	const done = time > settings.totalTime;

	return html`
  	${done
    	? html`<h1>Done</h1>`
      : html`
        <h1>Question ${currentQuestion}</h1>
        <div
          style=${{
            position: "fixed",
            top:...