Merge pull request #4 from tribalwarshelp/global-search-context
add GlobalSearch lib
This commit is contained in:
commit
85b6aa5814
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import { StringParam, useQueryParam, withDefault } from 'use-query-params';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { TWHELP, NAME } from '@config/app';
|
||||
|
@ -20,7 +19,7 @@ import {
|
|||
import { Input as InputIcon } from '@material-ui/icons';
|
||||
import Link from '@common/Link/Link';
|
||||
import VersionSelector from '@common/VersionSelector/VersionSelector';
|
||||
import SearchInput from './SearchInput';
|
||||
import SearchInput from '@libs/GlobalSearch/SearchInput';
|
||||
|
||||
export interface Props {
|
||||
appBarProps?: AppBarProps;
|
||||
|
@ -30,7 +29,6 @@ export default function Header({ appBarProps = {} }: Props) {
|
|||
const { t } = useTranslation(NAMESPACES.COMMON);
|
||||
const location = useLocation();
|
||||
const classes = useStyles();
|
||||
const [q] = useQueryParam('q', withDefault(StringParam, ''));
|
||||
|
||||
const versionSelector = (
|
||||
<div>
|
||||
|
@ -42,9 +40,7 @@ export default function Header({ appBarProps = {} }: Props) {
|
|||
<Container>
|
||||
<Toolbar disableGutters className={classes.toolbar}>
|
||||
<form className={classes.form}>
|
||||
<SearchInput
|
||||
defaultQ={location.pathname === ROUTES.SEARCH_PAGE ? q : ''}
|
||||
/>
|
||||
<SearchInput />
|
||||
</form>
|
||||
{location.pathname !== ROUTES.INDEX_PAGE && (
|
||||
<Link to={ROUTES.INDEX_PAGE}>
|
||||
|
|
|
@ -24,7 +24,7 @@ import {
|
|||
Fireplace as FireplaceIcon,
|
||||
} from '@material-ui/icons';
|
||||
import DevNote from '@common/DevNote/DevNote';
|
||||
import SearchInput from '@common/MainLayout/components/Header/SearchInput';
|
||||
import SearchInput from '@libs/GlobalSearch/SearchInput';
|
||||
import Nav from './components/Nav/Nav';
|
||||
import ServerInfo from './components/ServerInfo/ServerInfo';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { Menu as MenuIcon, Input as InputIcon } from '@material-ui/icons';
|
||||
import VersionSelector from '@common/VersionSelector/VersionSelector';
|
||||
import Link from '@common/Link/Link';
|
||||
import SearchInput from '@common/MainLayout/components/Header/SearchInput';
|
||||
import SearchInput from '@libs/GlobalSearch/SearchInput';
|
||||
|
||||
export interface Props {
|
||||
className?: string;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { ApolloProvider } from '@apollo/client';
|
|||
import { BrowserRouter, Route } from 'react-router-dom';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { QueryParamProvider } from 'use-query-params';
|
||||
import GlobalSearchProvider from './libs/GlobalSearch/Provider';
|
||||
import App from './features/App';
|
||||
import createTheme from './theme/createTheme';
|
||||
import createGraphQLClient from './libs/graphql/createClient';
|
||||
|
@ -20,7 +21,9 @@ const jsx = (
|
|||
<I18nextProvider i18n={initI18N()}>
|
||||
<ApolloProvider client={createGraphQLClient(API_URI)}>
|
||||
<QueryParamProvider ReactRouterRoute={Route}>
|
||||
<App />
|
||||
<GlobalSearchProvider>
|
||||
<App />
|
||||
</GlobalSearchProvider>
|
||||
</QueryParamProvider>
|
||||
</ApolloProvider>
|
||||
</I18nextProvider>
|
||||
|
|
32
src/libs/GlobalSearch/Provider.tsx
Normal file
32
src/libs/GlobalSearch/Provider.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { useQueryParam, StringParam, withDefault } from 'use-query-params';
|
||||
import { SEARCH_PAGE } from '@config/routes';
|
||||
|
||||
import Context from './context';
|
||||
|
||||
export interface Props {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
function Provider({ children, ...rest }: Props) {
|
||||
const [defaultQ] = useQueryParam('q', withDefault(StringParam, ''));
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const [q, setQ] = useState<string>(
|
||||
location.pathname === SEARCH_PAGE ? defaultQ : ''
|
||||
);
|
||||
const href = SEARCH_PAGE + `?q=${encodeURIComponent(q)}`;
|
||||
|
||||
const goToSearchPage = () => {
|
||||
history.push(href);
|
||||
};
|
||||
|
||||
return (
|
||||
<Context.Provider value={{ q, setQ, href, goToSearchPage }}>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default Provider;
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as ROUTES from '@config/routes';
|
||||
import useGlobalSearch from './useGlobalSearch';
|
||||
import * as NAMESPACES from '@config/namespaces';
|
||||
|
||||
import { InputAdornment, IconButton, TextFieldProps } from '@material-ui/core';
|
||||
|
@ -8,13 +8,9 @@ import { Search as SearchIcon } from '@material-ui/icons';
|
|||
import SearchInput from '@common/Form/SearchInput';
|
||||
import Link from '@common/Link/Link';
|
||||
|
||||
export type Props = TextFieldProps & {
|
||||
defaultQ?: string;
|
||||
};
|
||||
|
||||
function HeaderSearchInput({ defaultQ = '', ...rest }: Props) {
|
||||
function CustomizedSearchInput(props: TextFieldProps) {
|
||||
const { t } = useTranslation(NAMESPACES.COMMON);
|
||||
const [q, setQ] = useState<string>(defaultQ);
|
||||
const { q, setQ, href } = useGlobalSearch();
|
||||
const trimmedQLength = q.trim().length;
|
||||
const iconButton = (
|
||||
<IconButton size="small" type="submit" disabled={trimmedQLength === 0}>
|
||||
|
@ -26,9 +22,9 @@ function HeaderSearchInput({ defaultQ = '', ...rest }: Props) {
|
|||
<SearchInput
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
placeholder={t<string>('mainLayout.header.search')}
|
||||
placeholder={t<string>('globalSearch.searchInput.placeholder')}
|
||||
size="small"
|
||||
{...rest}
|
||||
{...props}
|
||||
value={q}
|
||||
onChange={e => {
|
||||
setQ(e.target.value);
|
||||
|
@ -36,13 +32,7 @@ function HeaderSearchInput({ defaultQ = '', ...rest }: Props) {
|
|||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
{trimmedQLength ? (
|
||||
<Link to={ROUTES.SEARCH_PAGE + `?q=${encodeURIComponent(q)}`}>
|
||||
{iconButton}
|
||||
</Link>
|
||||
) : (
|
||||
iconButton
|
||||
)}
|
||||
{trimmedQLength ? <Link to={href}>{iconButton}</Link> : iconButton}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
|
@ -51,4 +41,4 @@ function HeaderSearchInput({ defaultQ = '', ...rest }: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
export default HeaderSearchInput;
|
||||
export default CustomizedSearchInput;
|
11
src/libs/GlobalSearch/context.ts
Normal file
11
src/libs/GlobalSearch/context.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { createContext } from 'react';
|
||||
import { ContextValue } from './types';
|
||||
|
||||
const ctx = createContext<ContextValue>({
|
||||
href: '',
|
||||
q: '',
|
||||
setQ: (v: string) => {},
|
||||
goToSearchPage: () => {},
|
||||
});
|
||||
|
||||
export default ctx;
|
6
src/libs/GlobalSearch/types.ts
Normal file
6
src/libs/GlobalSearch/types.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export type ContextValue = {
|
||||
href: string;
|
||||
q: string;
|
||||
setQ: (v: string) => void;
|
||||
goToSearchPage: () => void;
|
||||
};
|
9
src/libs/GlobalSearch/useGlobalSearch.ts
Normal file
9
src/libs/GlobalSearch/useGlobalSearch.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { useContext } from 'react';
|
||||
import ctx from './context';
|
||||
import { ContextValue } from './types';
|
||||
|
||||
const useGlobalSearch = (): ContextValue => {
|
||||
return useContext(ctx);
|
||||
};
|
||||
|
||||
export default useGlobalSearch;
|
|
@ -17,10 +17,14 @@ const translations = {
|
|||
loading: 'Loading version...',
|
||||
},
|
||||
devNote: `This website is still under development and some things may be broken.`,
|
||||
globalSearch: {
|
||||
searchInput: {
|
||||
placeholder: 'Search',
|
||||
},
|
||||
},
|
||||
mainLayout: {
|
||||
header: {
|
||||
home: 'Home',
|
||||
search: 'Search',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,10 +17,14 @@ const translations = {
|
|||
loading: 'Ładowanie wersji...',
|
||||
},
|
||||
devNote: `Strona jest ciągle w procesie tworzenia i mogą występować błędy.`,
|
||||
globalSearch: {
|
||||
searchInput: {
|
||||
placeholder: 'Wyszukaj',
|
||||
},
|
||||
},
|
||||
mainLayout: {
|
||||
header: {
|
||||
home: 'Strona główna',
|
||||
search: 'Wyszukaj',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,6 +17,11 @@ const translations = {
|
|||
loading: 'Carregando a versão...',
|
||||
},
|
||||
devNote: `Este site ainda está em desenvolvimento e poder conter erros.`,
|
||||
globalSearch: {
|
||||
searchInput: {
|
||||
placeholder: 'Pesquisa',
|
||||
},
|
||||
},
|
||||
mainLayout: {
|
||||
header: {
|
||||
home: 'Início',
|
||||
|
|
|
@ -17,6 +17,11 @@ const translations = {
|
|||
loading: 'Carregando a versão...',
|
||||
},
|
||||
devNote: `Este site ainda está sendo desenvolvido e pode conter algum erro.`,
|
||||
globalSearch: {
|
||||
searchInput: {
|
||||
placeholder: 'Pesquisa',
|
||||
},
|
||||
},
|
||||
mainLayout: {
|
||||
header: {
|
||||
home: 'Página inicial',
|
||||
|
|
Reference in New Issue
Block a user