feat: use any account selection

This commit is contained in:
TrèsAbhi committed 2024-10-26 19:34:42 -05:00
1 parent 71c9d1461f
commit 3293afba76
4 files changed
+163 -98

No files matched your search

@@ -0,0 +1,150 @@
import {
searchPlayersAcrossRegions,
type AccountListWithServer,
} from '@blitzkit/core';
import strings from '@blitzkit/core/lang/en-US.json';
import { Link2Icon, PersonIcon } from '@radix-ui/react-icons';
import {
Badge,
Button,
Dialog,
Flex,
Heading,
Spinner,
Text,
TextField,
} from '@radix-ui/themes';
import { debounce } from 'lodash-es';
import { useCallback, useRef, useState } from 'react';
import { stringify } from 'urlon';
import type { configurations } from '../../constants/embeds';
import { App } from '../../stores/app';
import { EmbedState, type EmbedStateStore } from '../../stores/embedState';
import { CopyButton } from '../CopyButton';
interface CopyURLProps {
embed: keyof typeof configurations;
}
export function CopyURL({ embed }: CopyURLProps) {
const appStore = App.useStore();
const embedStateStore = EmbedState.useStore();
const input = useRef<HTMLInputElement>(null);
const [searching, setSearching] = useState(false);
const [results, setResults] = useState<AccountListWithServer>([]);
const performSearch = useCallback(
debounce(async () => {
if (!input.current) return;
const sanitized = input.current.value.trim();
if (sanitized.length === 0) {
setSearching(false);
return;
}
const results = await searchPlayersAcrossRegions(sanitized, 12);
setSearching(false);
setResults(results);
}, 500),
[],
);
const handleChange = useCallback(() => {
if (!input.current) return;
const sanitized = input.current.value.trim();
if (sanitized.length === 0) {
setSearching(false);
setResults([]);
} else {
setSearching(true);
performSearch();
}
}, []);
return (
<Dialog.Root>
<Dialog.Trigger>
<Button>
<Link2Icon />
Copy URL
</Button>
</Dialog.Trigger>
<Dialog.Content width="fit-content">
<Flex direction="column">
<Heading size="5">Copy URL</Heading>
<Text>Search an account to track</Text>
</Flex>
<TextField.Root
mt="4"
style={{ width: '20rem' }}
placeholder="Search players..."
ref={input}
onChange={handleChange}
>
<TextField.Slot>
<PersonIcon />
</TextField.Slot>
</TextField.Root>
<Flex justify="center" mt="4">
{searching && (
<Text color="gray">
<Flex align="center" gap="2">
<Spinner /> Searching
</Flex>
</Text>
)}
{!searching && results.length === 0 && (
<Text color="gray">No results</Text>
)}
</Flex>
{!searching && results.length > 0 && (
<Flex justify="center">
<Flex
direction="column"
gap="2"
mt="4"
width="fit-content"
minWidth="75%"
>
{results.map((result) => (
<CopyButton
variant="ghost"
copy={() => {
const state = embedStateStore.getState();
const initial = embedStateStore.getInitialState();
const shallowState: EmbedStateStore = {};
Object.entries(state).forEach(([key, value]) => {
if (value !== initial[key]) {
shallowState[key] = value;
}
});
const searchParams = new URLSearchParams({
id: `${result.account_id}`,
state: stringify(shallowState),
});
return `${location.origin}/tools/embed/${embed}/host?${searchParams.toString()}`;
}}
>
<Flex justify="between" width="100%" gap="2">
{result.nickname}
<Badge>{strings.common.regions.short[result.region]}</Badge>
</Flex>
</CopyButton>
))}
</Flex>
</Flex>
)}
</Dialog.Content>
</Dialog.Root>
);
}
@@ -3,7 +3,6 @@ import {
CodeIcon,
HeightIcon,
ImageIcon,
Link2Icon,
ResetIcon,
TimerIcon,
WidthIcon,
@@ -11,10 +10,10 @@ import {
import { Box, Button, Flex, Heading, ScrollArea, Text } from '@radix-ui/themes';
import { capitalize, startCase } from 'lodash-es';
import { useEffect, useRef, useState, type ReactNode } from 'react';
import { stringify } from 'urlon';
import { CopyButton } from '../../../../components/CopyButton';
import { Boolean } from '../../../../components/Embeds/Boolean';
import { Color } from '../../../../components/Embeds/Color';
import { CopyURL } from '../../../../components/Embeds/CopyURL';
import { Enum } from '../../../../components/Embeds/Enum';
import { Import } from '../../../../components/Embeds/Import';
import { PreviewWrapper } from '../../../../components/Embeds/PreviewWrapper';
@@ -25,18 +24,13 @@ import { SizeWithout0 } from '../../../../components/Embeds/SizeWithout0';
import { Slider } from '../../../../components/Embeds/Slider';
import { TextController } from '../../../../components/Embeds/TextController';
import { PageWrapper } from '../../../../components/PageWrapper';
import { WargamingLoginButton } from '../../../../components/WargamingLoginButton';
import {
configurations,
extractEmbedConfigDefaults,
} from '../../../../constants/embeds';
import { NAVBAR_HEIGHT } from '../../../../constants/navbar';
import { App } from '../../../../stores/app';
import {
EmbedState,
type EmbedConfig,
type EmbedStateStore,
} from '../../../../stores/embedState';
import { EmbedState, type EmbedConfig } from '../../../../stores/embedState';
import { EmbedItemType } from '../../../../stores/embedState/constants';
export interface EmbedPreviewControllerProps {
@@ -60,10 +54,6 @@ export function Page({ embed }: PageProps) {
}
function Content({ embed }: PageProps) {
const wargaming = App.useDeferred(
(state) => state.logins.wargaming,
undefined,
);
const embedStateStore = EmbedState.useStore();
const appStore = App.useStore();
const config = configurations[embed] as EmbedConfig;
@@ -100,39 +90,7 @@ function Content({ embed }: PageProps) {
</Text>
<Flex mb="6" gap="2" wrap="wrap">
<CopyButton
disabled={!wargaming}
copy={() => {
const { wargaming } = appStore.getState().logins;
if (!wargaming) return;
const state = embedStateStore.getState();
const initial = embedStateStore.getInitialState();
const shallowState: EmbedStateStore = {};
Object.entries(state).forEach(([key, value]) => {
if (value !== initial[key]) {
shallowState[key] = value;
}
});
const searchParams = new URLSearchParams({
id: `${wargaming.id}`,
state: stringify(shallowState),
});
return `${location.origin}/tools/embed/${embed}/host?${searchParams.toString()}`;
}}
>
<Link2Icon />
{wargaming ? 'Copy URL' : 'Log in to general URL'}
</CopyButton>
{!wargaming && (
<WargamingLoginButton>
Log in with Wargaming
</WargamingLoginButton>
)}
<CopyURL embed={embed} />
<CopyButton
variant="outline"
copy={() =>
@@ -1,51 +0,0 @@
import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
import { Callout, Flex, Link } from '@radix-ui/themes';
import { PageWrapper } from '../../../components/PageWrapper';
import { WargamingLoginButton } from '../../../components/WargamingLoginButton';
import { configurations } from '../../../constants/embeds';
import { App, type WargamingLogin } from '../../../stores/app';
export function Page() {
return (
<App.Provider>
<Content />
</App.Provider>
);
}
function Content() {
const wargaming = App.useDeferred((state) => state.logins.wargaming, {
expires: 0,
id: 0,
token: '',
} satisfies WargamingLogin);
return (
<PageWrapper color="red">
{!wargaming && (
<>
<Flex justify="center">
<Callout.Root size="1">
<Callout.Icon>
<ExclamationTriangleIcon />
</Callout.Icon>
<Callout.Text>
You must be logged in with your Wargaming account to export
embeds.
</Callout.Text>
</Callout.Root>
</Flex>
<Flex justify="center">
<WargamingLoginButton>Log in with Wargaming</WargamingLoginButton>
</Flex>
</>
)}
{Object.entries(configurations).map(([embed, config]) => (
<Link href={`/tools/embed/${embed}`}>{embed}</Link>
))}
</PageWrapper>
);
}
@@ -1,9 +1,17 @@
---
import { Link } from '@radix-ui/themes';
import { PageWrapper } from '../../../components/PageWrapper';
import { configurations } from '../../../constants/embeds';
import { embedTool } from '../../../constants/tools';
import ToolLayout from '../../../layouts/ToolLayout.astro';
import { Page } from './_index';
---
<ToolLayout tool={embedTool}>
<Page client:load />
<PageWrapper color="red">
{
Object.entries(configurations).map(([embed, config]) => (
<Link href={`/tools/embed/${embed}`}>{embed}</Link>
))
}
</PageWrapper>
</ToolLayout>