feat: per-page theming

This commit is contained in:
TrèsAbhi committed 2023-11-07 10:06:15 -06:00
1 parent bd1e17bac9
commit 1bb83da253
6 files changed
+106 -97

No files matched your search

+1 -6
View File
@@ -41,12 +41,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
: 'url(https://i.imgur.com/PhS06NJ.png)',
}}
>
<Theme
appearance="dark"
panelBackground="translucent"
radius="full"
accentColor="blue"
>
<Theme appearance="dark" panelBackground="translucent" radius="full">
{!isEmbed && <Navbar />}
<Flex direction="column">{children}</Flex>
+74 -70
View File
@@ -5,14 +5,7 @@ import {
CaretRightIcon,
MagnifyingGlassIcon,
} from '@radix-ui/react-icons';
import {
Button,
Flex,
Popover,
Select,
Text,
TextField,
} from '@radix-ui/themes';
import { Button, Flex, Popover, Select, TextField } from '@radix-ui/themes';
import { produce } from 'immer';
import { range } from 'lodash';
import { useEffect, useRef, useState } from 'react';
@@ -73,11 +66,15 @@ export default function Page() {
}
});
const [page, setPage] = useState(0);
const pageInput = useRef<HTMLInputElement>(null);
const playerSlice = players.data?.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage,
);
const previousPage = () => setPage((page) => Math.max(page - 1, 0));
const nextPage = () =>
setPage((page) =>
Math.min(page + 1, Math.floor((players.data?.length ?? 0) / rowsPerPage)),
);
cachePage(page - 1);
cachePage(page);
@@ -115,16 +112,51 @@ export default function Page() {
}
}
useEffect(() => {
if (pageInput.current) pageInput.current.value = `${page + 1}`;
}, [page]);
useEffect(() => {
setPage(0);
}, [season, region]);
function PageTurner() {
const pageInput = useRef<HTMLInputElement>(null);
useEffect(() => {
if (pageInput.current) pageInput.current.value = `${page + 1}`;
}, [page]);
return (
<TextField.Root className={noArrows}>
<TextField.Slot>Page</TextField.Slot>
<TextField.Input
className={noArrows}
type="number"
ref={pageInput}
style={{ width: 64, textAlign: 'center' }}
onBlur={(event) => {
setPage(
Math.max(
0,
Math.min(
Math.floor((players.data?.length ?? 0) / rowsPerPage),
event.target.valueAsNumber - 1,
),
),
);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
(event.target as HTMLInputElement).blur();
}
}}
/>
<TextField.Slot>
out of {Math.ceil((players.data?.length ?? 0) / rowsPerPage)}
</TextField.Slot>
</TextField.Root>
);
}
return (
<PageWrapper>
<PageWrapper color="tomato">
<Flex gap="2">
<Select.Root
defaultValue={region}
@@ -256,72 +288,44 @@ export default function Page() {
</Select.Root>
<Flex gap="2" align="center">
<Button
variant="soft"
onClick={() => setPage((page) => Math.max(page - 1, 0))}
>
<Button variant="soft" onClick={previousPage}>
<CaretLeftIcon />
</Button>
<TextField.Root className={noArrows}>
<TextField.Slot>Page</TextField.Slot>
<TextField.Input
className={noArrows}
type="number"
ref={pageInput}
style={{ width: 64, textAlign: 'center' }}
onBlur={(event) => {
setPage(
Math.max(
0,
Math.min(
Math.floor((players.data?.length ?? 0) / rowsPerPage),
event.target.valueAsNumber - 1,
),
),
);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
(event.target as HTMLInputElement).blur();
}
}}
/>
<TextField.Slot>
out of {Math.ceil((players.data?.length ?? 0) / rowsPerPage)}
</TextField.Slot>
</TextField.Root>
<Button
variant="soft"
onClick={() =>
setPage((page) =>
Math.min(
page + 1,
Math.floor((players.data?.length ?? 0) / rowsPerPage),
),
)
}
>
<PageTurner />
<Button variant="soft" onClick={nextPage}>
<CaretRightIcon />
</Button>
</Flex>
</Flex>
<Leaderboard.Root>
{playerSlice?.map((player, index) => (
<Leaderboard.Item
nickname={
usernameCache[region][player.id] ??
`Loading player ${player.id}...`
}
position={page * rowsPerPage + index + 1}
score={player.score}
clan={clanCache[region][player.id]}
key={player.id}
/>
))}
{players.isLoading ? (
<Leaderboard.Gap message="Loading players..." />
) : (
playerSlice?.map((player, index) => (
<Leaderboard.Item
nickname={
usernameCache[region][player.id] ??
`Loading player ${player.id}...`
}
position={page * rowsPerPage + index + 1}
score={player.score}
clan={clanCache[region][player.id]}
key={player.id}
/>
))
)}
</Leaderboard.Root>
{players.isLoading && <Text>Loading...</Text>}
<Flex justify="center" gap="2">
<Button variant="soft" onClick={previousPage}>
<CaretLeftIcon />
</Button>
<PageTurner />
<Button variant="soft" onClick={nextPage}>
<CaretRightIcon />
</Button>
</Flex>
</PageWrapper>
);
}
+1 -1
View File
@@ -51,7 +51,7 @@ export default function Page() {
}, [session]);
return (
<PageWrapper>
<PageWrapper color="blue">
<div className={styles.toolBar}>
<div style={{ flex: 1, boxSizing: 'border-box', position: 'relative' }}>
<TextField.Root>
+4 -2
View File
@@ -474,10 +474,12 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
{items && (
<Leaderboard.Root>
{playersBefore > 0 && (
<Leaderboard.Gap number={playersBefore} />
<Leaderboard.Gap message={`+ ${playersBefore} more`} />
)}
{items}
{playersAfter > 0 && <Leaderboard.Gap number={playersAfter} />}
{playersAfter > 0 && (
<Leaderboard.Gap message={`+ ${playersAfter} more`} />
)}
</Leaderboard.Root>
)}
</Wrapper>
@@ -1,10 +1,10 @@
import { theme } from '../../../stitches.config';
export interface GapProps {
number: number;
message: string;
}
export function Gap({ number }: GapProps) {
export function Gap({ message: number }: GapProps) {
return (
<div
style={{
@@ -22,7 +22,7 @@ export function Gap({ number }: GapProps) {
fontSize: 16,
}}
>
+ {number.toLocaleString()} more
{number.toLocaleString()}
</span>
</div>
);
+23 -15
View File
@@ -1,24 +1,32 @@
import { Theme } from '@radix-ui/themes';
import { ComponentProps } from 'react';
interface PageWrapperProps extends ComponentProps<'div'> {
color?: ComponentProps<typeof Theme>['accentColor'];
}
export default function PageWrapper({
style,
color,
...props
}: ComponentProps<'div'>) {
}: PageWrapperProps) {
return (
<div
style={{
width: '100%',
maxWidth: 800,
margin: 'auto',
display: 'flex',
padding: 16,
flexDirection: 'column',
gap: 16,
boxSizing: 'border-box',
<Theme accentColor={color}>
<div
style={{
width: '100%',
maxWidth: 800,
margin: 'auto',
display: 'flex',
padding: 16,
flexDirection: 'column',
gap: 16,
boxSizing: 'border-box',
...style,
}}
{...props}
/>
...style,
}}
{...props}
/>
</Theme>
);
}