Search Filter
Обычная сортировка
"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> );};
С отдельной базой данных и таблицей
"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> );};
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;
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", },]
Расширенные настройки
"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> )}
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} ₽ </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} ₽ <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;
.input { @apply h-12 transition-none border border-slate-200;
&:focus-within { @apply ring-2 ring-blue-600 border-transparent; }}