Filters 5
Filters1 ColumnText Align CenterFilter TopButtonsFiltersModal

Code
relume-filters5.tsx
import React, { useState } from "react";
import { AnimatePresence, motion } from "motion/react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Cancel, FilterList, KeyboardArrowDown, Search } from "relume-icons";
type FilterValues = {
filterOne: string;
filterTwo: string[];
filterThree: string[];
filterFour: string[];
};
const tabs = [
{ value: "View all", trigger: "View all" },
{ value: "Category one", trigger: "Category one" },
{ value: "Category two", trigger: "Category two" },
{ value: "Category three", trigger: "Category three" },
{ value: "Category four", trigger: "Category four" },
];
const options = [
{ value: "option-1", label: "Option one" },
{ value: "option-2", label: "Option two" },
{ value: "option-3", label: "Option three" },
{ value: "option-4", label: "Option four" },
{ value: "option-5", label: "Option five" },
];
const containerVariants = {
initial: {
height: 0,
opacity: 0,
transition: { duration: 0.2, ease: "easeInOut" },
},
animate: {
height: "auto",
opacity: 1,
transition: { duration: 0.2, ease: "easeInOut" },
},
exit: {
height: 0,
opacity: 0,
transition: { duration: 0.2, ease: "easeInOut", opacity: { duration: 0.1 } },
},
};
export const Filters5 = () => {
const [isOpen, setIsOpen] = useState(false);
const [selectedValues, setSelectedValues] = useState<FilterValues>({
filterOne: "",
filterTwo: ["option-1"],
filterThree: ["option-1"],
filterFour: ["option-1"],
});
const handleClear = (filter: keyof FilterValues) => {
setSelectedValues((prev) => ({
...prev,
[filter]: Array.isArray(prev[filter]) ? [] : "",
}));
};
const handleCheckboxChange = (filter: keyof Omit<FilterValues, "filterOne">, value: string) => {
setSelectedValues((prev) => {
const currentItems = prev[filter];
return {
...prev,
[filter]: currentItems.includes(value)
? currentItems.filter((item) => item !== value)
: [...currentItems, value],
};
});
};
const getSelectedLabels = (filter: keyof FilterValues) => {
if (!selectedValues[filter].length) return "Select options";
if (selectedValues[filter].length === 1) {
return options.find((opt) => opt.value === selectedValues[filter][0])?.label;
}
return `${selectedValues[filter].length} selected`;
};
return (
<section className="px-[5%] py-16 md:py-24 lg:py-28">
<div className="container">
<div className="mb-12 w-full text-center md:mb-18 lg:mb-20">
<h1 className="mb-5 text-h2 font-bold md:mb-6">Collection</h1>
<p className="text-medium">Lorem ipsum dolor sit amet.</p>
</div>
<div className="mb-8 grid auto-cols-fr grid-cols-2 grid-rows-[auto_auto] items-center justify-between gap-x-6 gap-y-8 lg:grid-cols-[1fr_max-content_1fr] lg:gap-y-0">
<Button
className="w-fit gap-3 self-start"
variant="secondary"
onClick={() => setIsOpen(!isOpen)}
>
<FilterList className="size-6 text-scheme-text" />
<span className="underline">Filters</span>
</Button>
<Tabs
defaultValue={tabs[0].value}
className="scrollbar-none flex w-full flex-col items-center justify-center overflow-scroll [grid-area:2/1/3/3] md:overflow-auto lg:[grid-area:auto/auto/auto/auto]"
>
<TabsList className="flex w-screen items-center justify-start pl-[5vw] md:w-full md:justify-center md:overflow-hidden md:pl-0">
{tabs.map((tab, index) => (
<TabsTrigger
key={index}
value={tab.value}
className="rounded-button px-4 py-2 data-[state=inactive]:border-transparent"
>
{tab.trigger}
</TabsTrigger>
))}
</TabsList>
</Tabs>
<DropdownMenu>
<DropdownMenuTrigger className="-mr-2 flex items-center gap-2 justify-self-end">
<p className="whitespace-nowrap">Sort by</p>
<KeyboardArrowDown className="shrink-0 text-scheme-text transition-transform duration-300" />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{[
"Most Popular",
"Most Recent",
"Name: A to Z",
"Name: Z to A",
"Price: Low to High",
"Price: High to Low",
].map((option) => (
<DropdownMenuItem key={option}>{option}</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
</div>
<AnimatePresence initial={false} mode="wait">
{isOpen && (
<motion.div
variants={containerVariants}
initial="initial"
animate="animate"
exit="exit"
className="overflow-hidden"
>
<div className="mb-8 grid grid-cols-1 gap-x-8 gap-y-4 lg:grid-cols-4">
<div>
<div className="mb-2 flex items-center justify-between">
<span>Filter One</span>
<Button
variant="link"
size="link"
onClick={() => handleClear("filterOne")}
className="text-small"
>
Clear
</Button>
</div>
<Input
placeholder="Keyword"
icon={<Search className="size-6 text-scheme-text" />}
value={selectedValues.filterOne}
onChange={(e) =>
setSelectedValues((prev) => ({
...prev,
filterOne: e.target.value,
}))
}
/>
</div>
<div>
<div className="mb-2 flex items-center justify-between">
<span>Filter Two</span>
<Button
variant="link"
size="link"
onClick={() => handleClear("filterTwo")}
className="text-small"
>
Clear
</Button>
</div>
<Select value="" onValueChange={() => {}}>
<SelectTrigger>
<SelectValue placeholder={getSelectedLabels("filterTwo")} />
</SelectTrigger>
<SelectContent>
{options.map((option) => (
<div key={option.value} className="flex items-center space-x-2 p-2">
<Checkbox
id={`filter-two-${option.value}`}
checked={selectedValues.filterTwo.includes(option.value)}
onCheckedChange={() => handleCheckboxChange("filterTwo", option.value)}
/>
<Label
className="grow cursor-pointer"
htmlFor={`filter-two-${option.value}`}
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
e.preventDefault();
handleCheckboxChange("filterTwo", option.value);
}}
>
{option.label}
</Label>
</div>
))}
</SelectContent>
</Select>
</div>
<div>
<div className="mb-2 flex items-center justify-between">
<span>Filter Three</span>
<Button
variant="link"
size="link"
onClick={() => handleClear("filterThree")}
className="text-small"
>
Clear
</Button>
</div>
<Select value="" onValueChange={() => {}}>
<SelectTrigger>
<SelectValue placeholder={getSelectedLabels("filterThree")} />
</SelectTrigger>
<SelectContent>
{options.map((option) => (
<div key={option.value} className="flex items-center space-x-2 px-2 py-1.5">
<Checkbox
id={`filter-three-${option.value}`}
checked={selectedValues.filterThree.includes(option.value)}
onCheckedChange={() =>
handleCheckboxChange("filterThree", option.value)
}
/>
<Label
className="grow cursor-pointer"
htmlFor={`filter-three-${option.value}`}
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
e.preventDefault();
handleCheckboxChange("filterThree", option.value);
}}
>
{option.label}
</Label>
</div>
))}
</SelectContent>
</Select>
</div>
<div>
<div className="mb-2 flex items-center justify-between">
<span>Filter Four</span>
<Button
variant="link"
size="link"
onClick={() => handleClear("filterFour")}
className="text-small"
>
Clear
</Button>
</div>
<Select value="" onValueChange={() => {}}>
<SelectTrigger>
<SelectValue placeholder={getSelectedLabels("filterFour")} />
</SelectTrigger>
<SelectContent>
{options.map((option) => (
<div key={option.value} className="flex items-center space-x-2 px-2 py-1.5">
<Checkbox
id={`filter-four-${option.value}`}
checked={selectedValues.filterFour.includes(option.value)}
onCheckedChange={() => handleCheckboxChange("filterFour", option.value)}
/>
<Label
className="grow cursor-pointer"
htmlFor={`filter-four-${option.value}`}
onClick={(e: React.MouseEvent<HTMLLabelElement>) => {
e.preventDefault();
handleCheckboxChange("filterFour", option.value);
}}
>
{option.label}
</Label>
</div>
))}
</SelectContent>
</Select>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
<div>
<div className="mb-8 flex w-full items-center justify-between gap-8">
<div className="flex items-center bg-scheme-foreground py-2 pr-3 pl-4">
<span>Tag</span>
<Cancel className="ml-2 size-5.5 flex-none cursor-pointer" />
</div>
<span className="text-small">Showing 0 of 100</span>
</div>
<div className="min-h-[200vh] w-full border-2 border-dashed border-neutral-darkest/15" />
<div className="border border-scheme-border p-[2.9rem] text-center">
<h6 className="mb-2 text-h6 font-bold">No results found.</h6>
<p>There are no results with this criteria. Try changing your search.</p>
</div>
</div>
</div>
</section>
);
};npm i @radix-ui/react-accordion @radix-ui/react-checkbox @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-radio-group @radix-ui/react-select @radix-ui/react-slider @radix-ui/react-slot @radix-ui/react-switch @radix-ui/react-tabs class-variance-authority@0.7.1 clsx@^2.1.1 luxon@^3.5.0 motion@^12.15.0 relume-icons@1.3.0 tailwind-merge@^2.2.2


