mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: search functionality
This commit is contained in:
1 parent
cbeb83d8d0
commit
57f6e928b7
2 files changed
+112
-12
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
import { style } from '@vanilla-extract/css';
|
import { style } from '@vanilla-extract/css';
|
||||||
|
import { theme } from '../../../stitches.config';
|
||||||
|
|
||||||
export const toolBar = style({
|
export const toolBar = style({
|
||||||
'@media': {
|
'@media': {
|
||||||
@@ -12,7 +13,7 @@ export const toolBar = style({
|
|||||||
gap: 8,
|
gap: 8,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const button = style({
|
export const toolbarButton = style({
|
||||||
'@media': {
|
'@media': {
|
||||||
'screen and (min-width: 640px)': {
|
'screen and (min-width: 640px)': {
|
||||||
flex: 0,
|
flex: 0,
|
||||||
@@ -21,3 +22,19 @@ export const button = style({
|
|||||||
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const searchButton = style({
|
||||||
|
border: 'none',
|
||||||
|
background: 'none',
|
||||||
|
fontSize: 16,
|
||||||
|
display: 'flex',
|
||||||
|
padding: 8,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
cursor: 'pointer',
|
||||||
|
|
||||||
|
':hover': {
|
||||||
|
backgroundColor: theme.colors.componentInteractiveHover,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -2,15 +2,21 @@
|
|||||||
|
|
||||||
import { CopyIcon, ListBulletIcon, ReloadIcon } from '@radix-ui/react-icons';
|
import { CopyIcon, ListBulletIcon, ReloadIcon } from '@radix-ui/react-icons';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { ChangeEvent, useRef } from 'react';
|
import { ChangeEvent, useRef, useState } from 'react';
|
||||||
import { Button } from '../../../components/Button';
|
import { Button } from '../../../components/Button';
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { SearchBar } from '../../../components/SearchBar';
|
import { SearchBar } from '../../../components/SearchBar';
|
||||||
|
import { REGION_NAMES } from '../../../constants/regions';
|
||||||
import { AccountListWithServer } from '../../../core/blitz/listPlayers';
|
import { AccountListWithServer } from '../../../core/blitz/listPlayers';
|
||||||
|
import { theme } from '../../../stitches.config';
|
||||||
import * as styles from './page.css';
|
import * as styles from './page.css';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
|
const [searchResults, setSearchResults] = useState<
|
||||||
|
AccountListWithServer | undefined
|
||||||
|
>(undefined);
|
||||||
|
const [showSearchResults, setShowSearchResults] = useState(false);
|
||||||
const handleChange = debounce(
|
const handleChange = debounce(
|
||||||
async (event: ChangeEvent<HTMLInputElement>) => {
|
async (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (event.target.value) {
|
if (event.target.value) {
|
||||||
@@ -18,11 +24,7 @@ export default function Page() {
|
|||||||
`/api/list/players?search=${event.target.value}`,
|
`/api/list/players?search=${event.target.value}`,
|
||||||
).then((response) => response.json() as Promise<AccountListWithServer>);
|
).then((response) => response.json() as Promise<AccountListWithServer>);
|
||||||
|
|
||||||
console.log(
|
setSearchResults(players);
|
||||||
players
|
|
||||||
.map((player) => `${player.region} - ${player.nickname}`)
|
|
||||||
.join('\n'),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@@ -33,21 +35,102 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<div className={styles.toolBar}>
|
<div className={styles.toolBar}>
|
||||||
|
<div style={{ flex: 1, boxSizing: 'border-box', position: 'relative' }}>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
ref={input}
|
ref={input}
|
||||||
onChange={handleChange}
|
style={{ width: '100%', boxSizing: 'border-box' }}
|
||||||
style={{ flex: 1 }}
|
onChange={(event) => {
|
||||||
|
if (event.target.value) {
|
||||||
|
setShowSearchResults(true);
|
||||||
|
setSearchResults(undefined);
|
||||||
|
} else {
|
||||||
|
setShowSearchResults(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(event);
|
||||||
|
}}
|
||||||
placeholder="Search for a player..."
|
placeholder="Search for a player..."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{showSearchResults && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
position: 'absolute',
|
||||||
|
width: '100%',
|
||||||
|
top: '100%',
|
||||||
|
marginTop: 8,
|
||||||
|
flexDirection: 'column',
|
||||||
|
backgroundColor: theme.colors.componentNonInteractive,
|
||||||
|
border: theme.borderStyles.nonInteractive,
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: 8,
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{searchResults === undefined ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignContent: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textLowContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Searching...
|
||||||
|
</div>
|
||||||
|
) : searchResults.length === 0 ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignContent: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textLowContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No results
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
searchResults?.map(({ account_id, nickname, region }) => (
|
||||||
|
<button
|
||||||
|
key={account_id}
|
||||||
|
className={styles.searchButton}
|
||||||
|
onClick={() => {
|
||||||
|
setShowSearchResults(false);
|
||||||
|
if (input.current) input.current.value = nickname;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{nickname}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: theme.colors.textLowContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{REGION_NAMES[region]}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', gap: 8 }}>
|
<div style={{ display: 'flex', gap: 8 }}>
|
||||||
<Button className={styles.button} color="dangerous">
|
<Button className={styles.toolbarButton} color="dangerous">
|
||||||
<ReloadIcon /> Reset
|
<ReloadIcon /> Reset
|
||||||
</Button>
|
</Button>
|
||||||
<Button className={styles.button}>
|
<Button className={styles.toolbarButton}>
|
||||||
<CopyIcon /> Embed
|
<CopyIcon /> Embed
|
||||||
</Button>
|
</Button>
|
||||||
<Button className={styles.button}>
|
<Button className={styles.toolbarButton}>
|
||||||
<ListBulletIcon /> Options
|
<ListBulletIcon /> Options
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user