diff --git a/public/assets/banners/home.webp b/public/assets/banners/home.webp new file mode 100644 index 000000000..21676c530 Binary files /dev/null and b/public/assets/banners/home.webp differ diff --git a/src/app/page.tsx b/src/app/page.tsx index 27a76797a..42defbfa3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,12 +1,60 @@ 'use client'; -import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; -import { Flex, Heading, Text, TextField } from '@radix-ui/themes'; +import { CaretRightIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons'; +import { + Button, + Card, + Flex, + Heading, + Spinner, + Text, + TextField, +} from '@radix-ui/themes'; +import { go } from 'fuzzysort'; +import { debounce } from 'lodash'; +import { useRef, useState } from 'react'; +import { Link } from '../components/Link'; import { NAVBAR_HEIGHT } from '../components/Navbar'; import PageWrapper from '../components/PageWrapper'; +import searchPlayersAcrossRegions, { + AccountListWithServer, +} from '../core/blitz/searchPlayersAcrossRegions'; +import { + TankDefinition, + tankDefinitions, + tankNames, +} from '../core/blitzkit/tankDefinitions'; +import { tankIcon } from '../core/blitzkit/tankIcon'; import { theme } from '../stitches.config'; export default function Page() { + const [showSearch, setShowSearch] = useState(false); + const [searching, setSearching] = useState(false); + const [searchResults, setSearchResults] = useState(); + const search = useRef(null); + + const performSearch = debounce(async () => { + if (!search.current) return; + + const sanitized = search.current.value.trim(); + const awaitedTankDefinitions = await tankDefinitions; + const awaitedTankNames = await tankNames; + const tanks = go(sanitized, awaitedTankNames, { + keys: ['combined'], + limit: 9, + }); + const players = await searchPlayersAcrossRegions(sanitized, 9); + + setSearchResults({ + tanks: tanks.map((tank) => awaitedTankDefinitions[tank.obj.id]), + players, + }); + setSearching(false); + }, 500); + return ( <>
@@ -58,18 +107,134 @@ export default function Page() { - - - - - + { + if (!search.current) return; + + const sanitized = search.current.value.trim(); + + if (sanitized.length > 0) { + setShowSearch(true); + setSearching(true); + performSearch(); + } else { + setShowSearch(false); + } + }} + onFocus={() => { + if (!search.current) return; + + const sanitized = search.current.value.trim(); + + setShowSearch(sanitized.length > 0); + }} + > + + + + + + {showSearch && ( + + {searching && ( + + + + )} + + {!searching && searchResults && ( + <> + + + + + Tankopedia + + + + + + {searchResults.tanks.map((tank) => ( + + + + + + ))} + + + + + Players + + + {searchResults.players.map((player) => ( + + {player.nickname} + + ))} + + + + + )} + + )} +
diff --git a/src/components/Link.tsx b/src/components/Link.tsx new file mode 100644 index 000000000..d5f619855 --- /dev/null +++ b/src/components/Link.tsx @@ -0,0 +1,28 @@ +import { + Link as RadixLink, + LinkProps as RadixLinkProps, +} from '@radix-ui/themes'; +import NextLink from 'next/link'; + +interface LinkProps extends RadixLinkProps { + href: string; +} + +export function Link({ href, children, target, onClick, ...props }: LinkProps) { + return ( + event.preventDefault()} + {...props} + > + + {children} + + + ); +} diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index d1a645395..c12750900 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -114,6 +114,7 @@ export default function Navbar() { return (