pretty UI for zone search suggestions
This commit is contained in:
parent
10563629ef
commit
479f43ed22
3 changed files with 52 additions and 9 deletions
|
@ -4,7 +4,6 @@ import { Box, Flex } from "@chakra-ui/core";
|
||||||
import ItemsPanel from "./ItemsPanel";
|
import ItemsPanel from "./ItemsPanel";
|
||||||
import SearchToolbar from "./SearchToolbar";
|
import SearchToolbar from "./SearchToolbar";
|
||||||
import SearchPanel from "./SearchPanel";
|
import SearchPanel from "./SearchPanel";
|
||||||
import { isNullableType } from "graphql";
|
|
||||||
|
|
||||||
const emptyQuery = { value: "", filterToZoneLabel: null };
|
const emptyQuery = { value: "", filterToZoneLabel: null };
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ function ItemsAndSearchPanels({ loading, outfitState, dispatchToOutfit }) {
|
||||||
query={searchQuery}
|
query={searchQuery}
|
||||||
searchQueryRef={searchQueryRef}
|
searchQueryRef={searchQueryRef}
|
||||||
firstSearchResultRef={firstSearchResultRef}
|
firstSearchResultRef={firstSearchResultRef}
|
||||||
onChange={setSearchQuery}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{searchQuery.value || searchQuery.filterToZoneLabel ? (
|
{searchQuery.value || searchQuery.filterToZoneLabel ? (
|
||||||
|
@ -50,7 +49,7 @@ function ItemsAndSearchPanels({ loading, outfitState, dispatchToOutfit }) {
|
||||||
overflow="auto"
|
overflow="auto"
|
||||||
ref={scrollContainerRef}
|
ref={scrollContainerRef}
|
||||||
>
|
>
|
||||||
<Box px="4" py="5">
|
<Box px="4" py="2">
|
||||||
<SearchPanel
|
<SearchPanel
|
||||||
query={searchQuery.value}
|
query={searchQuery.value}
|
||||||
outfitState={outfitState}
|
outfitState={outfitState}
|
||||||
|
@ -68,7 +67,7 @@ function ItemsAndSearchPanels({ loading, outfitState, dispatchToOutfit }) {
|
||||||
overflow="auto"
|
overflow="auto"
|
||||||
key="items-panel"
|
key="items-panel"
|
||||||
>
|
>
|
||||||
<Box px="4" py="5">
|
<Box px="4" py="2">
|
||||||
<ItemsPanel
|
<ItemsPanel
|
||||||
loading={loading}
|
loading={loading}
|
||||||
outfitState={outfitState}
|
outfitState={outfitState}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import gql from "graphql-tag";
|
||||||
import { Box, Text, VisuallyHidden } from "@chakra-ui/core";
|
import { Box, Text, VisuallyHidden } from "@chakra-ui/core";
|
||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
|
|
||||||
import { Delay, Heading1, useDebounce } from "../util";
|
import { Delay, useDebounce } from "../util";
|
||||||
import Item, { ItemListContainer, ItemListSkeleton } from "./Item";
|
import Item, { ItemListContainer, ItemListSkeleton } from "./Item";
|
||||||
import { itemAppearanceFragment } from "../components/useOutfitAppearance";
|
import { itemAppearanceFragment } from "../components/useOutfitAppearance";
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ function SearchPanel({
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Heading1 mb="4">Searching for "{query}"</Heading1>
|
|
||||||
<SearchResults
|
<SearchResults
|
||||||
query={query}
|
query={query}
|
||||||
outfitState={outfitState}
|
outfitState={outfitState}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
} from "@chakra-ui/core";
|
} from "@chakra-ui/core";
|
||||||
import { CloseIcon, SearchIcon } from "@chakra-ui/icons";
|
import { CloseIcon, SearchIcon } from "@chakra-ui/icons";
|
||||||
import { css } from "emotion";
|
import { css, cx } from "emotion";
|
||||||
import Autosuggest from "react-autosuggest";
|
import Autosuggest from "react-autosuggest";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,13 +57,55 @@ function SearchToolbar({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const suggestionBgColor = useColorModeValue("transparent", "whiteAlpha.100");
|
||||||
|
const highlightedBgColor = useColorModeValue("gray.100", "whiteAlpha.300");
|
||||||
|
|
||||||
const renderSuggestion = React.useCallback(
|
const renderSuggestion = React.useCallback(
|
||||||
(zoneLabel, { isHighlighted }) => (
|
(zoneLabel, { isHighlighted }) => (
|
||||||
<Box fontWeight={isHighlighted ? "bold" : "normal"}>{zoneLabel}</Box>
|
<Box
|
||||||
|
fontWeight={isHighlighted ? "bold" : "normal"}
|
||||||
|
background={isHighlighted ? highlightedBgColor : suggestionBgColor}
|
||||||
|
padding="2"
|
||||||
|
paddingLeft="2.5rem"
|
||||||
|
fontSize="sm"
|
||||||
|
>
|
||||||
|
{zoneLabel}
|
||||||
|
</Box>
|
||||||
),
|
),
|
||||||
|
[suggestionBgColor, highlightedBgColor]
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderSuggestionsContainer = React.useCallback(
|
||||||
|
({ containerProps, children }) => {
|
||||||
|
const { className, ...otherContainerProps } = containerProps;
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
{...otherContainerProps}
|
||||||
|
borderBottomRadius="md"
|
||||||
|
boxShadow="md"
|
||||||
|
overflow="hidden"
|
||||||
|
transition="all 0.4s"
|
||||||
|
className={cx(
|
||||||
|
className,
|
||||||
|
css`
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// When we change the filter zone, clear out the suggestions.
|
||||||
|
React.useEffect(() => {
|
||||||
|
setSuggestions([]);
|
||||||
|
}, [query.filterToZoneLabel]);
|
||||||
|
|
||||||
const focusBorderColor = useColorModeValue("green.600", "green.400");
|
const focusBorderColor = useColorModeValue("green.600", "green.400");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -83,7 +125,9 @@ function SearchToolbar({
|
||||||
}}
|
}}
|
||||||
getSuggestionValue={(zl) => zl}
|
getSuggestionValue={(zl) => zl}
|
||||||
shouldRenderSuggestions={() => query.filterToZoneLabel == null}
|
shouldRenderSuggestions={() => query.filterToZoneLabel == null}
|
||||||
|
highlightFirstSuggestion={true}
|
||||||
renderSuggestion={renderSuggestion}
|
renderSuggestion={renderSuggestion}
|
||||||
|
renderSuggestionsContainer={renderSuggestionsContainer}
|
||||||
renderInputComponent={(props) => (
|
renderInputComponent={(props) => (
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
{query.filterToZoneLabel ? (
|
{query.filterToZoneLabel ? (
|
||||||
|
@ -97,7 +141,7 @@ function SearchToolbar({
|
||||||
</InputLeftElement>
|
</InputLeftElement>
|
||||||
)}
|
)}
|
||||||
<Input {...props} />
|
<Input {...props} />
|
||||||
{query && (
|
{(query.value || query.filterToZoneLabel) && (
|
||||||
<InputRightElement>
|
<InputRightElement>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<CloseIcon />}
|
icon={<CloseIcon />}
|
||||||
|
@ -123,6 +167,7 @@ function SearchToolbar({
|
||||||
value: query.value || "",
|
value: query.value || "",
|
||||||
ref: searchQueryRef,
|
ref: searchQueryRef,
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
|
borderBottomRadius: suggestions.length > 0 ? "0" : "md",
|
||||||
// HACK: Chakra isn't noticing the InputLeftElement swapping out
|
// HACK: Chakra isn't noticing the InputLeftElement swapping out
|
||||||
// for the InputLeftAddon, so the styles aren't updating...
|
// for the InputLeftAddon, so the styles aren't updating...
|
||||||
// Hard override!
|
// Hard override!
|
||||||
|
|
Loading…
Reference in a new issue