mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-12 06:06:28 -05:00
Make GlobalSearch actual links so we can ctrl+click for new tab
This commit is contained in:
@@ -131,11 +131,18 @@
|
||||
}
|
||||
|
||||
.listBoxItem {
|
||||
display: block;
|
||||
padding: var(--s-2) var(--s-3);
|
||||
border-radius: var(--radius-field);
|
||||
cursor: pointer;
|
||||
font-size: var(--font-sm);
|
||||
outline: none;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.listBoxItem[data-hovered] {
|
||||
background-color: var(--color-bg-high);
|
||||
}
|
||||
|
||||
.listBoxItem[data-focused] {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
RadioGroup,
|
||||
} from "react-aria-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useFetcher, useNavigate, useSearchParams } from "react-router";
|
||||
import { useFetcher, useSearchParams } from "react-router";
|
||||
import { useDebounce } from "react-use";
|
||||
import { Avatar } from "~/components/Avatar";
|
||||
import { Image } from "~/components/Image";
|
||||
@@ -33,10 +33,8 @@ import styles from "./GlobalSearch.module.css";
|
||||
import {
|
||||
filterWeaponResults,
|
||||
getRecentWeapons,
|
||||
getWeaponDestinationUrl,
|
||||
type SelectedWeapon,
|
||||
saveRecentWeapon,
|
||||
type WeaponDestination,
|
||||
WeaponDestinationMenu,
|
||||
WeaponResultsList,
|
||||
} from "./WeaponSearch";
|
||||
@@ -182,7 +180,6 @@ function GlobalSearchContent({
|
||||
initialWeaponId: string | null;
|
||||
}) {
|
||||
const { t } = useTranslation(["common", "weapons"]);
|
||||
const navigate = useNavigate();
|
||||
const [query, setQuery] = React.useState("");
|
||||
const [searchType, setSearchType] = React.useState<SearchType>(
|
||||
initialSearchType ?? getInitialSearchType(),
|
||||
@@ -193,6 +190,11 @@ function GlobalSearchContent({
|
||||
);
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
const listBoxRef = React.useRef<HTMLDivElement>(null);
|
||||
const modifierKeyRef = React.useRef(false);
|
||||
|
||||
const handleClickCapture = (e: React.MouseEvent) => {
|
||||
modifierKeyRef.current = e.metaKey || e.ctrlKey;
|
||||
};
|
||||
|
||||
const fetcher = useFetcher<SearchLoaderData>();
|
||||
|
||||
@@ -254,9 +256,7 @@ function GlobalSearchContent({
|
||||
return;
|
||||
}
|
||||
|
||||
const result = results.find((r) => getResultKey(r) === key);
|
||||
if (result) {
|
||||
navigate(getResultHref(result));
|
||||
if (!modifierKeyRef.current) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
@@ -274,16 +274,13 @@ function GlobalSearchContent({
|
||||
}
|
||||
};
|
||||
|
||||
const handleDestinationSelect = (key: React.Key) => {
|
||||
const handleDestinationSelect = () => {
|
||||
if (!selectedWeapon) return;
|
||||
|
||||
const url = getWeaponDestinationUrl(
|
||||
key as WeaponDestination,
|
||||
selectedWeapon,
|
||||
);
|
||||
saveRecentWeapon(selectedWeapon.id);
|
||||
navigate(url);
|
||||
onClose();
|
||||
if (!modifierKeyRef.current) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackToWeaponSearch = () => {
|
||||
@@ -292,17 +289,19 @@ function GlobalSearchContent({
|
||||
|
||||
if (searchType === "weapons" && selectedWeapon) {
|
||||
return (
|
||||
<WeaponDestinationMenu
|
||||
selectedWeapon={selectedWeapon}
|
||||
onBack={handleBackToWeaponSearch}
|
||||
onSelect={handleDestinationSelect}
|
||||
listBoxRef={listBoxRef}
|
||||
/>
|
||||
<div onClickCapture={handleClickCapture}>
|
||||
<WeaponDestinationMenu
|
||||
selectedWeapon={selectedWeapon}
|
||||
onBack={handleBackToWeaponSearch}
|
||||
onSelect={handleDestinationSelect}
|
||||
listBoxRef={listBoxRef}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div onClickCapture={handleClickCapture}>
|
||||
<Input
|
||||
ref={inputRef}
|
||||
className={styles.input}
|
||||
@@ -355,7 +354,6 @@ function GlobalSearchContent({
|
||||
ref={listBoxRef}
|
||||
className={clsx(styles.listBox, "scrollbar")}
|
||||
aria-label={t("common:search")}
|
||||
selectionMode="single"
|
||||
onAction={handleSelect}
|
||||
renderEmptyState={() =>
|
||||
hasQuery ? (
|
||||
@@ -371,6 +369,7 @@ function GlobalSearchContent({
|
||||
<ListBoxItem
|
||||
key={getResultKey(result)}
|
||||
id={getResultKey(result)}
|
||||
href={getResultHref(result)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<ResultItem result={result} />
|
||||
@@ -378,7 +377,7 @@ function GlobalSearchContent({
|
||||
))}
|
||||
</ListBox>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ export function filterWeaponResults(
|
||||
return matches;
|
||||
}
|
||||
|
||||
export function getWeaponDestinationUrl(
|
||||
function getWeaponDestinationUrl(
|
||||
key: WeaponDestination,
|
||||
weapon: SelectedWeapon,
|
||||
): string {
|
||||
@@ -145,7 +145,11 @@ export function WeaponDestinationMenu({
|
||||
onAction={onSelect}
|
||||
autoFocus="first"
|
||||
>
|
||||
<ListBoxItem id="builds" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="builds"
|
||||
href={getWeaponDestinationUrl("builds", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<FlaskConical size={20} />
|
||||
<span className={styles.resultName}>
|
||||
@@ -153,7 +157,11 @@ export function WeaponDestinationMenu({
|
||||
</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="popular" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="popular"
|
||||
href={getWeaponDestinationUrl("popular", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<Flame size={20} />
|
||||
<span className={styles.resultName}>
|
||||
@@ -161,7 +169,11 @@ export function WeaponDestinationMenu({
|
||||
</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="stats" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="stats"
|
||||
href={getWeaponDestinationUrl("stats", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<ChartColumnBig size={20} />
|
||||
<span className={styles.resultName}>
|
||||
@@ -169,7 +181,11 @@ export function WeaponDestinationMenu({
|
||||
</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="analyzer" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="analyzer"
|
||||
href={getWeaponDestinationUrl("analyzer", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<Calculator size={20} />
|
||||
<span className={styles.resultName}>
|
||||
@@ -177,19 +193,31 @@ export function WeaponDestinationMenu({
|
||||
</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="vods" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="vods"
|
||||
href={getWeaponDestinationUrl("vods", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<Videotape size={20} />
|
||||
<span className={styles.resultName}>{t("common:pages.vods")}</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="art" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="art"
|
||||
href={getWeaponDestinationUrl("art", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<ImageIcon size={20} />
|
||||
<span className={styles.resultName}>{t("common:pages.art")}</span>
|
||||
</div>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem id="lfg" className={styles.listBoxItem}>
|
||||
<ListBoxItem
|
||||
id="lfg"
|
||||
href={getWeaponDestinationUrl("lfg", selectedWeapon)}
|
||||
className={styles.listBoxItem}
|
||||
>
|
||||
<div className={styles.resultItem}>
|
||||
<Users size={20} />
|
||||
<span className={styles.resultName}>{t("common:pages.lfg")}</span>
|
||||
|
||||
Reference in New Issue
Block a user