Skip to content

Commit

Permalink
[Nu-1780] add new icon
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Rudnicki committed Sep 5, 2024
1 parent 5325511 commit 0c0ee71
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 6 deletions.
1 change: 1 addition & 0 deletions designer/client/src/assets/img/advanced-search.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions designer/client/src/components/table/SearchFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { css, cx } from "@emotion/css";
import React from "react";
import SearchSvg from "../../assets/img/search.svg";
import AdvancedSearchSvg from "../../assets/img/advanced-search.svg";
import DeleteSvg from "../../assets/img/toolbarButtons/delete.svg";
import { useTheme } from "@mui/material";

Expand All @@ -9,6 +10,32 @@ const flex = css({
flex: 1,
});

export function AdvancedOptionsIcon(props: {
isActive?: boolean;
collapseHandler: React.Dispatch<React.SetStateAction<boolean>>;
}): JSX.Element {
const theme = useTheme();

const toggleCollapseHandler = () => {
props.collapseHandler((p) => !p);
};

return (
<AdvancedSearchSvg
onClick={toggleCollapseHandler}
className={cx(
flex,
css({
".icon-fill": {
fill: "none",
stroke: !props.isActive ? theme.palette.text.secondary : theme.palette.primary.main,
},
}),
)}
/>
);
}

export function SearchIcon(props: { isEmpty?: boolean }): JSX.Element {
const theme = useTheme();
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { css, cx } from "@emotion/css";
import { styled, useTheme } from "@mui/material";
import React, { forwardRef, PropsWithChildren, ReactElement, useCallback, useImperativeHandle, useRef } from "react";
import { AdvancedOptionsIcon, ClearIcon } from "../table/SearchFilter";
import { InputProps, ThemedInput } from "./ThemedInput";

type Props = PropsWithChildren<InputProps> & {
onClear?: () => void;
onAddonClick?: () => void;
};

export type Focusable = {
focus: (options?: FocusOptions) => void;
};

export const InputWithAdvancedSearchOptions = forwardRef<Focusable, Props>(function InputWithIcon(
{ children, onAddonClick, onClear, ...props },
forwardedRef,
): ReactElement {
const theme = useTheme();

const size = theme.custom.spacing.controlHeight;

const wrapperWithAddonStyles = css({
position: "relative",
display: "flex",
flexDirection: "row",
});

const addonWrapperStyles = css({
position: "absolute",
top: 0,
right: 0,
height: size,
display: "flex",
padding: size / 4,
});

const addonStyles = css({
display: "flex",
width: size / 2,
height: size / 2,
marginLeft: size / 4,
});

const ref = useRef<HTMLInputElement>();
const focus = useCallback(
(options?: FocusOptions) => {
const input = ref.current;
input.focus({ preventScroll: true });
input.setSelectionRange(0, props.value.length);
setTimeout(() => {
if (options?.preventScroll) return;
input.scrollIntoView({ behavior: "smooth", block: "center" });
}, theme.transitions.duration.standard);
},
[props.value.length, theme.transitions.duration.standard],
);

useImperativeHandle(forwardedRef, () => ({ focus }), [focus]);

return (
<div className={cx(children && wrapperWithAddonStyles)}>
<ThemedInput ref={ref} {...props} />
<div className={addonWrapperStyles}>
{!!props.value && onClear && (
<div className={addonStyles} onClick={onClear}>
<ClearIcon />
</div>
)}
{children && (
<div className={addonStyles} onClick={onAddonClick ?? (() => focus())}>
{children}
</div>
)}
</div>
</div>
);
});
16 changes: 16 additions & 0 deletions designer/client/src/components/themed/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { styled } from "@mui/material";
import { InputWithIcon } from "./InputWithIcon";
import { InputWithAdvancedSearchOptions } from "./InputWithAdvancedSearchOptions";

export const SearchInputWithIcon = styled(InputWithIcon)(({ theme }) => ({
...theme.typography.body2,
Expand All @@ -15,3 +16,18 @@ export const SearchInputWithIcon = styled(InputWithIcon)(({ theme }) => ({
boxShadow: "none",
},
}));

export const SearchInputWithAdvancedOptions = styled(InputWithAdvancedSearchOptions)(({ theme }) => ({
...theme.typography.body2,
width: "100%",
borderRadius: 0,
height: "36px !important",
color: theme.palette.text.secondary,
padding: "6px 12px !important",
backgroundColor: `${theme.palette.background.paper} !important`,
border: "none",
outline: "none !important",
"&:focus": {
boxShadow: "none",
},
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";

export function AdvancedSearchOptions() {
return <p>ADVANCED_SEARCH_OPTIONS</p>;
}
22 changes: 16 additions & 6 deletions designer/client/src/components/toolbars/search/SearchPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
import { isEmpty } from "lodash";
import React, { ReactElement, useCallback, useRef, useState } from "react";
import React, { ReactElement, useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { SearchIcon } from "../../table/SearchFilter";
import { AdvancedOptionsIcon, SearchIcon } from "../../table/SearchFilter";
import { Focusable } from "../../themed/InputWithIcon";
import { ToolbarPanelProps } from "../../toolbarComponents/DefaultToolbarPanel";
import { ToolbarWrapper } from "../../toolbarComponents/toolbarWrapper/ToolbarWrapper";
import { SearchResults } from "./SearchResults";
import { SearchInputWithIcon } from "../../themed/SearchInput";
import { SearchInputWithAdvancedOptions, SearchInputWithIcon } from "../../themed/SearchInput";
import { EventTrackingSelector, getEventTrackingProps } from "../../../containers/event-tracking";
import { Collapse } from "@mui/material";
import { AdvancedSearchOptions } from "./AdvancedSearchOptions";

export function SearchPanel(props: ToolbarPanelProps): ReactElement {
const { t } = useTranslation();
const [filter, setFilter] = useState<string>("");
const clearFilter = useCallback(() => setFilter(""), []);
const [advancedOptionsCollapsed, setAdvancedOptionsCollapsed] = useState(true);

const searchRef = useRef<Focusable>();

useEffect(() => {
setAdvancedOptionsCollapsed(false);
}, [filter]);

return (
<ToolbarWrapper {...props} title={t("panels.search.title", "Search")} onExpand={() => searchRef.current?.focus()}>
<SearchInputWithIcon
<SearchInputWithAdvancedOptions
ref={searchRef}
onChange={setFilter}
onClear={clearFilter}
value={filter}
placeholder={t("panels.search.filter.placeholder", "type here to search nodes...")}
{...getEventTrackingProps({ selector: EventTrackingSelector.NodesInScenario })}
>
<SearchIcon isEmpty={isEmpty(filter)} />
</SearchInputWithIcon>
<AdvancedOptionsIcon isActive={advancedOptionsCollapsed} collapseHandler={setAdvancedOptionsCollapsed} />
</SearchInputWithAdvancedOptions>
<Collapse in={advancedOptionsCollapsed} timeout="auto" unmountOnExit>
<AdvancedSearchOptions />
</Collapse>
<SearchResults filterRawText={filter} />
</ToolbarWrapper>
);
Expand Down

0 comments on commit 0c0ee71

Please sign in to comment.