hello-wordl/src/App.tsx

112 lines
3.1 KiB
TypeScript
Raw Normal View History

2021-12-31 03:43:09 +02:00
import "./App.css";
2022-01-17 20:42:56 +02:00
import { maxGuesses, seed } from "./util";
2021-12-31 03:43:09 +02:00
import Game from "./Game";
2022-01-18 00:25:44 +02:00
import { useEffect, useState } from "react";
2022-01-17 20:42:56 +02:00
import { About } from "./About";
2022-01-01 04:04:48 +02:00
2022-01-18 00:25:44 +02:00
function useSetting<T>(
key: string,
initial: T
): [T, (value: T | ((t: T) => T)) => void] {
2022-01-17 20:42:56 +02:00
const [current, setCurrent] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initial;
} catch (e) {
return initial;
}
});
const setSetting = (value: T | ((t: T) => T)) => {
try {
const v = value instanceof Function ? value(current) : value;
setCurrent(v);
window.localStorage.setItem(key, JSON.stringify(v));
} catch (e) {}
};
return [current, setSetting];
2022-01-17 14:34:32 +02:00
}
function App() {
2022-01-17 14:34:32 +02:00
const [page, setPage] = useState<"game" | "about" | "settings">("game");
2022-01-17 20:42:56 +02:00
const prefersDark =
2022-01-18 00:25:44 +02:00
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
2022-01-17 20:42:56 +02:00
const [dark, setDark] = useSetting<boolean>("dark", prefersDark);
const [hard, setHard] = useSetting<boolean>("hard", false);
2022-01-18 00:25:44 +02:00
useEffect(() => {
document.body.className = dark ? "dark" : "";
}, [dark]);
2022-01-01 04:04:48 +02:00
return (
2022-01-03 17:17:36 +02:00
<div className="App-container">
2022-01-18 00:25:44 +02:00
<h1>
<span style={hard ? { color: "#e66" } : {}}>hell</span>o wordl
</h1>
2022-01-03 17:17:36 +02:00
<div style={{ position: "absolute", right: 5, top: 5 }}>
2022-01-17 14:34:32 +02:00
{page !== "game" ? (
<a href="#" onClick={() => setPage("game")}>
Close
</a>
) : (
<>
<a href="#" onClick={() => setPage("about")}>
Help
</a>
{" • "}
<a href="#" onClick={() => setPage("settings")}>
Settings
</a>
</>
)}
2022-01-01 04:04:48 +02:00
</div>
2022-01-17 14:34:32 +02:00
<div
style={{
position: "absolute",
left: 5,
top: 5,
visibility: page === "game" ? "visible" : "hidden",
}}
>
2022-01-08 01:01:19 +02:00
<a
href="#"
onClick={() =>
(document.location = seed
2022-01-08 02:31:19 +02:00
? "?"
2022-01-18 00:25:44 +02:00
: "?seed=" +
new Date().toISOString().replace(/-/g, "").slice(0, 8))
2022-01-08 01:01:19 +02:00
}
>
{seed ? "Random" : "Today's"}
</a>
</div>
2022-01-17 14:34:32 +02:00
{page === "about" && <About />}
2022-01-17 20:42:56 +02:00
{page === "settings" && (
<div className="Settings">
<div className="Settings-setting">
<input
id="dark-setting"
type="checkbox"
checked={dark}
onChange={() => setDark((x: boolean) => !x)}
/>
<label htmlFor="dark-setting">Dark theme</label>
</div>
<div className="Settings-setting">
<input
id="hard-setting"
type="checkbox"
checked={hard}
onChange={() => setHard((x: boolean) => !x)}
/>
2022-01-18 00:25:44 +02:00
<label htmlFor="hard-setting">Hard mode (must use all clues)</label>
2022-01-17 20:42:56 +02:00
</div>
</div>
)}
<Game maxGuesses={maxGuesses} hidden={page !== "game"} hard={hard} />
2022-01-03 17:17:36 +02:00
</div>
2022-01-01 04:04:48 +02:00
);
}
export default App;