Commit 7019554e authored by tom goriunov's avatar tom goriunov Committed by GitHub

Dim out page to focus on a search (#1711)

* Dim out page to focus on a search

Fixes #1682

* add backdrop to search results page

* refactoring
parent 4dc76f69
...@@ -46,6 +46,11 @@ NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout ...@@ -46,6 +46,11 @@ NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_AD_BANNER_PROVIDER=hype NEXT_PUBLIC_AD_BANNER_PROVIDER=hype
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
#meta #meta
NEXT_PUBLIC_OG_IMAGE_URL=https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/eth.jpg?raw=true NEXT_PUBLIC_OG_IMAGE_URL=https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/eth.jpg?raw=true
...@@ -5,6 +5,7 @@ import React from 'react'; ...@@ -5,6 +5,7 @@ import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import { getRecentSearchKeywords } from 'lib/recentSearchKeywords'; import { getRecentSearchKeywords } from 'lib/recentSearchKeywords';
import SearchBarBackdrop from 'ui/snippets/searchBar/SearchBarBackdrop';
import SearchBarInput from 'ui/snippets/searchBar/SearchBarInput'; import SearchBarInput from 'ui/snippets/searchBar/SearchBarInput';
import SearchBarRecentKeywords from 'ui/snippets/searchBar/SearchBarRecentKeywords'; import SearchBarRecentKeywords from 'ui/snippets/searchBar/SearchBarRecentKeywords';
...@@ -66,33 +67,39 @@ const SearchResultsInput = ({ searchTerm, handleSubmit, handleSearchTermChange } ...@@ -66,33 +67,39 @@ const SearchResultsInput = ({ searchTerm, handleSubmit, handleSearchTermChange }
}; };
}, [ calculateMenuWidth ]); }, [ calculateMenuWidth ]);
const isSuggestOpen = isOpen && recentSearchKeywords.length > 0 && searchTerm.trim().length === 0;
return ( return (
<Popover <>
isOpen={ isOpen && recentSearchKeywords.length > 0 && searchTerm.trim().length === 0 } <Popover
autoFocus={ false } isOpen={ isSuggestOpen }
onClose={ onClose } autoFocus={ false }
placement="bottom-start" onClose={ onClose }
offset={ isMobile ? [ 16, -12 ] : undefined } placement="bottom-start"
isLazy offset={ isMobile ? [ 16, -12 ] : undefined }
> isLazy
<PopoverTrigger> >
<SearchBarInput <PopoverTrigger>
ref={ inputRef } <SearchBarInput
onChange={ handleSearchTermChange } ref={ inputRef }
onSubmit={ handleSubmit } onChange={ handleSearchTermChange }
onFocus={ handleFocus } onSubmit={ handleSubmit }
onBlur={ handleBlur } onFocus={ handleFocus }
onHide={ handelHide } onBlur={ handleBlur }
onClear={ handleClear } onHide={ handelHide }
value={ searchTerm } onClear={ handleClear }
/> value={ searchTerm }
</PopoverTrigger> isSuggestOpen={ isSuggestOpen }
<PopoverContent w={ `${ menuWidth.current }px` } maxH={{ base: '300px', lg: '500px' }} overflowY="scroll" ref={ menuRef }> />
<PopoverBody py={ 6 }> </PopoverTrigger>
<SearchBarRecentKeywords onClick={ handleSearchTermChange } onClear={ onClose }/> <PopoverContent w={ `${ menuWidth.current }px` } maxH={{ base: '300px', lg: '500px' }} overflowY="scroll" ref={ menuRef }>
</PopoverBody> <PopoverBody py={ 6 }>
</PopoverContent> <SearchBarRecentKeywords onClick={ handleSearchTermChange } onClear={ onClose }/>
</Popover> </PopoverBody>
</PopoverContent>
</Popover>
<SearchBarBackdrop isOpen={ isSuggestOpen }/>
</>
); );
}; };
......
import { Box, Portal, Popover, PopoverTrigger, PopoverContent, PopoverBody, useDisclosure, PopoverFooter, useOutsideClick } from '@chakra-ui/react'; import {
Box,
Portal,
Popover,
PopoverTrigger,
PopoverContent,
PopoverBody,
PopoverFooter,
useDisclosure,
useOutsideClick,
} from '@chakra-ui/react';
import _debounce from 'lodash/debounce'; import _debounce from 'lodash/debounce';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import type { FormEvent } from 'react'; import type { FormEvent } from 'react';
...@@ -12,6 +22,7 @@ import * as mixpanel from 'lib/mixpanel/index'; ...@@ -12,6 +22,7 @@ import * as mixpanel from 'lib/mixpanel/index';
import { getRecentSearchKeywords, saveToRecentKeywords } from 'lib/recentSearchKeywords'; import { getRecentSearchKeywords, saveToRecentKeywords } from 'lib/recentSearchKeywords';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import SearchBarBackdrop from './SearchBarBackdrop';
import SearchBarInput from './SearchBarInput'; import SearchBarInput from './SearchBarInput';
import SearchBarRecentKeywords from './SearchBarRecentKeywords'; import SearchBarRecentKeywords from './SearchBarRecentKeywords';
import SearchBarSuggest from './SearchBarSuggest/SearchBarSuggest'; import SearchBarSuggest from './SearchBarSuggest/SearchBarSuggest';
...@@ -106,69 +117,73 @@ const SearchBar = ({ isHomepage }: Props) => { ...@@ -106,69 +117,73 @@ const SearchBar = ({ isHomepage }: Props) => {
}, [ calculateMenuWidth ]); }, [ calculateMenuWidth ]);
return ( return (
<Popover <>
isOpen={ isOpen && (searchTerm.trim().length > 0 || recentSearchKeywords.length > 0) } <Popover
autoFocus={ false } isOpen={ isOpen && (searchTerm.trim().length > 0 || recentSearchKeywords.length > 0) }
onClose={ onClose } autoFocus={ false }
placement="bottom-start" onClose={ onClose }
offset={ isMobile && !isHomepage ? [ 16, -4 ] : undefined } placement="bottom-start"
isLazy offset={ isMobile && !isHomepage ? [ 16, -4 ] : undefined }
> isLazy
<PopoverTrigger> >
<SearchBarInput <PopoverTrigger>
ref={ inputRef } <SearchBarInput
onChange={ handleSearchTermChange } ref={ inputRef }
onSubmit={ handleSubmit } onChange={ handleSearchTermChange }
onFocus={ handleFocus } onSubmit={ handleSubmit }
onHide={ handelHide } onFocus={ handleFocus }
onClear={ handleClear } onHide={ handelHide }
isHomepage={ isHomepage } onClear={ handleClear }
value={ searchTerm } isHomepage={ isHomepage }
/> value={ searchTerm }
</PopoverTrigger> isSuggestOpen={ isOpen }
<Portal> />
<PopoverContent </PopoverTrigger>
w={ `${ menuWidth.current }px` } <Portal>
ref={ menuRef } <PopoverContent
> w={ `${ menuWidth.current }px` }
<PopoverBody ref={ menuRef }
p={ 0 }
color="chakra-body-text"
> >
<Box <PopoverBody
maxH="50vh" p={ 0 }
overflowY="auto" color="chakra-body-text"
id={ SCROLL_CONTAINER_ID }
ref={ scrollRef }
as={ Element }
px={ 4 }
> >
{ searchTerm.trim().length === 0 && recentSearchKeywords.length > 0 && ( <Box
<SearchBarRecentKeywords onClick={ handleSearchTermChange } onClear={ onClose }/> maxH="50vh"
) } overflowY="auto"
{ searchTerm.trim().length > 0 && ( id={ SCROLL_CONTAINER_ID }
<SearchBarSuggest ref={ scrollRef }
query={ query } as={ Element }
searchTerm={ debouncedSearchTerm } px={ 4 }
onItemClick={ handleItemClick }
containerId={ SCROLL_CONTAINER_ID }
/>
) }
</Box>
</PopoverBody>
{ searchTerm.trim().length > 0 && query.data && query.data.length >= 50 && (
<PopoverFooter>
<LinkInternal
href={ route({ pathname: '/search-results', query: { q: searchTerm } }) }
fontSize="sm"
> >
View all results { searchTerm.trim().length === 0 && recentSearchKeywords.length > 0 && (
</LinkInternal> <SearchBarRecentKeywords onClick={ handleSearchTermChange } onClear={ onClose }/>
</PopoverFooter> ) }
) } { searchTerm.trim().length > 0 && (
</PopoverContent> <SearchBarSuggest
</Portal> query={ query }
</Popover> searchTerm={ debouncedSearchTerm }
onItemClick={ handleItemClick }
containerId={ SCROLL_CONTAINER_ID }
/>
) }
</Box>
</PopoverBody>
{ searchTerm.trim().length > 0 && query.data && query.data.length >= 50 && (
<PopoverFooter>
<LinkInternal
href={ route({ pathname: '/search-results', query: { q: searchTerm } }) }
fontSize="sm"
>
View all results
</LinkInternal>
</PopoverFooter>
) }
</PopoverContent>
</Portal>
</Popover>
<SearchBarBackdrop isOpen={ isOpen }/>
</>
); );
}; };
......
import { Box, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
interface Props {
isOpen: boolean;
}
const SearchBarBackdrop = ({ isOpen }: Props) => {
const backdropBgColor = useColorModeValue('blackAlpha.400', 'blackAlpha.600');
return (
<Box
position="fixed"
top={ 0 }
left={ 0 }
w="100vw"
h="100vh"
bgColor={ backdropBgColor }
zIndex="overlay"
display={{ base: 'none', lg: isOpen ? 'block' : 'none' }}
/>
);
};
export default React.memo(SearchBarBackdrop);
...@@ -16,10 +16,14 @@ interface Props { ...@@ -16,10 +16,14 @@ interface Props {
onHide?: () => void; onHide?: () => void;
onClear: () => void; onClear: () => void;
isHomepage?: boolean; isHomepage?: boolean;
isSuggestOpen?: boolean;
value: string; value: string;
} }
const SearchBarInput = ({ onChange, onSubmit, isHomepage, onFocus, onBlur, onHide, onClear, value }: Props, ref: React.ForwardedRef<HTMLFormElement>) => { const SearchBarInput = (
{ onChange, onSubmit, isHomepage, isSuggestOpen, onFocus, onBlur, onHide, onClear, value }: Props,
ref: React.ForwardedRef<HTMLFormElement>,
) => {
const innerRef = React.useRef<HTMLFormElement>(null); const innerRef = React.useRef<HTMLFormElement>(null);
React.useImperativeHandle(ref, () => innerRef.current as HTMLFormElement, []); React.useImperativeHandle(ref, () => innerRef.current as HTMLFormElement, []);
const [ isSticky, setIsSticky ] = React.useState(false); const [ isSticky, setIsSticky ] = React.useState(false);
...@@ -71,10 +75,10 @@ const SearchBarInput = ({ onChange, onSubmit, isHomepage, onFocus, onBlur, onHid ...@@ -71,10 +75,10 @@ const SearchBarInput = ({ onChange, onSubmit, isHomepage, onFocus, onBlur, onHid
w="100%" w="100%"
backgroundColor={ bgColor } backgroundColor={ bgColor }
borderRadius={{ base: isHomepage ? 'base' : 'none', lg: 'base' }} borderRadius={{ base: isHomepage ? 'base' : 'none', lg: 'base' }}
position={{ base: isHomepage ? 'static' : 'absolute', lg: 'static' }} position={{ base: isHomepage ? 'static' : 'absolute', lg: 'relative' }}
top={{ base: isHomepage ? 0 : 55, lg: 0 }} top={{ base: isHomepage ? 0 : 55, lg: 0 }}
left="0" left="0"
zIndex={{ base: isHomepage ? 'auto' : '-1', lg: 'auto' }} zIndex={{ base: isHomepage ? 'auto' : '-1', lg: isSuggestOpen ? 'popover' : 'auto' }}
paddingX={{ base: isHomepage ? 0 : 4, lg: 0 }} paddingX={{ base: isHomepage ? 0 : 4, lg: 0 }}
paddingTop={{ base: isHomepage ? 0 : 1, lg: 0 }} paddingTop={{ base: isHomepage ? 0 : 1, lg: 0 }}
paddingBottom={{ base: isHomepage ? 0 : 2, lg: 0 }} paddingBottom={{ base: isHomepage ? 0 : 2, lg: 0 }}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment