diff --git a/packages/website/src/components/Embeds/CopyURL.tsx b/packages/website/src/components/Embeds/CopyURL.tsx new file mode 100644 index 000000000..1cefeedf6 --- /dev/null +++ b/packages/website/src/components/Embeds/CopyURL.tsx @@ -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(null); + const [searching, setSearching] = useState(false); + const [results, setResults] = useState([]); + 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 ( + + + + + + + + Copy URL + Search an account to track + + + + + + + + + + {searching && ( + + + Searching + + + )} + {!searching && results.length === 0 && ( + No results + )} + + + {!searching && results.length > 0 && ( + + + {results.map((result) => ( + { + 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()}`; + }} + > + + {result.nickname} + {strings.common.regions.short[result.region]} + + + ))} + + + )} + + + ); +} diff --git a/packages/website/src/pages/tools/embed/[embed]/_index.tsx b/packages/website/src/pages/tools/embed/[embed]/_index.tsx index 95a277108..f9b6c2a4b 100644 --- a/packages/website/src/pages/tools/embed/[embed]/_index.tsx +++ b/packages/website/src/pages/tools/embed/[embed]/_index.tsx @@ -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) { - { - 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()}`; - }} - > - - {wargaming ? 'Copy URL' : 'Log in to general URL'} - - {!wargaming && ( - - Log in with Wargaming - - )} + diff --git a/packages/website/src/pages/tools/embed/_index.tsx b/packages/website/src/pages/tools/embed/_index.tsx deleted file mode 100644 index a2a983d1f..000000000 --- a/packages/website/src/pages/tools/embed/_index.tsx +++ /dev/null @@ -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 ( - - - - ); -} - -function Content() { - const wargaming = App.useDeferred((state) => state.logins.wargaming, { - expires: 0, - id: 0, - token: '', - } satisfies WargamingLogin); - - return ( - - {!wargaming && ( - <> - - - - - - - - You must be logged in with your Wargaming account to export - embeds. - - - - - - Log in with Wargaming - - - )} - - {Object.entries(configurations).map(([embed, config]) => ( - {embed} - ))} - - ); -} diff --git a/packages/website/src/pages/tools/embed/index.astro b/packages/website/src/pages/tools/embed/index.astro index 1eb609380..9acde6dcb 100644 --- a/packages/website/src/pages/tools/embed/index.astro +++ b/packages/website/src/pages/tools/embed/index.astro @@ -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'; --- - + + { + Object.entries(configurations).map(([embed, config]) => ( + {embed} + )) + } +