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 Center({ children }) {
return html`<div style=${{ width: "100vw", height: "100vh", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", overflowY: "auto" }}>${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) {
return html`
<${Center}>
asdf
</>
`;
}
return html`
<${Center}>
<h1>LSAT Timer</h1>
<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;
default:
return 0;
}
}
function reducer(state, action) {
switch (action.type) {
case "START":
return {
status: "on",
startTime: Date.now(),
startValue: getTime(state)
}
case "PAUSE":
return {
status: "off",
startValue: getTime(state)
}
case "RESET":
default:
return {
status: "off",
startValue: 0
}
}
}
function useConstantRerender(enabled = true) {
const [, forceRerender] = useReducer(v => !v, true);
useEffect(() => {
if (enabled) {
let killed = false;
const callback = () => {
forceRerender();
if (!killed) {
requestAnimationFrame(callback);
}
}
requestAnimationFrame(callback);
...