mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-13 20:56:11 +01:00
migrate 3
This commit is contained in:
1 parent
de8b3959b3
commit
5285d081e4
29 files changed
+740
-83
No files matched your search
@@ -0,0 +1,7 @@
|
||||
.search-bar {
|
||||
/* justify="center" */
|
||||
|
||||
.wrapper {
|
||||
/* gap="2" flexGrow="1" */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import type { TankDefinition } from "@blitzkit/core";
|
||||
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
|
||||
import { debounce } from "lodash-es";
|
||||
import { type KeyboardEventHandler, useCallback, useRef } from "react";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { TankFilters } from "../../stores/tankFilters";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { Spinner } from "../Spinner";
|
||||
import { Sort } from "../TankSearch/components/Sort";
|
||||
import { TextField } from "../TextField";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
type SearchBarProps = MaybeSkeletonComponentProps & {
|
||||
topResult?: TankDefinition;
|
||||
onSelect?: (tank: TankDefinition) => void;
|
||||
};
|
||||
|
||||
export function TankSearchBar({
|
||||
topResult,
|
||||
skeleton,
|
||||
onSelect,
|
||||
}: SearchBarProps) {
|
||||
const { strings } = useLocale();
|
||||
const search = TankFilters.use((state) => state.search);
|
||||
const searching = TankFilters.use((state) => state.searching);
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
const performSearch = useCallback(
|
||||
debounce(() => {
|
||||
TankFilters.mutate((draft) => {
|
||||
draft.searching = false;
|
||||
});
|
||||
|
||||
if (!input.current) return;
|
||||
|
||||
const sanitized = input.current.value.trim();
|
||||
|
||||
TankFilters.mutate((draft) => {
|
||||
draft.search = sanitized.length === 0 ? null : sanitized;
|
||||
});
|
||||
}, 500),
|
||||
[],
|
||||
);
|
||||
const handleChange = useCallback(() => {
|
||||
if (!searching) {
|
||||
TankFilters.mutate((draft) => {
|
||||
draft.searching = true;
|
||||
});
|
||||
}
|
||||
|
||||
performSearch();
|
||||
}, [searching]);
|
||||
const handleKeyDown = useCallback<KeyboardEventHandler>(
|
||||
(event) => {
|
||||
if (event.key !== "Enter" || !topResult || searching) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (onSelect) {
|
||||
onSelect(topResult);
|
||||
} else {
|
||||
window.location.href = `/tanks/${topResult.slug}`;
|
||||
}
|
||||
},
|
||||
[topResult],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles["search-bar"]}>
|
||||
<div className={styles.wrapper}>
|
||||
<TextField
|
||||
disabled={skeleton}
|
||||
defaultValue={search ?? undefined}
|
||||
style={{ flex: 1 }}
|
||||
ref={input}
|
||||
placeholder={strings.website.common.tank_search.search_bar_hint}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
{searching ? <Spinner /> : <MagnifyingGlassIcon />}
|
||||
</TextField>
|
||||
|
||||
<Sort />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user