feat: better hamburger menu

This commit is contained in:
TrèsAbhi committed 2024-05-14 14:07:44 -05:00
1 parent cdd2a08ec0
commit 0198829a18
6 files changed
+349 -166

No files matched your search

+7 -4
View File
@@ -8,7 +8,7 @@ import { usePathname } from 'next/navigation';
import { ReactNode, Suspense, useEffect, useState } from 'react';
import { Footer } from '../components/Footer';
import { Loader } from '../components/Loader';
import Navbar from '../components/Navbar';
import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar';
import { Party3 } from '../components/Party3';
import isDev from '../core/blitzkit/isDev';
import { isLocalhost } from '../core/blitzkit/isLocalhost';
@@ -31,7 +31,6 @@ export default function RootLayout({ children }: RootLayoutProps) {
const pathname = usePathname();
const isEmbed = pathname.split('/')[1] === 'embeds';
const isRoot = pathname === '/';
const darkMode = useApp((state) => state.darkMode);
const [showDevBuildAlert, setShowDevBuildAlert] = useState(false);
useEffect(() => {
@@ -68,7 +67,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
}}
>
<Theme
appearance={darkMode ? 'dark' : 'light'}
appearance="dark"
panelBackground="solid"
radius="full"
suppressHydrationWarning
@@ -76,9 +75,13 @@ export default function RootLayout({ children }: RootLayoutProps) {
>
<Flex
direction="column"
style={{ minHeight: '100vh', paddingTop: isEmbed ? undefined : 64 }}
style={{
minHeight: '100vh',
paddingTop: isEmbed ? undefined : NAVBAR_HEIGHT,
}}
>
{!isEmbed && <Navbar />}
<AlertDialog.Root open={showDevBuildAlert}>
<AlertDialog.Content>
<AlertDialog.Title>Experimental version!</AlertDialog.Title>
-15
View File
@@ -6,25 +6,10 @@ import { useApp } from '../../stores/app';
export default function Page() {
const developerMode = useApp((state) => state.developerMode);
const darkMode = useApp((state) => state.darkMode);
return (
<PageWrapper justify="center" align="center">
<Flex direction="column" gap="4">
<Flex gap="3" direction="column">
<Heading size="5">Appearance</Heading>
<Flex align="center" gap="2">
<Text>Dark mode (experimental)</Text>
<Switch
checked={darkMode}
onCheckedChange={(checked) =>
useApp.setState({ darkMode: checked })
}
/>
</Flex>
</Flex>
<Flex gap="3" direction="column">
<Heading size="5">Advanced</Heading>
+154 -137
View File
@@ -1,10 +1,12 @@
import {
Cross1Icon,
DiscordLogoIcon,
GearIcon,
HamburgerMenuIcon,
PersonIcon,
} from '@radix-ui/react-icons';
import {
Box,
Button,
Dialog,
Flex,
@@ -12,10 +14,13 @@ import {
IconButton,
Link as LinkRadix,
Popover,
ScrollArea,
Spinner,
Text,
} from '@radix-ui/themes';
import Link from 'next/link';
import { Suspense, useEffect } from 'react';
import { Suspense, useEffect, useState } from 'react';
import * as styles from '../../app/page.css';
import { REGIONS, UNLOCALIZED_REGION_NAMES } from '../../constants/regions';
import { TOOLS } from '../../constants/tools';
import { authURL } from '../../core/blitz/authURL';
@@ -28,9 +33,12 @@ import { theme } from '../../stitches.config';
import { useApp } from '../../stores/app';
import { LoggedIn } from './components/LoggedIn';
export const NAVBAR_HEIGHT = 64;
export default function Navbar() {
const wideFormat = useWideFormat(480);
const login = useApp((state) => state.login);
const [showHamburgerMenu, setShowHamburgerMenu] = useState(true);
useEffect(() => {
if (!login) return;
@@ -76,155 +84,164 @@ export default function Navbar() {
);
return (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: 64 + 1, // extra pixel for frost bleeding
zIndex: 2,
padding: '1rem',
background: theme.colors.appBackground1_alpha,
borderBottom: theme.borderStyles.nonInteractive,
backdropFilter: 'blur(4rem)',
boxSizing: 'border-box',
}}
>
<Flex
justify="center"
<>
<Box
style={{
height: '100%',
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: showHamburgerMenu ? 176 : NAVBAR_HEIGHT + 1, // extra pixel for frost bleeding
zIndex: 2,
padding: '1rem',
background: theme.colors.appBackground1_alpha,
borderBottom: theme.borderStyles.nonInteractive,
backdropFilter: 'blur(4rem)',
boxSizing: 'border-box',
transition: 'height 0.2s ease',
overflow: 'hidden',
}}
>
<Flex
justify="between"
align="center"
style={{ maxWidth: 800, width: '100%', padding: '0 16px' }}
gap="4"
>
<Popover.Root>
<Popover.Trigger>
<IconButton variant="ghost" color="gray">
<HamburgerMenuIcon />
</IconButton>
</Popover.Trigger>
<Popover.Content>
<Flex direction="column" gap="4">
{!wideFormat && <Flex gap="2">{plugs}</Flex>}
<Flex direction="column" gap="2">
<Heading size="4">Tools</Heading>
<Flex direction="column" gap="1" pl="4">
{TOOLS.map((tool, index) => {
if (tool.href || tool.disabled) return null;
return (
<LinkRadix
key={tool.id}
tabIndex={-1}
href={`/tools/${tool.id}`}
onClick={(event) => event.preventDefault()}
>
<Link
href={`/tools/${tool.id}`}
key={index}
style={{
textDecoration: 'none',
color: 'inherit',
}}
>
{tool.title}
</Link>
</LinkRadix>
);
})}
</Flex>
</Flex>
</Flex>
</Popover.Content>
</Popover.Root>
<Link
href="/"
style={{
color: 'inherit',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
<Flex direction="column" align="center" pt="2">
<Flex
justify="between"
align="center"
style={{ maxWidth: 1600, width: '100%', padding: '0 16px' }}
gap="4"
>
<BlitzkitWide />
</Link>
<IconButton
variant="ghost"
color="gray"
onClick={() => setShowHamburgerMenu((state) => !state)}
>
{showHamburgerMenu ? <Cross1Icon /> : <HamburgerMenuIcon />}
</IconButton>
<div style={{ flex: 1 }} />
<Link
href="/"
style={{
color: 'inherit',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<BlitzkitWide />
</Link>
{wideFormat && plugs}
<div style={{ flex: 1 }} />
<Link href="/settings">
<Flex style={{ width: '100%', height: '100%' }} justify="center">
<IconButton variant="ghost" color="gray">
<GearIcon />
</IconButton>
</Flex>
</Link>
{wideFormat && plugs}
{login && (
<Popover.Root>
<Popover.Trigger>
<Link href="/settings">
<Flex style={{ width: '100%', height: '100%' }} justify="center">
<IconButton variant="ghost" color="gray">
<PersonIcon />
<GearIcon />
</IconButton>
</Popover.Trigger>
</Flex>
</Link>
<Popover.Content align="center">
<Flex direction="column" gap="2">
<Suspense fallback={<Spinner />}>
<LoggedIn />
</Suspense>
</Flex>
</Popover.Content>
</Popover.Root>
)}
{login && (
<Popover.Root>
<Popover.Trigger>
<IconButton variant="ghost" color="gray">
<PersonIcon />
</IconButton>
</Popover.Trigger>
{/* TODO: re-enable in the future */}
{!login && false && (
<Dialog.Root>
<Dialog.Trigger>
<Button variant="ghost">Log in</Button>
</Dialog.Trigger>
<Dialog.Content
style={{
maxWidth: 360,
}}
>
<Flex direction="column" gap="2" align="center">
<Heading size="3">Choose your region</Heading>
<Flex gap="4" align="center" justify="center" wrap="wrap">
{REGIONS.map((region) => (
<LinkRadix
key={region}
href={authURL(
region,
typeof window === 'undefined'
? undefined
: location.href,
)}
>
{UNLOCALIZED_REGION_NAMES[region]}
</LinkRadix>
))}
<Popover.Content align="center">
<Flex direction="column" gap="2">
<Suspense fallback={<Spinner />}>
<LoggedIn />
</Suspense>
</Flex>
</Flex>
</Dialog.Content>
</Dialog.Root>
)}
</Popover.Content>
</Popover.Root>
)}
{/* TODO: re-enable in the future */}
{!login && false && (
<Dialog.Root>
<Dialog.Trigger>
<Button variant="ghost">Log in</Button>
</Dialog.Trigger>
<Dialog.Content
style={{
maxWidth: 360,
}}
>
<Flex direction="column" gap="2" align="center">
<Heading size="3">Choose your region</Heading>
<Flex gap="4" align="center" justify="center" wrap="wrap">
{REGIONS.map((region) => (
<LinkRadix
key={region}
href={authURL(
region,
typeof window === 'undefined'
? undefined
: location.href,
)}
>
{UNLOCALIZED_REGION_NAMES[region]}
</LinkRadix>
))}
</Flex>
</Flex>
</Dialog.Content>
</Dialog.Root>
)}
</Flex>
<ScrollArea scrollbars="horizontal">
<Flex mt="6" gap="3" justify="center">
{TOOLS.filter((tool) => !tool.href).map((tool) => (
<Link
href={tool.href ?? `/tools/${tool.id}`}
target={tool.href ? '_blank' : undefined}
className={
tool.disabled ? styles.tool.disabled : styles.tool.enabled
}
style={{
backgroundImage: `url(/assets/banners/${tool.id}.webp)`,
cursor: tool.disabled ? 'default' : 'pointer',
opacity: tool.disabled ? 0.25 : 1,
height: 64,
width: 144,
borderRadius: 8,
textDecoration: 'none',
backgroundSize: 'cover',
backgroundPosition: 'center',
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'flex-end',
padding: 8,
transition: `box-shadow ${theme.durations.regular}`,
}}
onClick={(event) => {
if (tool.disabled) event.preventDefault();
}}
>
<Text
style={{
color: theme.colors.textHighContrast,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{tool.title}
</Text>
</Link>
))}
</Flex>
</ScrollArea>
</Flex>
</Flex>
</div>
</Box>
</>
);
}
+8 -8
View File
@@ -25,18 +25,11 @@ export const TOOLS: Tool[] = [
},
{
id: 'rating',
title: 'Rating leaderboard',
title: 'Rating',
description: 'Full rating gamemode leaderboard',
pageDescription:
'Live and archived full rating leaderboard for World of Tanks Blitz',
},
{
id: 'session',
title: 'Session tracker',
description: 'Live session performance tracker',
pageDescription:
'Track your stats in real time as you play World of Tanks Blitz',
},
{
id: 'compare',
title: 'Compare',
@@ -44,6 +37,13 @@ export const TOOLS: Tool[] = [
pageDescription:
'Compare tanks statistics and loadouts in World of Tanks Blitz',
},
{
id: 'session',
title: 'Session tracker',
description: 'Live session performance tracker',
pageDescription:
'Track your stats in real time as you play World of Tanks Blitz',
},
{
id: 'discord',
title: 'Discord bot',
+180
View File
@@ -0,0 +1,180 @@
import { ComponentProps } from 'react';
export function Blitzkit(props: ComponentProps<'svg'>) {
return (
<svg
width="426"
height="426"
viewBox="0 0 426 426"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M416.628 244.997L235.625 372.974C223.13 381.809 202.87 381.809 190.375 372.974L9.37173 244.997C3.1239 240.58 -3.95076e-06 234.79 0 229V196.6H426V229C426 234.79 422.876 240.58 416.628 244.997Z"
fill="url(#paint0_linear_513_245)"
/>
<path
d="M416.628 244.997L235.625 372.974C223.13 381.809 202.87 381.809 190.375 372.974L9.37173 244.997C3.1239 240.58 -3.95076e-06 234.79 0 229V196.6H426V229C426 234.79 422.876 240.58 416.628 244.997Z"
fill="url(#paint1_linear_513_245)"
/>
<path
d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37173 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z"
fill="#D9D9D9"
/>
<path
d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37173 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z"
fill="url(#paint2_linear_513_245)"
/>
<path
d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37173 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z"
fill="url(#paint3_linear_513_245)"
/>
<g filter="url(#filter0_d_513_245)">
<path
d="M218.056 168.108L311.596 231.945L331.832 217.599L310.153 202.23L309.86 195.31L356.236 200.298L380.102 183.378L309.049 176.111L307.355 136L284.968 151.871L286.867 185.722L238.292 153.762L218.056 168.108Z"
fill="url(#paint4_linear_513_245)"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M213.905 307L91 219.714L137.393 186.767C150.906 177.17 164.124 171.539 177.048 169.875C189.971 168.211 201.919 171.275 212.893 179.069C219.702 183.905 223.718 189.006 224.941 194.372C226.165 199.658 225.302 204.506 222.354 208.918L222.692 209.158C229.978 206.301 237.935 205.286 246.563 206.113C255.247 206.9 263.613 210.151 271.66 215.866C282.803 223.779 287.398 232.825 285.446 243.004C283.551 253.142 275.96 262.929 262.672 272.366L213.905 307ZM242.999 260.08L221.456 275.38L184.905 249.422L206.448 234.123C213.007 229.465 219.473 227.23 225.846 227.42C232.22 227.529 238.193 229.562 243.764 233.519C249.392 237.516 252.31 241.797 252.521 246.364C252.732 250.85 249.558 255.422 242.999 260.08ZM186.937 223.64L167.77 237.252L135.693 214.472L154.861 200.859C161.363 196.241 167.435 193.887 173.076 193.798C178.717 193.708 184.07 195.462 189.135 199.059C194.256 202.696 196.809 206.557 196.796 210.643C196.726 214.69 193.44 219.022 186.937 223.64Z"
fill="url(#paint5_linear_513_245)"
/>
<path
d="M184.681 109.963C181.602 107.766 180.042 105.326 180 102.641C179.973 99.947 181.629 97.409 184.968 95.0273C188.143 92.7627 191.804 91.6061 195.95 91.5574C200.097 91.5088 204.484 93.1343 209.11 96.4339L209.91 97.005C214.92 100.578 217.431 104.507 217.445 108.793C217.459 113.059 214.606 117.3 208.886 121.517L208.208 122L203.24 118.456L203.856 118.017C207.537 115.391 209.494 112.697 209.727 109.934C209.945 107.162 207.961 104.282 203.773 101.295L202.541 100.826C199.557 98.6983 197.046 97.4926 195.007 97.2094C192.967 96.9067 191.181 97.302 189.649 98.3953C188.212 99.4202 187.623 100.504 187.883 101.646C188.157 102.778 189.218 104.003 191.066 105.321C192.804 106.561 194.494 107.279 196.136 107.474C197.779 107.669 199.325 107.25 200.776 106.215C202.158 105.229 202.815 104.077 202.746 102.759C202.664 101.432 201.829 100.202 200.241 99.0693L201.986 97.8247C204.614 99.6991 206.229 101.808 206.832 104.151C207.434 106.493 206.38 108.631 203.671 110.564C200.852 112.575 197.731 113.512 194.31 113.375C190.888 113.238 187.679 112.101 184.681 109.963Z"
fill="url(#paint6_linear_513_245)"
/>
<path
d="M232.267 104.781L218.47 79.4488L203.957 89.8006L198.721 86.0665L219.844 71L224.094 74.0312L239 99.9786L232.267 104.781Z"
fill="url(#paint7_linear_513_245)"
/>
</g>
<defs>
<filter
id="filter0_d_513_245"
x="72.6"
y="60.6"
width="325.902"
height="272.8"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset dy="8" />
<feGaussianBlur stdDeviation="9.2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
/>
<feBlend
mode="normal"
in2="BackgroundImageFix"
result="effect1_dropShadow_513_245"
/>
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_dropShadow_513_245"
result="shape"
/>
</filter>
<linearGradient
id="paint0_linear_513_245"
x1="127.008"
y1="227.288"
x2="174.926"
y2="391.583"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#0F3F7D" />
<stop offset="1" stop-color="#10284C" />
</linearGradient>
<linearGradient
id="paint1_linear_513_245"
x1="213"
y1="196.6"
x2="213"
y2="379.6"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#10243E" />
<stop offset="1" stop-color="#0F1B2D" />
</linearGradient>
<linearGradient
id="paint2_linear_513_245"
x1="213"
y1="46"
x2="213"
y2="347.2"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#10243E" />
<stop offset="1" stop-color="#0F1B2D" />
</linearGradient>
<linearGradient
id="paint3_linear_513_245"
x1="127.008"
y1="96.51"
x2="241.48"
y2="334.974"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#0F3F7D" />
<stop offset="1" stop-color="#10284C" />
</linearGradient>
<linearGradient
id="paint4_linear_513_245"
x1="339.524"
y1="58.5884"
x2="423.41"
y2="176.706"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.34" stop-color="#EAF6FF" />
<stop offset="0.64" stop-color="#97CBFF" />
</linearGradient>
<linearGradient
id="paint5_linear_513_245"
x1="339.524"
y1="58.5884"
x2="423.41"
y2="176.706"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.34" stop-color="#EAF6FF" />
<stop offset="0.64" stop-color="#97CBFF" />
</linearGradient>
<linearGradient
id="paint6_linear_513_245"
x1="197.441"
y1="87.3302"
x2="217.462"
y2="115.4"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.34" stop-color="#EAF6FF" />
<stop offset="0.64" stop-color="#97CBFF" />
</linearGradient>
<linearGradient
id="paint7_linear_513_245"
x1="197.441"
y1="87.3302"
x2="217.462"
y2="115.4"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.34" stop-color="#EAF6FF" />
<stop offset="0.64" stop-color="#97CBFF" />
</linearGradient>
</defs>
</svg>
);
}
-2
View File
@@ -12,7 +12,6 @@ interface Login {
export interface App {
devBuildAgreementTime: number;
developerMode: boolean;
darkMode: boolean;
login?: Login;
}
@@ -21,7 +20,6 @@ export const useApp = create<App>()(
(set) => ({
devBuildAgreementTime: 0,
developerMode: false,
darkMode: true,
}),
{ name: 'app', merge: (a, b) => merge(b, a) },
),