1
0
mirror of https://github.com/uetchy/namae.git synced 2025-08-20 18:08:11 +09:00

feat: persistent search result

This commit is contained in:
2020-02-05 15:59:53 +09:00
parent 9187b817af
commit 6f5099d00c
9 changed files with 1775 additions and 1823 deletions

View File

@@ -1,15 +1,19 @@
import React, {useState, useRef, useEffect} from 'react';
import styled from 'styled-components';
import {useTranslation} from 'react-i18next';
import {Link, useHistory} from 'react-router-dom';
import {sendQueryStatistics} from '../util/analytics';
import {useDeferredState} from '../util/hooks';
import {mobile} from '../util/css';
import Suggestion from './Suggestion';
const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
const Form: React.FC<{
initialValue?: string;
}> = ({initialValue = ''}) => {
const history = useHistory();
const [query, setQuery] = useDeferredState(800, '');
const [inputValue, setInputValue] = useState('');
const [inputValue, setInputValue] = useState(initialValue);
const [suggested, setSuggested] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const {t} = useTranslation();
@@ -23,7 +27,8 @@ const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
// clear input form and focus on it
function onLogoClick(): void {
setInputValue('');
inputRef.current?.focus();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
inputRef.current!.focus();
}
// invoke when user clicked one of the suggested items
@@ -35,11 +40,20 @@ const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
const queryGiven = query && query.length > 0;
useEffect(() => {
function onQuery(query: string) {
if (!query || query === '') {
return;
}
sendQueryStatistics(query.length);
history.push(`/s/${query}`);
}
if (query.length === 0) {
setSuggested(false);
} else {
onQuery(query);
}
onQuery(query);
}, [query, onQuery]);
}, [query, history]);
useEffect(() => {
const modifiedValue = inputValue.replace(/[\s@+!#$%^&*()[\]]/g, '');
@@ -48,7 +62,9 @@ const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
return (
<InputContainer>
<Logo onClick={onLogoClick}>namæ</Logo>
<Logo onClick={onLogoClick}>
<Link to="/">namæ</Link>
</Logo>
<InputView
onChange={onInputChange}
value={inputValue}
@@ -89,6 +105,14 @@ const Logo = styled.div`
${mobile} {
font-size: 15px;
}
a:link,
a:hover,
a:active,
a:visited {
text-decoration: none;
color: #4a90e2;
}
`;
const InputView = styled.input.attrs({

View File

@@ -121,9 +121,13 @@ const Suggestion: React.FC<{
}
useEffect(() => {
let isEffective = true;
const fn = async (): Promise<void> => {
if (query && query.length > 0) {
const synonyms = await findSynonyms(query);
if (!isEffective) {
return;
}
synonymRef.current = synonyms;
const best = fillArray(
sampleFromArray(synonyms, maximumCount),
@@ -134,6 +138,9 @@ const Suggestion: React.FC<{
}
};
fn();
return () => {
isEffective = false;
};
}, [query]);
return (
@@ -141,15 +148,15 @@ const Suggestion: React.FC<{
<Title>{t('try')}</Title>
<Items>
{bestWords &&
bestWords.map((name) => (
<Item key={name} onClick={(): void => applyQuery(name)}>
bestWords.map((name, i) => (
<Item key={name + i} onClick={(): void => applyQuery(name)}>
{name}
</Item>
))}
<Icon>
<TiArrowSync onClick={shuffle} />
</Icon>
</Items>
<Icon>
<TiArrowSync onClick={shuffle} />
</Icon>
</Container>
);
};