M packages/moves/package.json => packages/moves/package.json +2 -0
@@ 5,6 5,7 @@
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
+ "@mui/icons-material": "^5.3.1",
"@mui/material": "^5.4.0",
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.2",
@@ 14,6 15,7 @@
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"fp-ts": "^2.11.8",
+ "fuse.js": "^6.5.3",
"markdown-it": "^12.3.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
A packages/moves/src/components/move.tsx => packages/moves/src/components/move.tsx +34 -0
@@ 0,0 1,34 @@
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import Typography from "@mui/material/Typography";
+import MarkdownIt from "markdown-it";
+import React from "react";
+
+const md = new MarkdownIt();
+
+export default function Move(props: { Name: string; Text: string }) {
+ const [hidden, setHidden] = React.useState(true);
+ const bodyText = md.render(props.Text);
+
+ return (
+ <Card>
+ <CardContent>
+ <Typography
+ variant="h6"
+ component="h1"
+ onClick={() => setHidden((x) => !x)}
+ sx={{ cursor: "pointer", width: "100%" }}
+ >
+ {props.Name}
+ </Typography>
+ {hidden ? (
+ <div />
+ ) : (
+ <Typography sx={{ maxWidth: 600 }} variant="body1">
+ <p dangerouslySetInnerHTML={{ __html: bodyText }}></p>
+ </Typography>
+ )}
+ </CardContent>
+ </Card>
+ );
+}
M packages/moves/src/moves.tsx => packages/moves/src/moves.tsx +35 -41
@@ 1,44 1,16 @@
-import React from "react";
+import Search from "@mui/icons-material/Search";
import Box from "@mui/material/Box";
-import Paper from "@mui/material/Paper";
import Chip from "@mui/material/Chip";
+import InputAdornment from "@mui/material/InputAdornment";
+import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
-import Card from "@mui/material/Card";
-import CardContent from "@mui/material/CardContent";
-import Typography from "@mui/material/Typography";
-import MarkdownIt from "markdown-it";
-import moves from "./moves.json";
+import TextField from "@mui/material/TextField";
import * as A from "fp-ts/Array";
import * as S from "fp-ts/string";
-
-const md = new MarkdownIt();
-
-function Move(props: { Name: string; Text: string }) {
- const [hidden, setHidden] = React.useState(true);
- const bodyText = md.render(props.Text);
-
- return (
- <Card>
- <CardContent>
- <Typography
- variant="h6"
- component="h1"
- onClick={() => setHidden((x) => !x)}
- sx={{ cursor: "pointer", width: "100%" }}
- >
- {props.Name}
- </Typography>
- {hidden ? (
- <div />
- ) : (
- <Typography sx={{ maxWidth: 600 }} variant="body1">
- <p dangerouslySetInnerHTML={{ __html: bodyText }}></p>
- </Typography>
- )}
- </CardContent>
- </Card>
- );
-}
+import Fuse from "fuse.js";
+import React from "react";
+import Move from "./components/move";
+import moves from "./moves.json";
/**
* TODO pull this stuff into a library.
@@ 69,13 41,37 @@ const MoveChip = ({
);
export default function Moves() {
+ const [searchTerm, setSearchTerm] = React.useState(null as null | string);
const [selectedCategories, setSelectedCategories] = React.useState(
[] as Array<string>
);
+ const selectedMoves = moves.Moves.filter((mv) =>
+ // display all moves when there are no categories selected
+ selectedCategories.length === 0
+ ? true
+ : selectedCategories.includes(mv.Category)
+ );
+
+ const fuse = new Fuse(selectedMoves, { keys: ["Name", "Text"] });
+
return (
<Box sx={{ maxWidth: 800 }}>
<Paper elevation={1}>
+ <TextField
+ sx={{ width: "100%" }}
+ value={searchTerm === null ? "" : searchTerm}
+ onChange={(e) =>
+ setSearchTerm(e.target.value === "" ? null : e.target.value)
+ }
+ InputProps={{
+ endAdornment: (
+ <InputAdornment position="end">
+ <Search />
+ </InputAdornment>
+ ),
+ }}
+ />
<Stack
spacing={1}
direction="row"
@@ 97,11 93,9 @@ export default function Moves() {
))}
</Stack>
<Stack sx={{ p: 1 }} spacing={0.5}>
- {moves.Moves.filter((mv) =>
- // display all moves when there are no categories selected
- selectedCategories.length === 0
- ? true
- : selectedCategories.includes(mv.Category)
+ {(searchTerm === null
+ ? selectedMoves
+ : fuse.search(searchTerm).map((res) => res.item)
).map((mv) => (
<Move key={mv.Name} {...mv} />
))}
M yarn.lock => yarn.lock +12 -0
@@ 1735,6 1735,13 @@
prop-types "^15.7.2"
react-is "^17.0.2"
+"@mui/icons-material@^5.3.1":
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.3.1.tgz#e0e0aecce5a86971dbaa46441d931a9c749a1c53"
+ integrity sha512-8zBWCaE8DHjIGZhGgMod92p6Rm38EhXrS+cZtaV0+jOTMeWh7z+mvswXzb/rVKc0ZYqw6mQYBcn2uEs2yclI9w==
+ dependencies:
+ "@babel/runtime" "^7.16.7"
+
"@mui/material@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.4.0.tgz#b54d9fbcad5c4036b95c53906f0fc9c16c980f6e"
@@ 7406,6 7413,11 @@ fuse.js@^3.6.1:
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c"
integrity sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==
+fuse.js@^6.5.3:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.5.3.tgz#7446c0acbc4ab0ab36fa602e97499bdb69452b93"
+ integrity sha512-sA5etGE7yD/pOqivZRBvUBd/NaL2sjAu6QuSaFoe1H2BrJSkH/T/UXAJ8CdXdw7DvY3Hs8CXKYkDWX7RiP5KOg==
+
gauge@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"