forked from Minecraft/Stonks
Optimize Search results rendering, replace favicon
parent
6e74b0fe8d
commit
f6e6b90d8d
|
@ -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",
|
||||
|
|
|
@ -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 |
|
@ -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>
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue