mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: start of monorepo
This commit is contained in:
1 parent
14f39d71ac
commit
73c7bdf0c0
260 files changed
+1236
-1235
No files matched your search
@@ -0,0 +1,75 @@
|
||||
'use client';
|
||||
|
||||
import { imgur } from '@blitzkit/core';
|
||||
import { Box, BoxProps, Text } from '@radix-ui/themes';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Vector2Tuple } from 'three';
|
||||
|
||||
export enum AdType {
|
||||
MediumRectangleHorizontalPurple = 738182777,
|
||||
LeaderboardHorizontalPurple = 84051521,
|
||||
WideSkyscraperVerticalPurple = 1755617140,
|
||||
HalfPageVerticalPurple = 880185176,
|
||||
}
|
||||
|
||||
const AD_DIMENSIONS: Record<AdType, Vector2Tuple> = {
|
||||
[AdType.MediumRectangleHorizontalPurple]: [300, 250],
|
||||
[AdType.LeaderboardHorizontalPurple]: [728, 90],
|
||||
[AdType.WideSkyscraperVerticalPurple]: [160, 600],
|
||||
[AdType.HalfPageVerticalPurple]: [300, 600],
|
||||
};
|
||||
|
||||
type AdProps = BoxProps & {
|
||||
type: AdType;
|
||||
};
|
||||
|
||||
export function Ad({ type, style, ...props }: AdProps) {
|
||||
const id = useRef(uniqueId());
|
||||
const dimensions = AD_DIMENSIONS[type];
|
||||
|
||||
useEffect(() => {
|
||||
(window as any).msAdsQueue.push(function () {
|
||||
(window as any).mmnow.render({
|
||||
adUnitId: type,
|
||||
elementId: `${type}-${id.current}`,
|
||||
});
|
||||
});
|
||||
}, [type]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
position="relative"
|
||||
width={`${dimensions[0]}px`}
|
||||
height={`${dimensions[1]}px`}
|
||||
style={{
|
||||
outline: '1px solid var(--gray-3)',
|
||||
borderRadius: 'var(--radius-1)',
|
||||
background: `url(${imgur('DK21EHY')})`,
|
||||
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Text
|
||||
color="gray"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
}}
|
||||
align="center"
|
||||
>
|
||||
Advertisement
|
||||
</Text>
|
||||
|
||||
<Box
|
||||
width={`${dimensions[0]}px`}
|
||||
height={`${dimensions[1]}px`}
|
||||
position="relative"
|
||||
id={`${type}-${id.current}`}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Flex, FlexProps } from '@radix-ui/themes';
|
||||
import { Ad, AdType } from './Ad';
|
||||
|
||||
export function AdMidSectionNarrowOnly(props: FlexProps) {
|
||||
return (
|
||||
<Flex
|
||||
justify="center"
|
||||
py="4"
|
||||
gap="4"
|
||||
display={{
|
||||
initial: 'flex',
|
||||
sm: 'none',
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Ad type={AdType.MediumRectangleHorizontalPurple} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Flex, FlexProps } from '@radix-ui/themes';
|
||||
import { Ad, AdType } from './Ad';
|
||||
|
||||
export function AdMidSectionResponsive(props: FlexProps) {
|
||||
return (
|
||||
<Flex justify="center" py="4" gap="4" {...props}>
|
||||
<Ad
|
||||
display={{
|
||||
initial: 'none',
|
||||
sm: 'block',
|
||||
}}
|
||||
type={AdType.LeaderboardHorizontalPurple}
|
||||
/>
|
||||
<Ad
|
||||
display={{
|
||||
initial: 'block',
|
||||
sm: 'none',
|
||||
}}
|
||||
type={AdType.MediumRectangleHorizontalPurple}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Flex, FlexProps } from '@radix-ui/themes';
|
||||
import { Ad, AdType } from './Ad';
|
||||
|
||||
export function AdMidSectionWideOnly(props: FlexProps) {
|
||||
return (
|
||||
<Flex
|
||||
justify="center"
|
||||
py="4"
|
||||
gap="4"
|
||||
display={{
|
||||
initial: 'none',
|
||||
sm: 'flex',
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Ad type={AdType.LeaderboardHorizontalPurple} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
export function BlitzkitButtonGrayIcon(props: ComponentProps<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
width="426"
|
||||
height="426"
|
||||
viewBox="0 0 426 426"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<g clip-path="url(#clip0_600_256)">
|
||||
<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.6L213 77.5L426 196.6V229C426 234.79 422.876 240.58 416.628 244.997Z"
|
||||
fill="#9E9E9E"
|
||||
/>
|
||||
<path
|
||||
d="M200.456 257.38L221.999 242.08C228.557 237.422 231.732 232.85 231.521 228.364C231.31 223.797 228.392 219.516 222.764 215.519C217.193 211.562 211.22 209.529 204.846 209.42C198.473 209.23 192.007 211.465 185.448 216.123L163.905 231.422L200.456 257.38Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M146.77 219.252L165.937 205.64C172.44 201.022 175.726 196.69 175.796 192.643C175.809 188.557 173.256 184.696 168.135 181.059C163.07 177.462 157.717 175.708 152.076 175.798C146.435 175.887 140.363 178.241 133.861 182.859L114.693 196.472L146.77 219.252Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M235.625 52.6262L416.628 180.603C429.124 189.438 429.124 203.762 416.628 212.597L235.625 340.574C223.13 349.409 202.87 349.409 190.375 340.574L9.37173 212.597C-3.12391 203.762 -3.12391 189.438 9.37172 180.603L190.375 52.6262C202.87 43.7913 223.13 43.7913 235.625 52.6262ZM290.596 213.945L197.056 150.108L217.292 135.762L265.867 167.722L263.968 133.871L286.355 118L288.049 158.111L359.102 165.378L335.236 182.298L288.86 177.31L289.153 184.23L310.832 199.599L290.596 213.945ZM70 201.714L192.905 289L241.672 254.366C254.96 244.929 262.551 235.142 264.446 225.004C266.398 214.825 261.803 205.779 250.66 197.866C242.613 192.151 234.247 188.9 225.563 188.113C216.935 187.286 208.978 188.301 201.692 191.158L201.354 190.918C204.302 186.506 205.165 181.658 203.941 176.372C202.718 171.006 198.702 165.905 191.893 161.069C180.919 153.275 168.971 150.211 156.048 151.875C143.124 153.539 129.906 159.17 116.393 168.767L70 201.714Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_600_256">
|
||||
<rect width="426" height="426" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Code } from '@radix-ui/themes';
|
||||
import { use } from 'react';
|
||||
import { gameDefinitions } from '../../../core/blitzkit/gameDefinitions';
|
||||
|
||||
export function WoTBVersion() {
|
||||
const awaitedGameDefinitions = use(gameDefinitions);
|
||||
|
||||
return (
|
||||
<Code color="gray" size="2">
|
||||
{awaitedGameDefinitions.version}
|
||||
</Code>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const containerInner = style({
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
maxWidth: 1024,
|
||||
padding: '0 16px',
|
||||
|
||||
'@media': {
|
||||
'screen and (max-width: 640px)': {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
'use client';
|
||||
|
||||
import { gameDefinitions } from '@blitzkit/core';
|
||||
import { Code, Flex, Heading, Text, Theme } from '@radix-ui/themes';
|
||||
import { use } from 'react';
|
||||
import packageJson from '../../../../../package.json';
|
||||
import { Link } from '../Link';
|
||||
|
||||
export function Footer() {
|
||||
const awaitedGameDefinitions = use(gameDefinitions);
|
||||
|
||||
return (
|
||||
<Theme radius="none">
|
||||
<Flex
|
||||
gap="6"
|
||||
p="6"
|
||||
direction="column"
|
||||
align="center"
|
||||
style={{ backgroundColor: 'var(--color-panel)' }}
|
||||
>
|
||||
<Flex
|
||||
align="center"
|
||||
justify="between"
|
||||
maxWidth="40rem"
|
||||
width="100%"
|
||||
flexGrow="1"
|
||||
gap="5"
|
||||
position="relative"
|
||||
direction={{ initial: 'column', sm: 'row' }}
|
||||
>
|
||||
<Flex
|
||||
direction="column"
|
||||
align={{
|
||||
initial: 'center',
|
||||
sm: 'start',
|
||||
}}
|
||||
>
|
||||
<Heading>BlitzKit </Heading>
|
||||
<Text color="gray">Everything World of Tanks Blitz</Text>
|
||||
<Text size="1" color="gray">
|
||||
Unaffiliated with Wargaming or any service
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
gap="6"
|
||||
width={{
|
||||
initial: '100%',
|
||||
sm: 'auto',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="1"
|
||||
align={{
|
||||
initial: 'end',
|
||||
sm: 'start',
|
||||
}}
|
||||
flexGrow={{
|
||||
initial: '1',
|
||||
sm: '0',
|
||||
}}
|
||||
flexBasis={{
|
||||
initial: '0',
|
||||
sm: 'auto',
|
||||
}}
|
||||
>
|
||||
<Heading size="3">About</Heading>
|
||||
<Flex
|
||||
direction="column"
|
||||
align={{
|
||||
initial: 'end',
|
||||
sm: 'start',
|
||||
}}
|
||||
>
|
||||
<Link href="/docs/about/credits" color="gray">
|
||||
Credits
|
||||
</Link>
|
||||
<Link
|
||||
href="https://discord.gg/nDt7AjGJQH"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
>
|
||||
Discord
|
||||
</Link>
|
||||
<Link
|
||||
href="https://github.com/tresabhi/blitzkit"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
>
|
||||
GitHub
|
||||
</Link>
|
||||
<Link href="/docs/patches" color="gray">
|
||||
Patches
|
||||
</Link>
|
||||
|
||||
{/* patreon supporters? */}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="1"
|
||||
flexGrow={{
|
||||
initial: '1',
|
||||
sm: '0',
|
||||
}}
|
||||
flexBasis={{
|
||||
initial: '0',
|
||||
sm: 'auto',
|
||||
}}
|
||||
>
|
||||
<Heading size="3">Legal</Heading>
|
||||
<Flex direction="column">
|
||||
<Link href="/docs/legal/privacy-policy" color="gray">
|
||||
Privacy policy
|
||||
</Link>
|
||||
<Link href="/docs/legal/terms-of-service" color="gray">
|
||||
Terms of service
|
||||
</Link>
|
||||
<Link
|
||||
href="https://www.google.com/settings/ads"
|
||||
target="_blank"
|
||||
color="gray"
|
||||
>
|
||||
Ad settings
|
||||
</Link>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex gap="5" display={{ initial: 'flex', sm: 'none' }}>
|
||||
<Flex direction="column" justify="between" align="end">
|
||||
<Text size="2" color="gray">
|
||||
BlitzKit
|
||||
</Text>
|
||||
<Text size="2" color="gray">
|
||||
WoT Blitz
|
||||
</Text>
|
||||
<Text size="2" color="gray">
|
||||
CDN
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex direction="column" justify="between" align="start">
|
||||
<Code size="2" color="gray">
|
||||
{packageJson.version}
|
||||
</Code>
|
||||
<Code size="2" color="gray">
|
||||
{awaitedGameDefinitions.version}
|
||||
</Code>
|
||||
<Code size="2" color="gray">
|
||||
{process.env.NEXT_PUBLIC_ASSET_BRANCH}
|
||||
</Code>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex gap="2" align="center" display={{ initial: 'none', sm: 'flex' }}>
|
||||
<Text size="2" color="gray">
|
||||
BlitzKit
|
||||
</Text>
|
||||
<Code size="2" color="gray">
|
||||
{packageJson.version}
|
||||
</Code>
|
||||
<Text size="2" color="gray">
|
||||
WoT Blitz
|
||||
</Text>
|
||||
<Code size="2" color="gray">
|
||||
{awaitedGameDefinitions.version}
|
||||
</Code>
|
||||
<Text size="2" color="gray">
|
||||
CDN
|
||||
</Text>
|
||||
<Code size="2" color="gray">
|
||||
{process.env.NEXT_PUBLIC_ASSET_BRANCH}
|
||||
</Code>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Theme>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Link as RadixLink,
|
||||
LinkProps as RadixLinkProps,
|
||||
} from '@radix-ui/themes';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
type LinkProps = RadixLinkProps & {
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
||||
({ href, onClick, target, disabled, style, ...props }, ref) => {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<RadixLink
|
||||
style={{
|
||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||
...style,
|
||||
}}
|
||||
ref={ref}
|
||||
href={disabled ? undefined : href}
|
||||
onClick={(event) => {
|
||||
if (disabled) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (href) {
|
||||
if (event.ctrlKey || event.metaKey || target === '_blank') {
|
||||
window.open(href);
|
||||
} else {
|
||||
router.push(href);
|
||||
}
|
||||
}
|
||||
onClick?.(event);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
import { idToRegion } from '@blitzkit/core';
|
||||
import { Text } from '@radix-ui/themes';
|
||||
import { use, useMemo } from 'react';
|
||||
import { getAccountInfo } from '../../../../../../src/core/blitz/getAccountInfo';
|
||||
import * as App from '../../../stores/app';
|
||||
|
||||
export function WargamingAccountName() {
|
||||
const wargaming = App.use((state) => state.logins.wargaming!);
|
||||
const promise = useMemo(
|
||||
() =>
|
||||
getAccountInfo(idToRegion(wargaming.id), wargaming.id, [], {
|
||||
access_token: wargaming.token,
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
return data?.nickname as string | undefined;
|
||||
}),
|
||||
[wargaming],
|
||||
);
|
||||
const nickname = use(promise);
|
||||
|
||||
return nickname ?? <Text color="gray">Unknown Account</Text>;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { Button, ButtonProps, Dialog, Flex } from '@radix-ui/themes';
|
||||
import { REGIONS } from '../../../../../../src/constants/regions';
|
||||
import strings from '../../../../../../src/lang/en-US.json';
|
||||
import { Link } from '../../Link';
|
||||
import { WargamingIcon } from '../../WargamingIcon';
|
||||
|
||||
export function WargamingLoginButton({ children, ...props }: ButtonProps) {
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Button
|
||||
color="red"
|
||||
{...props}
|
||||
children={
|
||||
<>
|
||||
<WargamingIcon width={15} height={15} /> {children ?? 'Wargaming'}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Content width="fit-content">
|
||||
<Dialog.Title align="center">Choose your region</Dialog.Title>
|
||||
|
||||
<Flex gap="2" wrap="wrap" justify="center" align="center">
|
||||
{REGIONS.map((region) => (
|
||||
<Dialog.Close key={region}>
|
||||
<Link
|
||||
href={
|
||||
typeof window !== 'undefined'
|
||||
? `https://api.worldoftanks.${
|
||||
region
|
||||
}/wot/auth/login/?application_id=${assertSecret(
|
||||
process.env.WARGAMING_APPLICATION_ID,
|
||||
)}&redirect_uri=${encodeURIComponent(
|
||||
`${location.origin}/auth/wargaming?return=${
|
||||
location.origin
|
||||
}${location.pathname}`,
|
||||
)}`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Button color="red">
|
||||
{strings.common.regions.normal[region]}
|
||||
</Button>
|
||||
</Link>
|
||||
</Dialog.Close>
|
||||
))}
|
||||
</Flex>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { style, styleVariants } from '@vanilla-extract/css';
|
||||
|
||||
const MIN_WIDTH = 640 + 128;
|
||||
export const NAVBAR_HEIGHT = 48;
|
||||
|
||||
export const hamburger = style({
|
||||
display: 'inline-flex',
|
||||
|
||||
'@media': {
|
||||
[`screen and (min-width: ${MIN_WIDTH}px)`]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const tools = style({
|
||||
display: 'none',
|
||||
|
||||
'@media': {
|
||||
[`screen and (min-width: ${MIN_WIDTH}px)`]: {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const navbar = style({
|
||||
height: NAVBAR_HEIGHT,
|
||||
marginBottom: -1, // 1px overlap with content to bleed color
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: 1,
|
||||
});
|
||||
|
||||
const navbarExpanderBase = style({
|
||||
transitionDuration: '250ms',
|
||||
height: '1000px',
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
|
||||
backdropFilter: 'blur(4rem) brightness(0.75)',
|
||||
WebkitBackdropFilter: 'blur(4rem) brightness(0.75)',
|
||||
|
||||
'@media': {
|
||||
[`screen and (min-width: ${MIN_WIDTH}px)`]: {
|
||||
maxHeight: NAVBAR_HEIGHT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const navbarExpander = styleVariants({
|
||||
false: [
|
||||
navbarExpanderBase,
|
||||
{
|
||||
maxHeight: NAVBAR_HEIGHT,
|
||||
},
|
||||
],
|
||||
true: [
|
||||
navbarExpanderBase,
|
||||
{
|
||||
maxHeight: '100vh',
|
||||
overscrollBehavior: 'contain',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const navbarContent = style({
|
||||
width: '100%',
|
||||
maxHeight: '100vh',
|
||||
});
|
||||
@@ -0,0 +1,325 @@
|
||||
'use client';
|
||||
|
||||
import { assertSecret } from '@blitzkit/core/src/blitzkit/assertSecret';
|
||||
import { imgur, ImgurSize } from '@blitzkit/core/src/imgur/imgur';
|
||||
import { patreonLoginUrl } from '@blitzkit/core/src/patreon/patreonLoginUrl';
|
||||
import {
|
||||
Cross1Icon,
|
||||
DiscordLogoIcon,
|
||||
GearIcon,
|
||||
HamburgerMenuIcon,
|
||||
PersonIcon,
|
||||
} from '@radix-ui/react-icons';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Code,
|
||||
Flex,
|
||||
Grid,
|
||||
IconButton,
|
||||
Inset,
|
||||
Popover,
|
||||
ScrollArea,
|
||||
Separator,
|
||||
Skeleton,
|
||||
Text,
|
||||
} from '@radix-ui/themes';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Fragment, Suspense, useState } from 'react';
|
||||
import { BRANCH_NAMES } from '../../app/components/Hero/constants';
|
||||
import { homeTool, TOOLS } from '../../constants/tools';
|
||||
import * as App from '../../stores/app';
|
||||
import { Link } from '../Link';
|
||||
import { PatreonIcon } from '../PatreonIcon';
|
||||
import { WargamingIcon } from '../WargamingIcon';
|
||||
import { WargamingAccountName } from './components/WargamingAccountName';
|
||||
import { WargamingLoginButton } from './components/WargamingLoginButton';
|
||||
import * as styles from './index.css';
|
||||
|
||||
export function Navbar() {
|
||||
const [showHamburgerMenu, setShowHamburgerMenu] = useState(false);
|
||||
const pathname = usePathname();
|
||||
const logins = App.use((state) => state.logins);
|
||||
const mutateApp = App.useMutation();
|
||||
const tools = [homeTool, ...TOOLS];
|
||||
const isBranchNamed =
|
||||
process.env.NEXT_PUBLIC_ASSET_BRANCH &&
|
||||
BRANCH_NAMES[process.env.NEXT_PUBLIC_ASSET_BRANCH];
|
||||
|
||||
return (
|
||||
<Flex className={styles.navbar}>
|
||||
<Flex
|
||||
className={styles.navbarExpander[`${showHamburgerMenu}`]}
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
direction="column"
|
||||
gap="2"
|
||||
>
|
||||
<Flex justify="center">
|
||||
<Flex flexGrow="1" maxWidth="1024px" p="3" align="center">
|
||||
<Flex gap="3" align="center">
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
color="gray"
|
||||
className={styles.hamburger}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setShowHamburgerMenu((state) => !state);
|
||||
}}
|
||||
>
|
||||
{showHamburgerMenu ? <Cross1Icon /> : <HamburgerMenuIcon />}
|
||||
</IconButton>
|
||||
|
||||
<Link
|
||||
color="gray"
|
||||
highContrast
|
||||
href="/"
|
||||
underline="hover"
|
||||
weight="bold"
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
>
|
||||
<Flex align="center" gap="1">
|
||||
BlitzKit
|
||||
{isBranchNamed && (
|
||||
<Code color="gray" size="1" highContrast variant="outline">
|
||||
{BRANCH_NAMES[process.env.NEXT_PUBLIC_ASSET_BRANCH!]}
|
||||
</Code>
|
||||
)}
|
||||
</Flex>
|
||||
</Link>
|
||||
</Flex>
|
||||
|
||||
<Box flexGrow="1" />
|
||||
|
||||
<Flex
|
||||
align="center"
|
||||
gap="2"
|
||||
justify="center"
|
||||
className={styles.tools}
|
||||
>
|
||||
{TOOLS.map((tool, index) => {
|
||||
const unavailableOnBranch = tool.branches?.every(
|
||||
(branch) =>
|
||||
branch !==
|
||||
assertSecret(process.env.NEXT_PUBLIC_ASSET_BRANCH),
|
||||
);
|
||||
const selected = pathname.startsWith(`/tools/${tool.id}`);
|
||||
|
||||
if (unavailableOnBranch) return null;
|
||||
|
||||
return (
|
||||
<Fragment key={tool.title}>
|
||||
{index > 0 && <Separator orientation="vertical" size="1" />}
|
||||
<Link
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
color="gray"
|
||||
highContrast={selected}
|
||||
size="2"
|
||||
href={`/tools/${tool.id}`}
|
||||
underline={selected ? 'always' : 'hover'}
|
||||
>
|
||||
{tool.title}
|
||||
</Link>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
|
||||
<Box flexGrow="1" />
|
||||
|
||||
<Flex align="center" gap="3">
|
||||
<Link
|
||||
style={{ display: 'flex', alignContent: 'center' }}
|
||||
color="gray"
|
||||
href="https://discord.gg/nDt7AjGJQH"
|
||||
underline="none"
|
||||
target="_blank"
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
>
|
||||
<DiscordLogoIcon />
|
||||
</Link>
|
||||
<Link
|
||||
style={{ display: 'flex', alignContent: 'center' }}
|
||||
color="gray"
|
||||
href="https://www.patreon.com/tresabhi"
|
||||
underline="none"
|
||||
target="_blank"
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
>
|
||||
<PatreonIcon width="0.75em" height="0.75em" />
|
||||
</Link>
|
||||
<Link
|
||||
style={{ display: 'flex', alignContent: 'center' }}
|
||||
color="gray"
|
||||
href="/settings"
|
||||
underline="none"
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
>
|
||||
<GearIcon />
|
||||
</Link>
|
||||
<Popover.Root>
|
||||
<Popover.Trigger>
|
||||
<IconButton variant="ghost" color="gray">
|
||||
<PersonIcon />
|
||||
</IconButton>
|
||||
</Popover.Trigger>
|
||||
|
||||
<Popover.Content
|
||||
align="end"
|
||||
width="320px"
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
>
|
||||
{(logins.patreon || logins.wargaming) && (
|
||||
<Flex direction="column" gap="2">
|
||||
<Text align="center" color="gray">
|
||||
Logged in accounts
|
||||
</Text>
|
||||
|
||||
{logins.patreon && (
|
||||
<Flex align="center" gap="2" justify="center">
|
||||
<PatreonIcon width={15} height={15} />
|
||||
<Text>Patreon</Text>
|
||||
<Button
|
||||
color="red"
|
||||
variant="ghost"
|
||||
onClick={() =>
|
||||
mutateApp((draft) => {
|
||||
draft.logins.patreon = undefined;
|
||||
})
|
||||
}
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{logins.wargaming && (
|
||||
<Flex align="center" gap="2" justify="center">
|
||||
<WargamingIcon width={15} height={15} />
|
||||
<Text>
|
||||
<Suspense
|
||||
fallback={<Skeleton height="1em" width="5rem" />}
|
||||
>
|
||||
<WargamingAccountName />
|
||||
</Suspense>
|
||||
</Text>
|
||||
<Button
|
||||
color="red"
|
||||
variant="ghost"
|
||||
onClick={() =>
|
||||
mutateApp((draft) => {
|
||||
draft.logins.wargaming = undefined;
|
||||
})
|
||||
}
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{!logins.patreon !== !logins.wargaming && (
|
||||
<Inset side="x">
|
||||
<Separator my="4" size="4" />
|
||||
</Inset>
|
||||
)}
|
||||
|
||||
{(!logins.patreon || !logins.wargaming) && (
|
||||
<Flex direction="column" gap="2">
|
||||
<Text align="center" color="gray">
|
||||
Log in with...
|
||||
</Text>
|
||||
|
||||
{!logins.patreon && (
|
||||
<Link
|
||||
style={{ width: '100%' }}
|
||||
href={patreonLoginUrl()}
|
||||
>
|
||||
<Button style={{ width: '100%' }} color="tomato">
|
||||
<PatreonIcon width={15} height={15} /> Patreon
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{!logins.wargaming && <WargamingLoginButton />}
|
||||
</Flex>
|
||||
)}
|
||||
</Popover.Content>
|
||||
</Popover.Root>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<ScrollArea>
|
||||
<Grid
|
||||
columns="repeat(auto-fill, minmax(192px, 1fr))"
|
||||
flow="dense"
|
||||
gap="2"
|
||||
width="100%"
|
||||
p="3"
|
||||
pt="0"
|
||||
>
|
||||
{tools.map((tool) => {
|
||||
const unavailableOnBranch = tool.branches?.every(
|
||||
(branch) =>
|
||||
branch !== assertSecret(process.env.NEXT_PUBLIC_ASSET_BRANCH),
|
||||
);
|
||||
|
||||
if (unavailableOnBranch) return null;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
key={tool.id}
|
||||
onClick={() => setShowHamburgerMenu(false)}
|
||||
style={{
|
||||
position: 'relative',
|
||||
borderRadius: 'var(--radius-2)',
|
||||
overflow: 'hidden',
|
||||
backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.MediumThumbnail })})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
aspectRatio: '2 / 1',
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href={tool.id.length === 0 ? '/' : `/tools/${tool.id}`}
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
textDecoration: 'none',
|
||||
color: 'inherit',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
flexGrow="1"
|
||||
style={{
|
||||
backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.MediumThumbnail })})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Flex
|
||||
p="2"
|
||||
align="center"
|
||||
width="100%"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-panel-translucent)',
|
||||
backdropFilter: 'blur(4rem)',
|
||||
WebkitBackdropFilter: 'blur(4rem)',
|
||||
}}
|
||||
>
|
||||
<Text weight="medium">{tool.title}</Text>
|
||||
</Flex>
|
||||
</Link>
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</ScrollArea>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Flex, FlexProps, Theme } from '@radix-ui/themes';
|
||||
import { ComponentProps } from 'react';
|
||||
import { RadixSize } from '../../packages/website/src/stores/embedState';
|
||||
|
||||
type PageWrapperProps = FlexProps & {
|
||||
color?: ComponentProps<typeof Theme>['accentColor'];
|
||||
size?: number | string;
|
||||
noMaxWidth?: boolean;
|
||||
containerProps?: ComponentProps<typeof Theme>;
|
||||
noFlex1?: boolean;
|
||||
padding?: RadixSize;
|
||||
};
|
||||
|
||||
export default function PageWrapper({
|
||||
style,
|
||||
color,
|
||||
size = 800,
|
||||
children,
|
||||
noMaxWidth = false,
|
||||
noFlex1 = false,
|
||||
containerProps,
|
||||
padding = '4',
|
||||
...props
|
||||
}: PageWrapperProps) {
|
||||
return (
|
||||
<Theme
|
||||
accentColor={color}
|
||||
style={{
|
||||
flex: noFlex1 ? undefined : 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
...containerProps?.style,
|
||||
}}
|
||||
{...containerProps}
|
||||
>
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="4"
|
||||
p={padding}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: noMaxWidth ? undefined : size,
|
||||
margin: 'auto',
|
||||
boxSizing: 'border-box',
|
||||
flex: 1,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Flex>
|
||||
</Theme>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function Party3() {
|
||||
useEffect(() => {
|
||||
(window as any).msAdsQueue = (window as any).msAdsQueue || [];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* analytics */}
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=G-GL2JVHCGPQ"
|
||||
/>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-GL2JVHCGPQ');
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* adsense */}
|
||||
{/* <script
|
||||
async
|
||||
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1289406790225052"
|
||||
crossOrigin="anonymous"
|
||||
/> */}
|
||||
|
||||
{/* pub center */}
|
||||
{/* <script
|
||||
async
|
||||
src="https://adsdk.microsoft.com/mmnow/sdk.js?siteId=364645&publisherId=253617120"
|
||||
crossOrigin="anonymous"
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
export function PatreonIcon(props: ComponentProps<'svg'>) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 436 476" {...props}>
|
||||
<path
|
||||
fill="currentColor"
|
||||
data-fill="1"
|
||||
d="M436 143c-.084-60.778-47.57-110.591-103.285-128.565C263.528-7.884 172.279-4.649 106.214 26.424 26.142 64.089.988 146.596.051 228.883c-.77 67.653 6.004 245.841 106.83 247.11 74.917.948 86.072-95.279 120.737-141.623 24.662-32.972 56.417-42.285 95.507-51.929C390.309 265.865 436.097 213.011 436 143Z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
export function WargamingIcon(props: ComponentProps<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
width="15"
|
||||
height="15"
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<g clipPath="url(#clip0_574_231)">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M7.46409 0.156338C8.91652 0.149247 10.3384 0.57301 11.55 1.37404C12.7616 2.17507 13.7085 3.31739 14.2709 4.65654C14.8332 5.9957 14.9859 7.47154 14.7095 8.89745C14.4331 10.3234 13.7401 11.6353 12.7181 12.6673C11.6961 13.6994 10.391 14.4052 8.96789 14.6955C7.54475 14.9859 6.06748 14.8477 4.72288 14.2984C3.37829 13.7492 2.22676 12.8136 1.41391 11.6099C0.601062 10.4062 0.163403 8.98846 0.156278 7.53603V7.50009C0.150882 5.5586 0.916644 3.69442 2.28523 2.31733C3.65382 0.940243 5.51323 0.162958 7.45472 0.156338H7.46409ZM7.46409 1.56259C8.76962 1.56799 10.0372 2.00218 11.0719 2.79837C12.1065 3.59456 12.8509 4.70863 13.1906 5.96922C13.5302 7.2298 13.4463 8.56706 12.9517 9.77529C12.4571 10.9835 11.5792 11.9958 10.4532 12.6563C10.8305 11.3103 10.9857 9.91172 10.9125 8.51571C11.2938 8.62353 11.5094 8.68446 11.8922 8.8079C11.47 7.70829 10.9518 6.64795 10.3438 5.63915C9.79373 6.67527 9.10279 7.63018 8.29065 8.47665L9.51565 8.40009C8.46097 10.2938 6.97347 11.2126 5.08909 11.4798C4.6594 9.33759 4.98128 5.85478 7.38597 4.21728L7.62972 5.38603C8.09847 4.63134 9.02503 3.6329 9.71409 2.93759C8.57965 2.49502 7.34402 2.37866 6.1469 2.60165C6.34534 2.77196 6.59065 2.98759 6.78909 3.15634C4.07815 4.3079 2.58909 6.20009 1.6094 8.40009C1.48639 7.55586 1.54531 6.69509 1.78221 5.87549C2.0191 5.0559 2.4285 4.29643 2.98295 3.64802C3.5374 2.99961 4.22409 2.47724 4.99695 2.11595C5.76982 1.75465 6.611 1.56279 7.46409 1.55321V1.56259Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_574_231">
|
||||
<rect width="15" height="15" fill="currentColor" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user