Merge pull request 'added filter (beta version)' (#147) from feature/add-filters into develop
Reviewed-on: http://85.143.176.51:3000/free-land/front-end/pulls/147
This commit is contained in:
commit
8a2a7f0c53
@ -5,6 +5,7 @@
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { StyleType } from "core/_variants";
|
import { StyleType } from "core/_variants";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {ReactComponent as DeleteIcon} from "./Filters/svg/chest.svg"
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Component props */
|
/* Component props */
|
||||||
@ -15,7 +16,8 @@ type Props = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
iconed?: boolean;
|
iconed?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: (element: any) => void;
|
||||||
|
closeOption?: Boolean;
|
||||||
} & Omit<React.MouseEventHandler<HTMLSpanElement>, "">;
|
} & Omit<React.MouseEventHandler<HTMLSpanElement>, "">;
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
@ -27,17 +29,18 @@ function Badge({
|
|||||||
children,
|
children,
|
||||||
onClick,
|
onClick,
|
||||||
emphasis = "low",
|
emphasis = "low",
|
||||||
|
closeOption = false,
|
||||||
...props
|
...props
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<span
|
<span
|
||||||
onClick={onClick}
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"border p-2 rounded-sm text-xs text-center",
|
"border-none p-2 rounded-md text-xs text-center",
|
||||||
{
|
{
|
||||||
"cursor-pointer": onClick,
|
"cursor-pointer": onClick,
|
||||||
"border-transparent": emphasis == "low",
|
"border-transparent": emphasis == "low",
|
||||||
"bg-blue-400 text-white": emphasis == "high",
|
"bg-blue-400 text-white rounded-xs": emphasis == "high",
|
||||||
"border-gray-400 background-gray-200": emphasis == "medium",
|
"border-gray-400 background-gray-200": emphasis == "medium",
|
||||||
},
|
},
|
||||||
className
|
className
|
||||||
@ -45,7 +48,16 @@ function Badge({
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
{closeOption && (
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className=" text-white pr-1 pl-3 py-1"
|
||||||
|
>
|
||||||
|
<div><DeleteIcon className="h-[9px] w-[9px]" /></div>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default Badge;
|
export default Badge;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { ReactComponent as Checkmark } from "assets/svg/check.svg";
|
import { ReactComponent as Checkmark } from "../assets/svg/arrow-down.svg";
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
/**
|
/**
|
||||||
* Control the state of checkbox
|
* Control the state of checkbox
|
||||||
*/
|
*/
|
||||||
isChecked: boolean;
|
isChecked?: boolean;
|
||||||
/**
|
/**
|
||||||
* An Element next to the checkbox
|
* An Element next to the checkbox
|
||||||
*/
|
*/
|
||||||
@ -33,12 +33,8 @@ const Checkbox = ({ children, className, isChecked, ...props }: Props) => {
|
|||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
<div //
|
<div className="h-2 w-2 absolute top-0 left-0">
|
||||||
className=" w-4 h-3 leading-[0] absolute top-1.5 left-1 opacity-0
|
<Checkmark className="h-6 w-6 fill-white hover:fill-white stroke-white" />
|
||||||
pointer-events-none focus:pointer-events-auto flex items-center justify-center
|
|
||||||
fill-white peer-disabled:fill-gray-500 "
|
|
||||||
>
|
|
||||||
<Checkmark className="fill-inherit" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
|
55
src/components/Disclosure.tsx
Normal file
55
src/components/Disclosure.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Imports */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import React from "react";
|
||||||
|
import { Disclosure as Disclose } from "@headlessui/react";
|
||||||
|
import { ReactComponent as SelectIcon } from "../assets/svg/arrow-down.svg";
|
||||||
|
import classNames from "classnames";
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Component props */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
type Props = {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
caption?: string;
|
||||||
|
};
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* styles */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
const ButtonStyle = `
|
||||||
|
flex w-full
|
||||||
|
justify-between
|
||||||
|
items-center
|
||||||
|
py-2 text-left
|
||||||
|
text-base
|
||||||
|
font-medium
|
||||||
|
text-black-400
|
||||||
|
`;
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Component implementation */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
export default function Disclosure({ children, className, caption }: Props) {
|
||||||
|
return (
|
||||||
|
<div className={classNames("top-16 ", className)}>
|
||||||
|
<div className="mx-auto w-full bg-white py-2">
|
||||||
|
<Disclose as="div">
|
||||||
|
{({ open }) => (
|
||||||
|
<>
|
||||||
|
<Disclose.Button className={`${ButtonStyle}`}>
|
||||||
|
<span>{caption}</span>
|
||||||
|
<SelectIcon
|
||||||
|
className={`${
|
||||||
|
open ? "rotate-180 transform" : ""
|
||||||
|
} h-4 w-5 fill-black hover:fill-black stroke-black`}
|
||||||
|
/>
|
||||||
|
</Disclose.Button>
|
||||||
|
<Disclose.Panel className="py-2 text-sm text-gray-500 ">
|
||||||
|
{children}
|
||||||
|
</Disclose.Panel>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Disclose>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
64
src/components/Filters/AppiledFilters.tsx
Normal file
64
src/components/Filters/AppiledFilters.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Imports */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
import React from "react";
|
||||||
|
import Badge from "components/Badge";
|
||||||
|
import { IProduct } from "./IProdutct";
|
||||||
|
import classNames from "classnames";
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Component props */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
type Props = {
|
||||||
|
hints?: IProduct[];
|
||||||
|
delFilter: (element: IProduct) => void;
|
||||||
|
clearAll: () => void;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Component implementation */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
export default function AppiledFilters({
|
||||||
|
hints,
|
||||||
|
delFilter,
|
||||||
|
clearAll,
|
||||||
|
className,
|
||||||
|
}: Props) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"w-full py-3 h-36 max-h-36 overflow-hidden ",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row items-center justify-between space-x-3 ">
|
||||||
|
<div className="font-medium">Фильтры</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={clearAll}
|
||||||
|
className="font-normal text-sm text-gray-400"
|
||||||
|
>
|
||||||
|
Очистить всё
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul className="list-none mt-2 h-24 max-h-32 overflow-auto">
|
||||||
|
{hints &&
|
||||||
|
hints.length > 0 &&
|
||||||
|
hints.map((item: IProduct) => (
|
||||||
|
<li className="mt-1" key={item.id}>
|
||||||
|
<Badge
|
||||||
|
className="py-1 cursor-default"
|
||||||
|
emphasis="high"
|
||||||
|
closeOption={true}
|
||||||
|
onClick={() => delFilter(item)}
|
||||||
|
>
|
||||||
|
{item.brand}
|
||||||
|
</Badge>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
109
src/components/Filters/Filter.tsx
Normal file
109
src/components/Filters/Filter.tsx
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Disclosure from "components/Disclosure";
|
||||||
|
import AppiledFilters from "./AppiledFilters";
|
||||||
|
import SearchFilterBar from "./SearchFilterBar";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useDebounce } from "./functions/debounce";
|
||||||
|
import { IProduct } from "./IProdutct";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Fiter({ className }: Props) {
|
||||||
|
const [checkedId, setCheckedId] = React.useState<Array<number>>([]);
|
||||||
|
const [activeFilter, setActiveFilter] = React.useState<Array<IProduct>>([]);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Test request to demonstrate the basic functionality of the filter */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
const [query, setQuery] = React.useState("");
|
||||||
|
const [hints, setHints] = React.useState<Array<IProduct>>([]);
|
||||||
|
|
||||||
|
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setQuery(e.target.value);
|
||||||
|
};
|
||||||
|
const debounced = useDebounce(query);
|
||||||
|
|
||||||
|
async function fetchProducts() {
|
||||||
|
const response = await axios.get(
|
||||||
|
`https://dummyjson.com/products/search?q=${debounced}`
|
||||||
|
);
|
||||||
|
setHints(response.data.products);
|
||||||
|
}
|
||||||
|
React.useEffect(() => {
|
||||||
|
fetchProducts();
|
||||||
|
}, [debounced, query]);
|
||||||
|
|
||||||
|
const isChecked = (item: number) => (checkedId.includes(item) ? true : false);
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const selectedId = parseInt(e.target.value);
|
||||||
|
|
||||||
|
/* ------------- Check if "checkedId" contains "selectedIds" ------------- */
|
||||||
|
/* -------------- If true, this checkbox is already checked -------------- */
|
||||||
|
|
||||||
|
if (checkedId.includes(selectedId)) {
|
||||||
|
setCheckedId(checkedId.filter((id) => id !== selectedId));
|
||||||
|
setActiveFilter(activeFilter.filter((item) => item.id !== selectedId));
|
||||||
|
} else {
|
||||||
|
const newId = [...checkedId];
|
||||||
|
newId.push(selectedId);
|
||||||
|
setCheckedId(newId);
|
||||||
|
|
||||||
|
/* --------------- Adding checked filters to AppliedFilters component -------------- */
|
||||||
|
|
||||||
|
hints.forEach((hint) => {
|
||||||
|
if (hint.id === selectedId)
|
||||||
|
activeFilter.push({ id: selectedId, brand: hint.brand });
|
||||||
|
setActiveFilter(activeFilter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------- Delete filter from AppliedFilters component ------------- */
|
||||||
|
|
||||||
|
const DelFilter = (e: IProduct) => {
|
||||||
|
setActiveFilter(activeFilter.filter((item) => item.id !== e.id));
|
||||||
|
setCheckedId(checkedId.filter((id) => id !== e.id));
|
||||||
|
};
|
||||||
|
const clearAll = () => {
|
||||||
|
setActiveFilter([]);
|
||||||
|
setCheckedId([]);
|
||||||
|
setQuery("");
|
||||||
|
};
|
||||||
|
//console.log(activeFilter)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="pl-2">
|
||||||
|
<div className="max-w-[268px] mx-auto divide-y divide-solid">
|
||||||
|
<AppiledFilters
|
||||||
|
hints={activeFilter}
|
||||||
|
delFilter={DelFilter}
|
||||||
|
clearAll={clearAll}
|
||||||
|
></AppiledFilters>
|
||||||
|
<Disclosure caption="Авторы">
|
||||||
|
<SearchFilterBar
|
||||||
|
hints={hints}
|
||||||
|
isChecked={isChecked}
|
||||||
|
handleChange={handleChange}
|
||||||
|
onChange={onChange}
|
||||||
|
query={query}
|
||||||
|
placeHolder={"Введите имя автора"}
|
||||||
|
/>
|
||||||
|
</Disclosure>
|
||||||
|
<Disclosure caption="Публикации">
|
||||||
|
<p>контент...</p>
|
||||||
|
</Disclosure>
|
||||||
|
<Disclosure caption="Тип издания">
|
||||||
|
<p>контент...</p>
|
||||||
|
</Disclosure>
|
||||||
|
<Disclosure caption="Тематика публикаций">
|
||||||
|
<p>контент...</p>
|
||||||
|
</Disclosure>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
23
src/components/Filters/IProdutct.ts
Normal file
23
src/components/Filters/IProdutct.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export interface IProduct {
|
||||||
|
id?: number;
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
price?: number;
|
||||||
|
discountPercentage?: number;
|
||||||
|
rating?: number;
|
||||||
|
stock?: number;
|
||||||
|
brand?: string;
|
||||||
|
category?: string;
|
||||||
|
thumbnail?: string;
|
||||||
|
images?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface serverResponse<T> {
|
||||||
|
products: T[];
|
||||||
|
total: number;
|
||||||
|
skip: number;
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
117
src/components/Filters/SearchFilterBar.tsx
Normal file
117
src/components/Filters/SearchFilterBar.tsx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { useState, useCallback, Fragment } from "react";
|
||||||
|
import { Combobox, Transition } from "@headlessui/react";
|
||||||
|
import { IProduct } from "./IProdutct";
|
||||||
|
import Checkbox from "components/Checkbox";
|
||||||
|
import { ReactComponent as SearchIcon } from "./svg/searchIcon.svg";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
hints: IProduct[];
|
||||||
|
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
isChecked: (item: number) => boolean;
|
||||||
|
className?: string;
|
||||||
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
placeHolder: string;
|
||||||
|
query: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SearchFilterBar({
|
||||||
|
hints,
|
||||||
|
isChecked,
|
||||||
|
handleChange,
|
||||||
|
className,
|
||||||
|
onChange,
|
||||||
|
placeHolder,
|
||||||
|
query,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
const [checkList, setCheckList] = useState(hints);
|
||||||
|
const [showFilters, SetShowFilters] = useState(false);
|
||||||
|
|
||||||
|
const ShowAllFilters = useCallback(() => {
|
||||||
|
SetShowFilters((prev) => !prev);
|
||||||
|
}, [SetShowFilters]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Combobox value={checkList} onChange={setCheckList}>
|
||||||
|
{({ open }) => (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"flex flex-row w-full items-center border border-solid rounded border-gray-200",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="basis-6 ">
|
||||||
|
<Combobox.Button>
|
||||||
|
<div className="pl-1 pt-1">
|
||||||
|
<SearchIcon />
|
||||||
|
</div>
|
||||||
|
</Combobox.Button>
|
||||||
|
</div>
|
||||||
|
<div className="grow">
|
||||||
|
<Combobox.Input
|
||||||
|
onChange={onChange}
|
||||||
|
placeholder={placeHolder}
|
||||||
|
className="w-full text-sm py-1 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4">
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
leave="transition ease-in duration-100"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
>
|
||||||
|
<Combobox.Options static={true}>
|
||||||
|
{open && (
|
||||||
|
<ul
|
||||||
|
className={classNames([
|
||||||
|
"w-[276px] relative h-40 top-0 right-2",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"max-h-60 h-60 overflow-auto": showFilters === true,
|
||||||
|
"max-h-40 h-40 overflow-hidden":
|
||||||
|
showFilters === false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
])}
|
||||||
|
>
|
||||||
|
<li className="">
|
||||||
|
{hints.length >= 5 && query !== "" && (
|
||||||
|
<button
|
||||||
|
onClick={ShowAllFilters}
|
||||||
|
className="text-right text-blue-500 pl-2 text-sm font-medium"
|
||||||
|
>
|
||||||
|
Показать всё({hints.length})
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
{hints.length > 0 ? (
|
||||||
|
hints.map((item) => (
|
||||||
|
<li key={item.id} className="mt-1 pl-2">
|
||||||
|
<Checkbox
|
||||||
|
className="z-10 mt-1 w-full max-h-56"
|
||||||
|
value={item.id}
|
||||||
|
isChecked={item.id ? isChecked(item.id) : false}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<p>{item.brand}</p>
|
||||||
|
</Checkbox>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<p className="text-blue-300 pl-2">Nothing Found</p>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Combobox>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
11
src/components/Filters/functions/debounce.ts
Normal file
11
src/components/Filters/functions/debounce.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export function useDebounce(value: string, delay: number = 300) {
|
||||||
|
const [debounced, setDebouced] = React.useState(value);
|
||||||
|
React.useEffect(() => {
|
||||||
|
const handler = setTimeout(() => setDebouced(value), delay);
|
||||||
|
return () => clearTimeout(handler);
|
||||||
|
}, [value, delay]);
|
||||||
|
|
||||||
|
return debounced;
|
||||||
|
}
|
4
src/components/Filters/svg/chest.svg
Normal file
4
src/components/Filters/svg/chest.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="12" height="13" viewBox="0 0 12 13" fill="white" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.9497 11.4498L1.05026 1.55027" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M10.9497 1.55029L1.05025 11.4498" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 304 B |
3
src/components/Filters/svg/searchIcon.svg
Normal file
3
src/components/Filters/svg/searchIcon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M15.1003 14.1184L10.4628 9.48086C11.1824 8.55051 11.5717 7.41301 11.5717 6.21658C11.5717 4.78444 11.0128 3.44158 10.0021 2.42908C8.99135 1.41658 7.64492 0.859436 6.21456 0.859436C4.78421 0.859436 3.43778 1.41836 2.42706 2.42908C1.41456 3.43979 0.857422 4.78444 0.857422 6.21658C0.857422 7.64694 1.41635 8.99336 2.42706 10.0041C3.43778 11.0166 4.78242 11.5737 6.21456 11.5737C7.41099 11.5737 8.54671 11.1844 9.47707 10.4666L14.1146 15.1023C14.1282 15.1159 14.1443 15.1267 14.1621 15.1341C14.1799 15.1414 14.1989 15.1452 14.2181 15.1452C14.2374 15.1452 14.2564 15.1414 14.2742 15.1341C14.292 15.1267 14.3081 15.1159 14.3217 15.1023L15.1003 14.3255C15.1139 14.3119 15.1247 14.2958 15.132 14.278C15.1394 14.2602 15.1432 14.2412 15.1432 14.2219C15.1432 14.2027 15.1394 14.1837 15.132 14.1659C15.1247 14.1481 15.1139 14.132 15.1003 14.1184ZM9.04314 9.04515C8.28599 9.80051 7.28242 10.2166 6.21456 10.2166C5.14671 10.2166 4.14314 9.80051 3.38599 9.04515C2.63064 8.28801 2.21456 7.28444 2.21456 6.21658C2.21456 5.14872 2.63064 4.14336 3.38599 3.38801C4.14314 2.63265 5.14671 2.21658 6.21456 2.21658C7.28242 2.21658 8.28778 2.63086 9.04314 3.38801C9.79849 4.14515 10.2146 5.14872 10.2146 6.21658C10.2146 7.28444 9.79849 8.28979 9.04314 9.04515Z" fill="#8C8C8C"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -6,6 +6,7 @@ import { SearchResultSection } from "components/SearchResultsSection";
|
|||||||
import { useSearchStoreImplementation } from "searchResults/data/searchStoreImplementation";
|
import { useSearchStoreImplementation } from "searchResults/data/searchStoreImplementation";
|
||||||
import { useSearchViewModel } from "searchResults/controller/searchResultsViewModel";
|
import { useSearchViewModel } from "searchResults/controller/searchResultsViewModel";
|
||||||
import { Loader } from "components/Loader/Loader";
|
import { Loader } from "components/Loader/Loader";
|
||||||
|
import Fiter from "components/Filters/Filter";
|
||||||
|
|
||||||
export const SearchResultsPage = () => {
|
export const SearchResultsPage = () => {
|
||||||
return (
|
return (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user