pl-fe: migrate search to react-query
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
@ -20,6 +20,7 @@ interface IAutosuggestAccountInput {
|
||||
menu?: Menu;
|
||||
onKeyDown?: React.KeyboardEventHandler;
|
||||
theme?: InputThemes;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const AutosuggestAccountInput: React.FC<IAutosuggestAccountInput> = ({
|
||||
|
||||
112
packages/pl-fe/src/components/search-input.tsx
Normal file
112
packages/pl-fe/src/components/search-input.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
import AutosuggestAccountInput from 'pl-fe/components/autosuggest-account-input';
|
||||
import SvgIcon from 'pl-fe/components/ui/svg-icon';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { selectAccount } from 'pl-fe/selectors';
|
||||
import { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
|
||||
action: { id: 'search.action', defaultMessage: 'Search for “{query}”' },
|
||||
});
|
||||
|
||||
const redirectToAccount = (accountId: string, routerHistory: any) =>
|
||||
(_dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const acct = selectAccount(getState(), accountId)!.acct;
|
||||
|
||||
if (acct && routerHistory) {
|
||||
routerHistory.push(`/@${acct}`);
|
||||
}
|
||||
};
|
||||
|
||||
const SearchInput = () => {
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const history = useHistory();
|
||||
const intl = useIntl();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
const handleClear = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
setValue('');
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
setValue('');
|
||||
history.push('/search?' + new URLSearchParams({ q: value }));
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
|
||||
handleSubmit();
|
||||
} else if (event.key === 'Escape') {
|
||||
document.querySelector('.ui')?.parentElement?.focus();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelected = (accountId: string) => {
|
||||
setValue('');
|
||||
dispatch(redirectToAccount(accountId, history));
|
||||
};
|
||||
|
||||
const makeMenu = () => [
|
||||
{
|
||||
text: intl.formatMessage(messages.action, { query: value }),
|
||||
icon: require('@tabler/icons/outline/search.svg'),
|
||||
action: handleSubmit,
|
||||
},
|
||||
];
|
||||
|
||||
const hasValue = value.length > 0;
|
||||
|
||||
return (
|
||||
<div className='w-full'>
|
||||
<label htmlFor='search' className='sr-only'>{intl.formatMessage(messages.placeholder)}</label>
|
||||
|
||||
<div className='relative'>
|
||||
<AutosuggestAccountInput
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onSelected={handleSelected}
|
||||
menu={makeMenu()}
|
||||
autoSelect={false}
|
||||
theme='search'
|
||||
className='pr-10 rtl:pl-10 rtl:pr-3'
|
||||
/>
|
||||
|
||||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
className='absolute inset-y-0 right-0 flex cursor-pointer items-center px-3 rtl:left-0 rtl:right-auto'
|
||||
onClick={handleClear}
|
||||
>
|
||||
<SvgIcon
|
||||
src={require('@tabler/icons/outline/search.svg')}
|
||||
className={clsx('size-4 text-gray-600', { hidden: hasValue })}
|
||||
/>
|
||||
|
||||
<SvgIcon
|
||||
src={require('@tabler/icons/outline/x.svg')}
|
||||
className={clsx('size-4 text-gray-600', { hidden: !hasValue })}
|
||||
aria-label={intl.formatMessage(messages.placeholder)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { SearchInput as default };
|
||||
@ -5,7 +5,6 @@ import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-intera
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import { useStatContext } from 'pl-fe/contexts/stat-context';
|
||||
import Search from 'pl-fe/features/search/components/search';
|
||||
import ComposeButton from 'pl-fe/features/ui/components/compose-button';
|
||||
import ProfileDropdown from 'pl-fe/features/ui/components/profile-dropdown';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
@ -18,6 +17,7 @@ import { useSettings } from 'pl-fe/hooks/use-settings';
|
||||
|
||||
import Account from './account';
|
||||
import DropdownMenu, { Menu } from './dropdown-menu';
|
||||
import SearchInput from './search-input';
|
||||
import SidebarNavigationLink from './sidebar-navigation-link';
|
||||
import SiteLogo from './site-logo';
|
||||
|
||||
@ -176,7 +176,7 @@ const SidebarNavigation = () => {
|
||||
</ProfileDropdown>
|
||||
</div>
|
||||
<div className='block w-full max-w-xs'>
|
||||
<Search openInRoute autosuggest />
|
||||
<SearchInput />
|
||||
</div>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user