forked from Minecraft/Stonks
Optimize Search results rendering, replace favicon
parent
6e74b0fe8d
commit
f6e6b90d8d
|
@ -4777,6 +4777,11 @@
|
||||||
"wrap-ansi": "^6.2.0"
|
"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": {
|
"co": {
|
||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||||
|
@ -5789,6 +5794,15 @@
|
||||||
"utila": "~0.4"
|
"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": {
|
"dom-serializer": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"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": {
|
"react-query": {
|
||||||
"version": "3.18.1",
|
"version": "3.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.18.1.tgz",
|
||||||
|
@ -13166,6 +13185,19 @@
|
||||||
"tslib": "^1.0.0"
|
"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": {
|
"read-pkg": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
"react-icons": "^4.2.0",
|
"react-icons": "^4.2.0",
|
||||||
"react-query": "^3.18.1",
|
"react-query": "^3.18.1",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3"
|
"react-scripts": "4.0.3",
|
||||||
|
"react-virtualized": "^9.22.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"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" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#FFFFFF" />
|
||||||
|
<!--
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="Web site created using create-react-app"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
|
-->
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
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.
|
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`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>Stonks!</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
import axios from "axios";
|
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 { Container } from "@chakra-ui/react";
|
||||||
|
|
||||||
import Search from "./Search";
|
import Search from "./Search";
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import React from "react";
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Center,
|
Center,
|
||||||
Flex,
|
|
||||||
Heading,
|
Heading,
|
||||||
Icon,
|
|
||||||
Image,
|
Image,
|
||||||
Table,
|
Table,
|
||||||
Thead,
|
Thead,
|
||||||
Tbody,
|
Tbody,
|
||||||
Tfoot,
|
|
||||||
Tr,
|
Tr,
|
||||||
Th,
|
Th,
|
||||||
Td,
|
Td,
|
||||||
TableCaption,
|
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const Player = ({ playerId, players }) => {
|
const Player = ({ playerId, players }) => {
|
||||||
|
@ -33,9 +27,7 @@ const Player = ({ playerId, players }) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const playerDict = useMemo(() => {
|
const playerName = players.data.find((x) => x.id === playerId).name;
|
||||||
return Object.assign({}, ...players.data.map((x) => ({ [x.id]: x.name })));
|
|
||||||
}, players);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -55,9 +47,9 @@ const Player = ({ playerId, players }) => {
|
||||||
src={`https://minotar.net/avatar/${playerId.replaceAll("-", "")}/48`}
|
src={`https://minotar.net/avatar/${playerId.replaceAll("-", "")}/48`}
|
||||||
mr="4"
|
mr="4"
|
||||||
/>
|
/>
|
||||||
{playerDict[playerId]}
|
{playerName}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Table variant="simple" size="sm" variant="striped">
|
<Table size="sm" variant="striped">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Statistic</Th>
|
<Th>Statistic</Th>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import Fuse from "fuse.js";
|
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 { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { AutoSizer, WindowScroller, List } from "react-virtualized";
|
||||||
|
|
||||||
const Search = ({ statistics, players }) => {
|
const Search = ({ statistics, players }) => {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
@ -39,54 +40,86 @@ const Search = ({ statistics, players }) => {
|
||||||
return searchEngine.search(`'"${searchTerm}"'`);
|
return searchEngine.search(`'"${searchTerm}"'`);
|
||||||
}, [searchEngine, 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 (
|
return (
|
||||||
<>
|
<WindowScroller>
|
||||||
<Heading as="h1" size="4xl" my="8">
|
{({ height, isScrolling, onChildScroll, scrollTop, registerChild }) => (
|
||||||
<Center>📈</Center>
|
<>
|
||||||
</Heading>
|
<Heading as="h1" size="4xl" my="8">
|
||||||
<Input
|
<Center>📈</Center>
|
||||||
placeholder="Find statistics or players"
|
</Heading>
|
||||||
size="lg"
|
<Input
|
||||||
variant="filled"
|
placeholder="Find statistics or players"
|
||||||
value={searchTerm}
|
size="lg"
|
||||||
onChange={(event) => setSearchTerm(event.target.value)}
|
variant="filled"
|
||||||
/>
|
value={searchTerm}
|
||||||
<Flex direction="column" align="stretch" my="4">
|
onChange={(event) => setSearchTerm(event.target.value)}
|
||||||
{searchResults.map((x, i) => {
|
/>
|
||||||
return (
|
<div ref={registerChild}>
|
||||||
<Link
|
<AutoSizer disableHeight>
|
||||||
to={
|
{({ width }) => (
|
||||||
x.item.type === "player"
|
<List
|
||||||
? `/${x.item.type}/${x.item.value.id}`
|
autoHeight
|
||||||
: `/${x.item.type}/${x.item.value.type}/${x.item.value.name}`
|
height={height}
|
||||||
}
|
isScrolling={isScrolling}
|
||||||
>
|
onScroll={onChildScroll}
|
||||||
<Button
|
scrollTop={scrollTop}
|
||||||
key={i}
|
rowCount={searchResults.length}
|
||||||
size="sm"
|
rowHeight={36}
|
||||||
leftIcon={
|
rowRenderer={renderRow}
|
||||||
x.item.type === "player" ? (
|
width={width}
|
||||||
<Icon as={FaUserCircle} />
|
/>
|
||||||
) : (
|
)}
|
||||||
<Icon
|
</AutoSizer>
|
||||||
as={FaArrowAltCircleRight}
|
</div>
|
||||||
transform="rotate(-45deg)"
|
</>
|
||||||
/>
|
)}
|
||||||
)
|
</WindowScroller>
|
||||||
}
|
|
||||||
variant="ghost"
|
|
||||||
my="0.5"
|
|
||||||
display="block"
|
|
||||||
textAlign="left"
|
|
||||||
width="100%"
|
|
||||||
>
|
|
||||||
{x.item.searchTerm}
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Center,
|
Center,
|
||||||
Flex,
|
|
||||||
Heading,
|
Heading,
|
||||||
Icon,
|
|
||||||
Input,
|
|
||||||
Table,
|
Table,
|
||||||
Thead,
|
Thead,
|
||||||
Tbody,
|
Tbody,
|
||||||
Tfoot,
|
|
||||||
Tr,
|
Tr,
|
||||||
Th,
|
Th,
|
||||||
Td,
|
Td,
|
||||||
TableCaption,
|
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { FaUserCircle, FaArrowAltCircleRight } from "react-icons/fa";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const Statistic = ({ type, name, players }) => {
|
const Statistic = ({ type, name, players }) => {
|
||||||
|
@ -34,7 +27,7 @@ const Statistic = ({ type, name, players }) => {
|
||||||
|
|
||||||
const playerDict = useMemo(() => {
|
const playerDict = useMemo(() => {
|
||||||
return Object.assign({}, ...players.data.map((x) => ({ [x.id]: x.name })));
|
return Object.assign({}, ...players.data.map((x) => ({ [x.id]: x.name })));
|
||||||
}, players);
|
}, [players]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -49,7 +42,7 @@ const Statistic = ({ type, name, players }) => {
|
||||||
<Heading as="h1" size="xl" mb="8">
|
<Heading as="h1" size="xl" mb="8">
|
||||||
{type} {name}
|
{type} {name}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Table variant="simple" size="sm" variant="striped">
|
<Table size="sm" variant="striped">
|
||||||
<Thead>
|
<Thead>
|
||||||
<Tr>
|
<Tr>
|
||||||
<Th>Player</Th>
|
<Th>Player</Th>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from "react-query";
|
||||||
import App from "./App.js";
|
import App from "./App.js";
|
||||||
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
import "react-virtualized/styles.css";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue