Перейти к содержимому

Search Filter

Обычная сортировка

./app/page.tsx
"use client"
import { useState } from "react";
const Users = [
{
"id": 1,
"first_name": "Emiline",
"last_name": "McClune",
"email": "emcclune0@xrea.com",
"gender": "Female",
},
{
"id": 2,
"first_name": "Felix",
"last_name": "Ingleston",
"email": "fingleston1@hibu.com",
"gender": "Female",
},
{
"id": 3,
"first_name": "Travus",
"last_name": "Bergstram",
"email": "tbergstram2@pbs.org",
"gender": "Female",
},
];
export default function FilteredItems() {
const [query, setQuery] = useState("");
return (
<div className="app">
<input
className="border p-2 rounded-md"
type="text"
placeholder="Поиск..."
onChange={(e) => setQuery(e.target.value)}
/>
<ul className="list">
{Users.filter((user) =>
user.first_name.toLowerCase().includes(query.toLowerCase()) ||
user.last_name.toLowerCase().includes(query.toLowerCase()) ||
user.email.toLowerCase().includes(query.toLowerCase())
).map((user) => (
<li className="flex gap-4" key={user.id}>
<span>{user.first_name}</span>
<span>{user.last_name}</span>
<span>{user.email}</span>
</li>
))}
</ul>
</div>
);
};

С отдельной базой данных и таблицей

./app/page.tsx
"use client"
import { useState } from "react";
import { Users } from "../../data/users";
import Table from "./table";
export default function FilteredItems() {
const [query, setQuery] = useState("");
const Search = (data: any) => {
return data.filter((item: any) =>
keys.some((key) => item[key].toLowerCase().includes(query.toLowerCase()))
);
};
const keys = [
"first_name",
"last_name",
"email"
]
return (
<div>
<input
className="border p-2 rounded-md"
type="text"
placeholder="Поиск..."
onChange={(e) => setQuery(e.target.value)}
/>
{<Table data={Search(Users)} />}
</div>
);
};
./components/_ui/table.tsx
const Table = ({ data }: any) => {
return (
<table>
<tbody>
<tr>
<th>Name</th>
<th>Surname</th>
<th>Email</th>
</tr>
{data.map((item: any) => (
<tr key={item.id}>
<td>{item.first_name}</td>
<td>{item.last_name}</td>
<td>{item.email}</td>
</tr>
))}
</tbody>
</table>
);
};
export default Table;
./data/users.tsx
export const Users = [
{
"id": 1,
"first_name": "Emiline",
"last_name": "McClune",
"email": "emcclune0@xrea.com",
"gender": "Female",
},
{
"id": 2,
"first_name": "Felix",
"last_name": "Ingleston",
"email": "fingleston1@hibu.com",
"gender": "Female",
},
{
"id": 3,
"first_name": "Travus",
"last_name": "Bergstram",
"email": "tbergstram2@pbs.org",
"gender": "Female",
},
]

Расширенные настройки

./components/cards/index.tsx
"use client"
import { useState } from "react";
import classes from './input.module.css';
import { Input, CloseButton } from '@mantine/core';
import { IconLayoutGrid, IconListDetails, IconSearch } from '@tabler/icons-react'
import { Cards } from "../../data/cards"
import CardBlock from "./card"
export default function FilteredItems() {
const [opened, setOpened] = useState(false)
const [query, setQuery] = useState('')
const Search = (data: any) => {
return data.filter((item: any) =>
keys.some((key) => item[key].toLowerCase().includes(query))
)
}
const keys = [
"name",
"disc"
]
return (
<div className="space-y-8">
<div className="flex items-center gap-4">
<div className="flex-1">
<Input
leftSection={<IconSearch size={20} />}
placeholder="Поиск..."
value={query}
onChange={(e) => setQuery(e.target.value)}
rightSectionPointerEvents="all"
size="md"
radius="md"
rightSection={
<CloseButton
aria-label="Clear input"
onClick={() => setQuery('')}
style={{ display: query ? undefined : 'none' }}
/>
}
classNames={classes}
autoCapitalize="off"
/>
</div>
<div className="h-12 px-4 bg-slate-200 flex items-center rounded-md">
Category
</div>
<div className="flex items-center">
<button
onClick={() => setOpened(false)}
className={`${opened ? 'bg-slate-200 text-black' : 'bg-blue-600 text-white'} h-12 px-4 rounded-l-md`}
type="button"
>
<IconLayoutGrid size={24} />
</button>
<button
onClick={() => setOpened(true)}
className={`${opened ? 'bg-blue-600 text-white' : 'bg-slate-200 text-black'} h-12 px-4 rounded-r-md`}
type="button"
>
<IconListDetails size={24} />
</button>
</div>
</div>
<CardBlock
data={Search(Cards)}
state={opened ?
'grid-cols-1 gap-4' :
'grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4'
}
card={opened ?
'bg-white rounded-xl p-4 md:hover:pl-6 flex items-center gap-3.5 py-3.5 text-xs md:text-sm hover:shadow-2xl hover:shadow-slate-200 duration-200' :
'bg-white rounded-xl p-4 flex flex-col items-start gap-3 relative hover:shadow-2xl hover:shadow-slate-200 hover:-translate-y-1.5 duration-200'
}
size={opened ? '40' : '64'}
bage={opened ? '' : 'py-1'}
price={opened ? '' : 'absolute top-4 right-4 z-40'}
/>
</div>
)
}
./components/cards/card.tsx
import Image from "next/image";
import { useDisclosure } from '@mantine/hooks';
import { Modal } from '@mantine/core';
import { IconShoppingCartPlus, IconShoppingCart } from '@tabler/icons-react'
const CardBlock = ({ data, state, card, size, bage, price }: any) => {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<div className={`grid ${state}`}>
{data && data.length > 0 ? (
data.map((item: any) => (
<div onClick={open} className={`${card} cursor-pointer`} key={item.id}>
<Image
className=" rounded-xl"
src={item.logo}
width={size}
height={size}
alt={item.name}
/>
<div className="flex-1 flex flex-col gap-1">
<h4 className="opacity-50 text-xs">{item.name}</h4>
<p className="font-semibold leading-snug text-sm">{item.disc}</p>
</div>
<div className="inline-flex flex-col md:flex-row md:items-end gap-2 text-[10px] font-medium">
{item.offer && <span className={`${bage} bg-orange-100 text-orange-500 rounded-md px-2 w-fit`}>
Супер предложение
</span>}
{item.benefit && <span className={`${bage} bg-emerald-50 text-emerald-500 rounded-md px-2 w-fit`}>
Выгода: {item.benefit}&nbsp;
</span>}
</div>
<button className={`${price} flex items-center gap-2 bg-slate-100 hover:bg-blue-600 hover:text-white py-2 px-3 rounded-full text-xs font-medium group duration-200`} type="button">
{item.price}&nbsp;
<IconShoppingCartPlus className="text-slate-400 group-hover:text-white duration-200" size="18" />
</button>
</div>
))
) : (
<p>Результатов не найдено!</p>
)}
</div>
<Modal opened={opened} onClose={close} title="Карточа" centered>
Modal content
</Modal>
</>
);
};
export default CardBlock;
./components/cards/input.module.css
.input {
@apply h-12 transition-none border border-slate-200;
&:focus-within {
@apply ring-2 ring-blue-600 border-transparent;
}
}