Optimize Search results rendering, replace favicon

main
Kevin Belisle 2021-07-08 23:10:04 -04:00
parent 6e74b0fe8d
commit f6e6b90d8d
9 changed files with 128 additions and 74 deletions

32
spa/package-lock.json generated
View File

@ -4777,6 +4777,11 @@
"wrap-ansi": "^6.2.0"
}
},
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@ -5789,6 +5794,15 @@
"utila": "~0.4"
}
},
"dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
@ -13008,6 +13022,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-query": {
"version": "3.18.1",
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.18.1.tgz",
@ -13166,6 +13185,19 @@
"tslib": "^1.0.0"
}
},
"react-virtualized": {
"version": "9.22.3",
"resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz",
"integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==",
"requires": {
"@babel/runtime": "^7.7.2",
"clsx": "^1.0.4",
"dom-helpers": "^5.1.3",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",

View File

@ -18,7 +18,8 @@
"react-icons": "^4.2.0",
"react-query": "^3.18.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3"
"react-scripts": "4.0.3",
"react-virtualized": "^9.22.3"
},
"scripts": {
"start": "react-scripts start",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -4,12 +4,14 @@
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="theme-color" content="#FFFFFF" />
<!--
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
-->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
@ -19,7 +21,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>Stonks!</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,7 +1,7 @@
import React from "react";
import { useQuery } from "react-query";
import axios from "axios";
import { BrowserRouter, Switch, Redirect, Route } from "react-router-dom";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import { Container } from "@chakra-ui/react";
import Search from "./Search";

View File

@ -1,23 +1,17 @@
import React, { useMemo, useState } from "react";
import React from "react";
import { useQuery } from "react-query";
import axios from "axios";
import {
Button,
Center,
Flex,
Heading,
Icon,
Image,
Table,
Thead,
Tbody,
Tfoot,
Tr,
Th,
Td,
TableCaption,
} from "@chakra-ui/react";
import { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
import { Link } from "react-router-dom";
const Player = ({ playerId, players }) => {
@ -33,9 +27,7 @@ const Player = ({ playerId, players }) => {
}
);
const playerDict = useMemo(() => {
return Object.assign({}, ...players.data.map((x) => ({ [x.id]: x.name })));
}, players);
const playerName = players.data.find((x) => x.id === playerId).name;
return (
<>
@ -55,9 +47,9 @@ const Player = ({ playerId, players }) => {
src={`https://minotar.net/avatar/${playerId.replaceAll("-", "")}/48`}
mr="4"
/>
{playerDict[playerId]}
{playerName}
</Heading>
<Table variant="simple" size="sm" variant="striped">
<Table size="sm" variant="striped">
<Thead>
<Tr>
<Th>Statistic</Th>

View File

@ -1,9 +1,10 @@
import React, { useMemo, useState } from "react";
import Fuse from "fuse.js";
import { Button, Center, Flex, Heading, Icon, Input } from "@chakra-ui/react";
import { Button, Center, Heading, Icon, Input } from "@chakra-ui/react";
import { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
import { Link } from "react-router-dom";
import { AutoSizer, WindowScroller, List } from "react-virtualized";
const Search = ({ statistics, players }) => {
const [searchTerm, setSearchTerm] = useState("");
@ -39,54 +40,86 @@ const Search = ({ statistics, players }) => {
return searchEngine.search(`'"${searchTerm}"'`);
}, [searchEngine, searchTerm]);
const renderRow = ({
index, // Index of row
isScrolling, // The List is currently being scrolled
isVisible, // This row is visible within the List (eg it is not an overscanned row)
key, // Unique key within array of rendered rows
parent, // Reference to the parent List (instance)
style, // Style object to be applied to row (to position it);
// This must be passed through to the rendered row element.
}) => {
const x = searchResults[index];
return (
<Link
key={
x.item.type === "player"
? `/${x.item.type}/${x.item.value.id}`
: `/${x.item.type}/${x.item.value.type}/${x.item.value.name}`
}
to={
x.item.type === "player"
? `/${x.item.type}/${x.item.value.id}`
: `/${x.item.type}/${x.item.value.type}/${x.item.value.name}`
}
style={style}
>
<Button
size="sm"
leftIcon={
x.item.type === "player" ? (
<Icon as={FaUserCircle} />
) : (
<Icon as={FaArrowAltCircleRight} transform="rotate(-45deg)" />
)
}
variant="ghost"
my="0.5"
display="block"
textAlign="left"
width="100%"
>
{x.item.searchTerm}
</Button>
</Link>
);
};
return (
<>
<Heading as="h1" size="4xl" my="8">
<Center>📈</Center>
</Heading>
<Input
placeholder="Find statistics or players"
size="lg"
variant="filled"
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
/>
<Flex direction="column" align="stretch" my="4">
{searchResults.map((x, i) => {
return (
<Link
to={
x.item.type === "player"
? `/${x.item.type}/${x.item.value.id}`
: `/${x.item.type}/${x.item.value.type}/${x.item.value.name}`
}
>
<Button
key={i}
size="sm"
leftIcon={
x.item.type === "player" ? (
<Icon as={FaUserCircle} />
) : (
<Icon
as={FaArrowAltCircleRight}
transform="rotate(-45deg)"
/>
)
}
variant="ghost"
my="0.5"
display="block"
textAlign="left"
width="100%"
>
{x.item.searchTerm}
</Button>
</Link>
);
})}
</Flex>
</>
<WindowScroller>
{({ height, isScrolling, onChildScroll, scrollTop, registerChild }) => (
<>
<Heading as="h1" size="4xl" my="8">
<Center>📈</Center>
</Heading>
<Input
placeholder="Find statistics or players"
size="lg"
variant="filled"
value={searchTerm}
onChange={(event) => setSearchTerm(event.target.value)}
/>
<div ref={registerChild}>
<AutoSizer disableHeight>
{({ width }) => (
<List
autoHeight
height={height}
isScrolling={isScrolling}
onScroll={onChildScroll}
scrollTop={scrollTop}
rowCount={searchResults.length}
rowHeight={36}
rowRenderer={renderRow}
width={width}
/>
)}
</AutoSizer>
</div>
</>
)}
</WindowScroller>
);
};

View File

@ -1,23 +1,16 @@
import React, { useMemo, useState } from "react";
import React, { useMemo } from "react";
import { useQuery } from "react-query";
import axios from "axios";
import {
Button,
Center,
Flex,
Heading,
Icon,
Input,
Table,
Thead,
Tbody,
Tfoot,
Tr,
Th,
Td,
TableCaption,
} from "@chakra-ui/react";
import { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
import { Link } from "react-router-dom";
const Statistic = ({ type, name, players }) => {
@ -34,7 +27,7 @@ const Statistic = ({ type, name, players }) => {
const playerDict = useMemo(() => {
return Object.assign({}, ...players.data.map((x) => ({ [x.id]: x.name })));
}, players);
}, [players]);
return (
<>
@ -49,7 +42,7 @@ const Statistic = ({ type, name, players }) => {
<Heading as="h1" size="xl" mb="8">
{type} {name}
</Heading>
<Table variant="simple" size="sm" variant="striped">
<Table size="sm" variant="striped">
<Thead>
<Tr>
<Th>Player</Th>

View File

@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from "react-query";
import App from "./App.js";
import "./index.css";
import "react-virtualized/styles.css";
const queryClient = new QueryClient();