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)
-->

JavaScript

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

function AppWrapper({ children }) {
	return html`
    <div
      style=${{
        width: "100vw",
        height: "100vh",
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        overflowY: "auto"
      }}
    >
    	<h1>LSAT Timer</h1>
      ${children}
    </div>
  `;
}

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

	const { time, status, start, pause, reset } = useStopwatch();
  
  const safeReset = () => {
  	if (confirm("Are you sure you want to reset?")) {
    	reset();
    }
  }
  
  if (settings === null) {
  	const onSubmit = (event) => {
    	event.preventDefault();
      
      const data = new FormData(event.target);
      setSettings({
      	totalTime: 60 * Number(data.get("totalTime")),
        questions: Number(data.get("questions"))
      })
    }
  
    return html`
    	<${AppWrapper}>
        <form onSubmit=${onSubmit}>
          <label>
            <div>Number of questions:</div>
            <input type="number" name="questions" defaultValue=${23} />
          </label>
          <label>
            <div>Total time (minutes):</div>
            <input type="number" name="totalTime" defaultValue=${35} />
          </label>
          <div>
            <input type="submit" value="Confirm" />
          </div>
        </form>
      </>
    `;
  }

	return html`
  	<${AppWrapper}>
      <div>${time}</div>
      ${status === "off" && html`
      	<button onClick=${start}>Start</button>
        ${time > 0 && html`<button onClick=${safeReset}>Reset</button>`}
      `}
      ${status === "on" && html`
      	<button onClick=${pause}>Pause</button>
      `}
    </>
  `;
}

function getTime(state) {
	switch (state.status) {
    case "off":
    	return state.startValue;
    case "on":
    	return state.startValue + (Date.now() - state.startTime) / 1000;
   ...