mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: jump to position
This commit is contained in:
1 parent
466f68701f
commit
ca00f18a6a
1 file changed
+147
-101
+147
-101
@@ -83,6 +83,7 @@ export default function Page() {
|
|||||||
page * rowsPerPage,
|
page * rowsPerPage,
|
||||||
page * rowsPerPage + rowsPerPage,
|
page * rowsPerPage + rowsPerPage,
|
||||||
);
|
);
|
||||||
|
const positionInput = useRef<HTMLInputElement>(null);
|
||||||
const previousPage = () => setPage((page) => Math.max(page - 1, 0));
|
const previousPage = () => setPage((page) => Math.max(page - 1, 0));
|
||||||
const nextPage = () =>
|
const nextPage = () =>
|
||||||
setPage((page) =>
|
setPage((page) =>
|
||||||
@@ -152,6 +153,19 @@ export default function Page() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const handleJumpToPosition = () => {
|
||||||
|
const rawPosition = positionInput.current!.valueAsNumber - 1;
|
||||||
|
const position = Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(rawPosition, (players.data?.length ?? 0) - 1),
|
||||||
|
);
|
||||||
|
setPage(Math.floor(position / rowsPerPage));
|
||||||
|
|
||||||
|
if (players.data) {
|
||||||
|
setHighlightedPlayerId(players.data[position].id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const [jumpToPositionOpen, setJumpToPositionOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPage(0);
|
setPage(0);
|
||||||
@@ -246,98 +260,11 @@ export default function Page() {
|
|||||||
</Select.Root>
|
</Select.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex justify="between" wrap="wrap" gap="2">
|
<Flex justify="center" wrap="wrap" gap="2">
|
||||||
<Flex gap="2">
|
<Button variant="soft" onClick={previousPage}>
|
||||||
<Popover.Root>
|
<CaretLeftIcon />
|
||||||
<Popover.Trigger>
|
</Button>
|
||||||
<Button variant="soft">Jump to league</Button>
|
<PageTurner />
|
||||||
</Popover.Trigger>
|
|
||||||
|
|
||||||
<Popover.Content>
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Select.Root
|
|
||||||
value={`${jumpToLeague}`}
|
|
||||||
onValueChange={(value) => setJumpToLeague(parseInt(value))}
|
|
||||||
>
|
|
||||||
<Select.Trigger />
|
|
||||||
|
|
||||||
<Select.Content>
|
|
||||||
{ratingsInfo?.detail === undefined &&
|
|
||||||
ratingsInfo?.leagues.map(({ index, title }) => (
|
|
||||||
<Select.Item key={index} value={`${index}`}>
|
|
||||||
{title}
|
|
||||||
</Select.Item>
|
|
||||||
))}
|
|
||||||
</Select.Content>
|
|
||||||
</Select.Root>
|
|
||||||
|
|
||||||
<Flex gap="2">
|
|
||||||
<Popover.Close>
|
|
||||||
<Button color="red">Cancel</Button>
|
|
||||||
</Popover.Close>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Popover.Content>
|
|
||||||
</Popover.Root>
|
|
||||||
|
|
||||||
<Dialog.Root>
|
|
||||||
<Dialog.Trigger>
|
|
||||||
<Button variant="soft">Jump to player</Button>
|
|
||||||
</Dialog.Trigger>
|
|
||||||
|
|
||||||
<Dialog.Content>
|
|
||||||
<Flex gap="4" direction="column">
|
|
||||||
<TextField.Root>
|
|
||||||
<TextField.Slot>
|
|
||||||
<MagnifyingGlassIcon height="16" width="16" />
|
|
||||||
</TextField.Slot>
|
|
||||||
|
|
||||||
<TextField.Input
|
|
||||||
onChange={handleSearchPlayerChange}
|
|
||||||
placeholder="Search for player..."
|
|
||||||
/>
|
|
||||||
</TextField.Root>
|
|
||||||
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
{searchResults?.map((player) => (
|
|
||||||
<Dialog.Close>
|
|
||||||
<Button
|
|
||||||
key={player.account_id}
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => {
|
|
||||||
const playerIndex = players.data?.findIndex(
|
|
||||||
(playerData) => playerData.id === player.account_id,
|
|
||||||
);
|
|
||||||
const playerPage = Math.floor(
|
|
||||||
playerIndex! / rowsPerPage,
|
|
||||||
);
|
|
||||||
|
|
||||||
setPage(playerPage);
|
|
||||||
setHighlightedPlayerId(player.account_id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{player.nickname}
|
|
||||||
</Button>
|
|
||||||
</Dialog.Close>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{searchResults?.length === 0 && (
|
|
||||||
<Button disabled variant="ghost">
|
|
||||||
No players found in leaderboard
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex gap="2">
|
|
||||||
<Dialog.Close>
|
|
||||||
<Button color="red">Cancel</Button>
|
|
||||||
</Dialog.Close>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Dialog.Content>
|
|
||||||
</Dialog.Root>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Select.Root
|
<Select.Root
|
||||||
onValueChange={(value) => setRowsPerPage(parseInt(value))}
|
onValueChange={(value) => setRowsPerPage(parseInt(value))}
|
||||||
defaultValue={`${rowsPerPage}`}
|
defaultValue={`${rowsPerPage}`}
|
||||||
@@ -352,16 +279,135 @@ export default function Page() {
|
|||||||
))}
|
))}
|
||||||
</Select.Content>
|
</Select.Content>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
|
<Button variant="soft" onClick={nextPage}>
|
||||||
|
<CaretRightIcon />
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex gap="2" align="center">
|
<Flex gap="2" justify="center">
|
||||||
<Button variant="soft" onClick={previousPage}>
|
<Dialog.Root
|
||||||
<CaretLeftIcon />
|
open={jumpToPositionOpen}
|
||||||
</Button>
|
onOpenChange={setJumpToPositionOpen}
|
||||||
<PageTurner />
|
>
|
||||||
<Button variant="soft" onClick={nextPage}>
|
<Dialog.Trigger>
|
||||||
<CaretRightIcon />
|
<Button variant="soft">Jump to position...</Button>
|
||||||
</Button>
|
</Dialog.Trigger>
|
||||||
</Flex>
|
|
||||||
|
<Dialog.Content>
|
||||||
|
<Flex gap="4" justify="center">
|
||||||
|
<TextField.Input
|
||||||
|
ref={positionInput}
|
||||||
|
onChange={handleSearchPlayerChange}
|
||||||
|
type="number"
|
||||||
|
placeholder="Type a position..."
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
handleJumpToPosition();
|
||||||
|
setJumpToPositionOpen(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Flex gap="2">
|
||||||
|
<Dialog.Close>
|
||||||
|
<Button color="red">Cancel</Button>
|
||||||
|
</Dialog.Close>
|
||||||
|
<Dialog.Close>
|
||||||
|
<Button onClick={handleJumpToPosition}>Jump</Button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
||||||
|
|
||||||
|
<Popover.Root>
|
||||||
|
<Popover.Trigger>
|
||||||
|
<Button variant="soft">Jump to league...</Button>
|
||||||
|
</Popover.Trigger>
|
||||||
|
|
||||||
|
<Popover.Content>
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Select.Root
|
||||||
|
value={`${jumpToLeague}`}
|
||||||
|
onValueChange={(value) => setJumpToLeague(parseInt(value))}
|
||||||
|
>
|
||||||
|
<Select.Trigger />
|
||||||
|
|
||||||
|
<Select.Content>
|
||||||
|
{ratingsInfo?.detail === undefined &&
|
||||||
|
ratingsInfo?.leagues.map(({ index, title }) => (
|
||||||
|
<Select.Item key={index} value={`${index}`}>
|
||||||
|
{title}
|
||||||
|
</Select.Item>
|
||||||
|
))}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
|
||||||
|
<Flex gap="2">
|
||||||
|
<Popover.Close>
|
||||||
|
<Button color="red">Cancel</Button>
|
||||||
|
</Popover.Close>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
|
||||||
|
<Dialog.Root>
|
||||||
|
<Dialog.Trigger>
|
||||||
|
<Button variant="soft">Jump to player...</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
|
||||||
|
<Dialog.Content>
|
||||||
|
<Flex gap="4" direction="column">
|
||||||
|
<TextField.Root>
|
||||||
|
<TextField.Slot>
|
||||||
|
<MagnifyingGlassIcon height="16" width="16" />
|
||||||
|
</TextField.Slot>
|
||||||
|
|
||||||
|
<TextField.Input
|
||||||
|
onChange={handleSearchPlayerChange}
|
||||||
|
placeholder="Search for player..."
|
||||||
|
/>
|
||||||
|
</TextField.Root>
|
||||||
|
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
{searchResults?.map((player) => (
|
||||||
|
<Dialog.Close>
|
||||||
|
<Button
|
||||||
|
key={player.account_id}
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => {
|
||||||
|
const playerIndex = players.data?.findIndex(
|
||||||
|
(playerData) => playerData.id === player.account_id,
|
||||||
|
);
|
||||||
|
const playerPage = Math.floor(
|
||||||
|
playerIndex! / rowsPerPage,
|
||||||
|
);
|
||||||
|
|
||||||
|
setPage(playerPage);
|
||||||
|
setHighlightedPlayerId(player.account_id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{player.nickname}
|
||||||
|
</Button>
|
||||||
|
</Dialog.Close>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{searchResults?.length === 0 && (
|
||||||
|
<Button disabled variant="ghost">
|
||||||
|
No players found in leaderboard
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex gap="2">
|
||||||
|
<Dialog.Close>
|
||||||
|
<Button color="red">Cancel</Button>
|
||||||
|
</Dialog.Close>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Leaderboard.Root>
|
<Leaderboard.Root>
|
||||||
|
|||||||
Reference in new issue
Block a user