fix(site): fix search menu for creating workspace and templates filter (#11674)

This commit is contained in:
Bruno Quaresma
2024-01-17 17:54:56 +00:00
committed by GitHub
parent b246f08d84
commit 1be119b08f
4 changed files with 131 additions and 103 deletions
+12 -48
View File
@@ -32,6 +32,12 @@ import { Loader } from "components/Loader/Loader";
import { useDebouncedFunction } from "hooks/debounce";
import { useFilterMenu } from "./menu";
import type { BaseOption } from "./options";
import {
Search,
SearchEmpty,
SearchInput,
searchStyles,
} from "components/Menu/Search";
export type PresetFilter = {
name: string;
@@ -489,7 +495,7 @@ export const FilterSearchMenu = <TOption extends BaseOption>({
onQueryChange={menu.setQuery}
renderOption={(option) => (
<MenuItem
key={option.label}
key={option.value}
selected={option.value === menu.selectedOption?.value}
onClick={() => {
menu.selectOption(option);
@@ -576,7 +582,6 @@ function SearchMenu<TOption extends BaseOption>({
}: SearchMenuProps<TOption>) {
const menuListRef = useRef<HTMLUListElement>(null);
const searchInputRef = useRef<HTMLInputElement>(null);
const theme = useTheme();
return (
<Menu
@@ -586,10 +591,7 @@ function SearchMenu<TOption extends BaseOption>({
onQueryChange("");
}}
css={{
"& .MuiPaper-root": {
width: 320,
padding: 0,
},
"& .MuiPaper-root": searchStyles.content,
}}
// Disabled this so when we clear the filter and do some sorting in the
// search items it does not look strange. Github removes exit transitions
@@ -606,44 +608,16 @@ function SearchMenu<TOption extends BaseOption>({
}
}}
>
<li
css={{
display: "flex",
alignItems: "center",
paddingLeft: 16,
height: 40,
borderBottom: `1px solid ${theme.palette.divider}`,
}}
>
<SearchOutlined
css={{
fontSize: 14,
color: theme.palette.text.secondary,
}}
/>
<input
tabIndex={-1}
type="text"
placeholder="Search..."
<Search component="li">
<SearchInput
autoFocus
value={query}
ref={searchInputRef}
onChange={(e) => {
onQueryChange(e.target.value);
}}
css={{
height: "100%",
border: 0,
background: "none",
width: "100%",
marginLeft: 16,
outline: 0,
"&::placeholder": {
color: theme.palette.text.secondary,
},
}}
/>
</li>
</Search>
<li css={{ maxHeight: 480, overflowY: "auto" }}>
<MenuList
@@ -660,17 +634,7 @@ function SearchMenu<TOption extends BaseOption>({
options.length > 0 ? (
options.map(renderOption)
) : (
<div
css={{
fontSize: 13,
color: theme.palette.text.secondary,
textAlign: "center",
paddingTop: 8,
paddingBottom: 8,
}}
>
No results
</div>
<SearchEmpty />
)
) : (
<Loader size={14} />
+100
View File
@@ -0,0 +1,100 @@
import SearchOutlined from "@mui/icons-material/SearchOutlined";
// eslint-disable-next-line no-restricted-imports -- use it to have the component prop
import Box, { BoxProps } from "@mui/material/Box";
import { Interpolation, Theme, useTheme } from "@mui/material/styles";
import visuallyHidden from "@mui/utils/visuallyHidden";
import { FC, HTMLAttributes, InputHTMLAttributes, forwardRef } from "react";
export const Search = forwardRef<HTMLElement, BoxProps>(
({ children, ...boxProps }, ref) => {
const theme = useTheme();
return (
<Box
ref={ref}
{...boxProps}
css={{
display: "flex",
alignItems: "center",
paddingLeft: 16,
height: 40,
borderBottom: `1px solid ${theme.palette.divider}`,
}}
>
<SearchOutlined
css={{
fontSize: 14,
color: theme.palette.text.secondary,
}}
/>
{children}
</Box>
);
},
);
type SearchInputProps = InputHTMLAttributes<HTMLInputElement> & {
label?: string;
};
export const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
({ label, ...inputProps }, ref) => {
const theme = useTheme();
return (
<>
<label css={{ ...visuallyHidden }} htmlFor={inputProps.id}>
{label}
</label>
<input
ref={ref}
tabIndex={-1}
type="text"
placeholder="Search..."
css={{
height: "100%",
border: 0,
background: "none",
flex: 1,
marginLeft: 16,
outline: 0,
"&::placeholder": {
color: theme.palette.text.secondary,
},
}}
{...inputProps}
/>
</>
);
},
);
export const SearchEmpty: FC<HTMLAttributes<HTMLDivElement>> = ({
children = "Not found",
...props
}) => {
const theme = useTheme();
return (
<div
css={{
fontSize: 13,
color: theme.palette.text.secondary,
textAlign: "center",
paddingTop: 8,
paddingBottom: 8,
}}
{...props}
>
{children}
</div>
);
};
export const searchStyles = {
content: {
width: 320,
padding: 0,
borderRadius: 4,
},
} satisfies Record<string, Interpolation<Theme>>;
@@ -11,7 +11,6 @@ import AddIcon from "@mui/icons-material/AddOutlined";
import OpenIcon from "@mui/icons-material/OpenInNewOutlined";
import { Loader } from "components/Loader/Loader";
import { OverflowY } from "components/OverflowY/OverflowY";
import { EmptyState } from "components/EmptyState/EmptyState";
import { Avatar } from "components/Avatar/Avatar";
import { SearchBox } from "./WorkspacesSearchBox";
import {
@@ -19,6 +18,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "components/Popover/Popover";
import { SearchEmpty, searchStyles } from "components/Menu/Search";
const ICON_SIZE = 18;
@@ -43,17 +43,15 @@ export const WorkspacesButton: FC<WorkspacesButtonProps> = ({
let emptyState: ReactNode = undefined;
if (templates?.length === 0) {
emptyState = (
<EmptyState
message="No templates yet"
cta={
<Link to="/templates" component={RouterLink}>
Create one now.
</Link>
}
/>
<SearchEmpty>
No templates yet.{" "}
<Link to="/templates" component={RouterLink}>
Create one now.
</Link>
</SearchEmpty>
);
} else if (processed.length === 0) {
emptyState = <EmptyState message="No templates match your text" />;
emptyState = <SearchEmpty>No templates found</SearchEmpty>;
}
return (
@@ -63,7 +61,12 @@ export const WorkspacesButton: FC<WorkspacesButtonProps> = ({
{children}
</Button>
</PopoverTrigger>
<PopoverContent horizontal="right">
<PopoverContent
horizontal="right"
css={{
".MuiPaper-root": searchStyles.content,
}}
>
<SearchBox
value={searchTerm}
onValueChange={(newValue) => setSearchTerm(newValue)}
@@ -11,9 +11,7 @@ import {
forwardRef,
useId,
} from "react";
import SearchIcon from "@mui/icons-material/SearchOutlined";
import { visuallyHidden } from "@mui/utils";
import { useTheme } from "@emotion/react";
import { Search, SearchInput } from "components/Menu/Search";
interface SearchBoxProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
@@ -35,39 +33,12 @@ export const SearchBox = forwardRef(function SearchBox(
} = props;
const hookId = useId();
const theme = useTheme();
const inputId = `${hookId}-${SearchBox.name}-input`;
return (
<div
css={{
display: "flex",
flexFlow: "row nowrap",
alignItems: "center",
padding: "0 8px",
height: "40px",
borderBottom: `1px solid ${theme.palette.divider}`,
}}
>
<div css={{ width: 18 }}>
<SearchIcon
css={{
display: "block",
fontSize: "14px",
marginLeft: "auto",
marginRight: "auto",
color: theme.palette.text.secondary,
}}
/>
</div>
<label css={{ ...visuallyHidden }} htmlFor={inputId}>
{label}
</label>
<input
type="text"
<Search>
<SearchInput
label={label}
ref={ref}
id={inputId}
autoFocus
@@ -76,17 +47,7 @@ export const SearchBox = forwardRef(function SearchBox(
{...attrs}
onKeyDown={onKeyDown}
onChange={(e) => onValueChange(e.target.value)}
css={{
height: "100%",
border: 0,
background: "none",
width: "100%",
outline: 0,
"&::placeholder": {
color: theme.palette.text.secondary,
},
}}
/>
</div>
</Search>
);
});