Merge pull request 'feature/polish' (#2) from feature/polish into main

Reviewed-on: #2
This commit is contained in:
Manuel Friedli 2023-04-16 03:05:19 +02:00
commit de6b2e8946
6 changed files with 13903 additions and 9768 deletions

23582
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,20 +1,31 @@
{ {
"dependencies": { "dependencies": {
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0"
"react-scripts": "^5.0.0"
}, },
"main": "/index.js", "main": "/index.js",
"devDependencies": { "devDependencies": {
"react-scripts": "1.0.0" "react-scripts": "^5.0.1"
}, },
"name": "ljg0t8", "name": "a-maze-r",
"description": null, "description": "The A-Maze-Ing Generator!",
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test --env=jsdom", "test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject" "eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
} }
} }

View file

@ -4,18 +4,26 @@ import InputForm from "./InputForm";
export default function App() { export default function App() {
const [maze, setMaze] = useState({}); const [maze, setMaze] = useState({});
let title; const [showSolution, setShowSolution] = useState(false);
if (!!maze.grid) { const hasValidMaze = !!maze.width &&
title = <h1>The Maze ({maze.width}x{maze.height})</h1>; !!maze.height &&
} else { !!maze.id &&
title = <span/>; !!maze.grid;
}
return ( return (
<div> <>
<InputForm handleResult={setMaze}/> <InputForm handleResult={setMaze}/>
{title} {hasValidMaze &&
<Maze labyrinth={maze} <>
showSolution={true}/> <h1>The Maze ({maze.width}x{maze.height}, ID: {maze.id})</h1>
</div> <input type={"checkbox"}
onChange={(e) => {
setShowSolution(e.target.checked);
}}
id={"showSolution"}/><label htmlFor="showSolution">Show Solution</label>
<Maze labyrinth={maze}
showSolution={showSolution}/>
</>
}
</>
); );
} }

View file

@ -2,8 +2,8 @@ import React, {useState} from 'react';
import ValidatingInputNumberField from "./ValidatingInputNumberField"; import ValidatingInputNumberField from "./ValidatingInputNumberField";
export default function InputForm({handleResult}) { export default function InputForm({handleResult}) {
const [width, setWidth] = useState(2); const [width, setWidth] = useState(10);
const [height, setHeight] = useState(2); const [height, setHeight] = useState(10);
const [id, setId] = useState(null); const [id, setId] = useState(null);
const [status, setStatus] = useState("typing"); // "typing", "submitting" const [status, setStatus] = useState("typing"); // "typing", "submitting"
@ -20,7 +20,6 @@ export default function InputForm({handleResult}) {
.then(response => response.json()) .then(response => response.json())
.then(result => { .then(result => {
handleResult(result); handleResult(result);
// FIXME doesn't update the contents of the text input field.
setId(_ => result.id); setId(_ => result.id);
}) })
.catch(reason => { .catch(reason => {
@ -75,7 +74,7 @@ export default function InputForm({handleResult}) {
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<ValidatingInputNumberField id={"width"} <ValidatingInputNumberField id={"width"}
label={"Width"} label={"Width"}
defaultValue={width} value={width}
constraints={{ constraints={{
min: 2 min: 2
}} }}
@ -85,7 +84,7 @@ export default function InputForm({handleResult}) {
/><br/> /><br/>
<ValidatingInputNumberField id={"height"} <ValidatingInputNumberField id={"height"}
label={"Height"} label={"Height"}
defaultValue={height} value={height}
constraints={{ constraints={{
min: 2 min: 2
}} }}
@ -95,7 +94,7 @@ export default function InputForm({handleResult}) {
/><br/> /><br/>
<ValidatingInputNumberField id={"id"} <ValidatingInputNumberField id={"id"}
label={"ID (optional)"} label={"ID (optional)"}
defaultValue={id} value={id}
validatorFn={validateIdInput} validatorFn={validateIdInput}
disabled={status === "submitting"} disabled={status === "submitting"}
onChange={setId} onChange={setId}

View file

@ -3,7 +3,7 @@ import React, {useState} from 'react';
export default function ValidatingInputNumberField({ export default function ValidatingInputNumberField({
id, id,
label, label,
defaultValue = 0, value = 0,
constraints = {}, constraints = {},
validatorFn = (value) => { validatorFn = (value) => {
return {valid: true, value}; return {valid: true, value};
@ -13,7 +13,6 @@ export default function ValidatingInputNumberField({
} }
}) { }) {
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [value, setValue] = useState(defaultValue);
const handleValueChange = (e) => { const handleValueChange = (e) => {
const value = e.target.value; const value = e.target.value;
@ -22,18 +21,11 @@ export default function ValidatingInputNumberField({
setError(validation.message); setError(validation.message);
} else { } else {
setError(null); setError(null);
onChange(validation.value);
} }
setValue(validation.value); onChange(validation.value);
}; };
let errorComponent;
if (!!error) {
errorComponent = <span>{error}</span>;
} else {
errorComponent = <span/>;
}
return ( return (
<span> <>
<label htmlFor={id}>{label}: </label> <label htmlFor={id}>{label}: </label>
<input id={id} <input id={id}
type={"number"} type={"number"}
@ -43,7 +35,7 @@ export default function ValidatingInputNumberField({
max={constraints.max || null} max={constraints.max || null}
disabled={disabled} disabled={disabled}
/> />
{errorComponent} {!!error && <span>{error}</span>}
</span> </>
); );
} }

View file

@ -41,7 +41,12 @@ div.cell.bottom {
div.cell.left { div.cell.left {
border-left-color: #000; border-left-color: #000;
} }
div.cell.user {
background-color: hotpink;
}
div.cell.solution.user {
background-color: darkred;
}
input:invalid { input:invalid {
border-color: #f00; border-color: #f00;
} }