SearchInput: Add keyboard shortcuts with platform detection
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
"react-dom": "^17.0.1",
|
||||
"react-dropdown-select": "^4.4.2",
|
||||
"react-ga": "^3.1.2",
|
||||
"react-hotkeys-hook": "^3.2.1",
|
||||
"react-scripts": "3.4.1",
|
||||
"react-use": "^15.3.2",
|
||||
"recoil": "^0.1.2",
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.search-bar:focus-within .keys {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-bar input {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
border: none;
|
||||
margin-left: 12px;
|
||||
margin: 0 12px;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
@@ -48,6 +52,13 @@
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.keys {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-width: 42px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 558px) {
|
||||
#search-icon {
|
||||
display: none;
|
||||
@@ -58,3 +69,9 @@
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 858px) and (max-width: 1100px) {
|
||||
.search-bar {
|
||||
flex-basis: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useRef, MutableRefObject } from "react";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useDebounce } from "react-use";
|
||||
import { MagnifyingGlass, X, HourglassHigh } from "phosphor-react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { Command, MagnifyingGlass, X, HourglassHigh } from "phosphor-react";
|
||||
import ReactGA from "react-ga";
|
||||
|
||||
import { searchQueryAtom } from "../../state/atoms";
|
||||
@@ -12,6 +13,24 @@ type SearchInputProps = {};
|
||||
const SearchInput: React.FC<SearchInputProps> = () => {
|
||||
const [value, setValue] = useState<string>("");
|
||||
const [query, setQuery] = useRecoilState(searchQueryAtom);
|
||||
const inputRef = useRef<HTMLInputElement>() as MutableRefObject<HTMLInputElement>;
|
||||
const isMobile = useRef<boolean>(false) as MutableRefObject<boolean>;
|
||||
const isApple = useRef<boolean>(false) as MutableRefObject<boolean>;
|
||||
|
||||
useEffect(() => {
|
||||
const apple = /iPhone|iPod|iPad|Macintosh|MacIntel|MacPPC/i;
|
||||
const mobile = /Android|iPhone|iPod|iPad|Opera Mini|IEMobile/i;
|
||||
isApple.current = apple.test(window.navigator.platform);
|
||||
isMobile.current = mobile.test(window.navigator.userAgent);
|
||||
}, [isApple, isMobile]);
|
||||
|
||||
useHotkeys("ctrl+k,cmd+k", (e) => {
|
||||
e.preventDefault();
|
||||
if (!e.repeat) {
|
||||
inputRef.current?.focus();
|
||||
inputRef.current.select();
|
||||
}
|
||||
});
|
||||
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
useEffect(() => {
|
||||
@@ -28,9 +47,11 @@ const SearchInput: React.FC<SearchInputProps> = () => {
|
||||
() => {
|
||||
if (value !== query) {
|
||||
setQuery(value);
|
||||
!!value && ReactGA.event({ category: "Search", action: "Query", label: value });
|
||||
!!value &&
|
||||
ReactGA.event({ category: "Search", action: "Query", label: value });
|
||||
}
|
||||
!!value && void document
|
||||
!!value &&
|
||||
void document
|
||||
.getElementById("beacon")
|
||||
?.scrollIntoView({ block: "start", behavior: "smooth" });
|
||||
},
|
||||
@@ -49,6 +70,7 @@ const SearchInput: React.FC<SearchInputProps> = () => {
|
||||
<div className="search-bar">
|
||||
<MagnifyingGlass id="search-icon" size={24} />
|
||||
<input
|
||||
ref={inputRef}
|
||||
id="search-input"
|
||||
title="Search for icon names, categories, or keywords"
|
||||
aria-label="Search for an icon"
|
||||
@@ -62,6 +84,9 @@ const SearchInput: React.FC<SearchInputProps> = () => {
|
||||
key === "Enter" && currentTarget.blur()
|
||||
}
|
||||
/>
|
||||
{!value && !isMobile.current && (
|
||||
<Keys>{isApple.current ? <Command /> : "Ctrl"} + K</Keys>
|
||||
)}
|
||||
{value ? (
|
||||
isReady() ? (
|
||||
<X className="clear-icon" size={18} onClick={handleCancelSearch} />
|
||||
@@ -73,4 +98,8 @@ const SearchInput: React.FC<SearchInputProps> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Keys: React.FC<{}> = ({ children }) => (
|
||||
<div className="keys">{children}</div>
|
||||
);
|
||||
|
||||
export default SearchInput;
|
||||
|
||||
Reference in New Issue
Block a user