feature/polish #2
6 changed files with 13903 additions and 9768 deletions
23470
package-lock.json
generated
23470
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
28
src/App.js
28
src/App.js
|
@ -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 &&
|
||||||
|
<>
|
||||||
|
<h1>The Maze ({maze.width}x{maze.height}, ID: {maze.id})</h1>
|
||||||
|
<input type={"checkbox"}
|
||||||
|
onChange={(e) => {
|
||||||
|
setShowSolution(e.target.checked);
|
||||||
|
}}
|
||||||
|
id={"showSolution"}/><label htmlFor="showSolution">Show Solution</label>
|
||||||
<Maze labyrinth={maze}
|
<Maze labyrinth={maze}
|
||||||
showSolution={true}/>
|
showSolution={showSolution}/>
|
||||||
</div>
|
</>
|
||||||
|
}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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);
|
onChange(validation.value);
|
||||||
}
|
|
||||||
setValue(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>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue