Category Filters
Category Filters é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Bund UI
MIT
other
O que é
Category Filters é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Não precisa de pacotes além do que o projeto já tem
Licença
Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Category Filters
"use client";
import Link from "next/link";
import Image from "next/image";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
import { Input } from "@/components/ui/input";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { cn } from "@/lib/utils";
import { Checkbox } from "@/components/ui/checkbox";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
const products = [
{
title: "White T-Shirt",
image: "/images/products/list1.png",
price: "$29.00"
},
{
title: "White T-Shirt",
image: "/images/products/list2.png",
price: "$29.00"
},
{
title: "White T-Shirt",
image: "/images/products/list3.png",
price: "$29.00"
},
{
title: "White T-Shirt",
image: "/images/products/list4.png",
price: "$29.00"
},
{
title: "White T-Shirt",
image: "/images/products/list5.png",
price: "$29.00"
},
{
title: "White T-Shirt",
image: "/images/products/list6.png",
price: "$29.00"
}
];
export type Product = (typeof products)[number];
const colorFilters = [
{
name: "Blue",
classNames:
"border-blue-500 bg-blue-500 shadow-none data-[state=checked]:border-blue-500 data-[state=checked]:bg-blue-500"
},
{
name: "Pink",
classNames:
"border-pink-500 bg-pink-500 shadow-none data-[state=checked]:border-pink-500 data-[state=checked]:bg-pink-500"
},
{
name: "Red",
classNames:
"border-red-500 bg-red-500 shadow-none data-[state=checked]:border-red-500 data-[state=checked]:bg-red-500"
},
{
name: "Orange",
classNames:
"border-amber-500 bg-amber-500 shadow-none data-[state=checked]:border-amber-500 data-[state=checked]:bg-amber-500"
},
{
name: "Green",
classNames:
"border-emerald-500 bg-emerald-500 shadow-none data-[state=checked]:border-emerald-500 data-[state=checked]:bg-emerald-500"
}
];
const categories = [
{ name: "T-Shirts" },
{ name: "Hoodies" },
{ name: "Jackets" },
{ name: "Accessories" },
{ name: "Sweaters" },
{ name: "Shorts" },
{ name: "Bags" }
];
const sizes = [{ name: "SM" }, { name: "LG" }, { name: "XL" }, { name: "XXL" }];
const sortFilters = [
{ key: "featured", name: "Featured" },
{ key: "best_selling", name: "Best Selling" },
{ key: "price_low_high", name: "Price: Low to High" },
{ key: "price_high_low", name: "Price: High to Low" },
{ key: "newest", name: "Newest Arrivals" },
{ key: "rating", name: "Customer Rating" },
{ key: "discount", name: "Discount: High to Low" }
];
export default function Page() {
const min_price = 5;
const max_price = 1240;
const [value, setValue] = useState([min_price, max_price]);
const formatPrice = (price: number) => {
return price === max_price ? `$${price.toLocaleString()}+` : `$${price.toLocaleString()}`;
};
return (
<section className="py-10 lg:py-20">
<div className="container mx-auto px-4">
<div className="grid grid-cols-[240px_1fr] gap-8">
<div></div>
<header className="mb-6 flex items-center justify-between space-y-2">
<h2 className="font-heading text-2xl lg:text-3xl">New Season Products</h2>
<Select defaultValue={sortFilters[0].key}>
<SelectTrigger>
<span className="text-muted-foreground text-sm">Sort by</span>
<SelectValue placeholder="Sort" />
</SelectTrigger>
<SelectContent className="[&_*[role=option]]:ps-2 [&_*[role=option]]:pe-8 [&_*[role=option]>span]:start-auto [&_*[role=option]>span]:end-2">
{sortFilters.map((item, i) => (
<SelectItem key={item.key} value={item.key}>
{item.name}
</SelectItem>
))}
</SelectContent>
</Select>
</header>
</div>
<div className="grid grid-cols-[240px_1fr] gap-8">
<div className="space-y-10">
{/* Filter group */}
<div className="space-y-4">
<div className="text-muted-foreground flex justify-between text-[11px] font-semibold tracking-widest uppercase">
Keywords
</div>
<Input type="text" placeholder="Search..." />
</div>
{/* Filter group */}
<div className="space-y-4">
<div className="text-muted-foreground flex justify-between text-sm">
<span className="text-muted-foreground flex justify-between text-[11px] font-semibold tracking-widest uppercase">
Price
</span>
<Label className="text-xs">
From {formatPrice(value[0])} to {formatPrice(value[1])}
</Label>
</div>
<div className="*:not-first:mt-3">
<Slider
value={value}
onValueChange={setValue}
min={min_price}
max={max_price}
aria-label="Price range slider"
/>
</div>
</div>
{/* Filter group */}
<div className="space-y-4">
<div className="text-muted-foreground flex justify-between text-[11px] font-semibold tracking-widest uppercase">
Categories
</div>
<div className="space-y-3">
{categories.map((item, i) => (
<div className="flex items-center gap-2">
<Checkbox id={`category-${i}`} />
<Label htmlFor={`category-${i}`} className="text-muted-foreground">
{item.name}
</Label>
</div>
))}
</div>
</div>
{/* Filter group */}
<div className="space-y-4">
<div className="text-muted-foreground flex justify-between text-[11px] font-semibold tracking-widest uppercase">
Colours
</div>
<fieldset>
<RadioGroup className="flex flex-col gap-3" defaultValue="Blue">
{colorFilters.map((item, i) => (
<div className="flex items-center gap-2">
<RadioGroupItem
id={`color-${i}`}
value={item.name}
aria-label="Blue"
className={cn("size-4", item.classNames)}
/>
<Label htmlFor={`color-${i}`} className="text-muted-foreground">
{item.name}
</Label>
</div>
))}
</RadioGroup>
</fieldset>
</div>
{/* Filter group */}
<div className="space-y-4">
<div className="text-muted-foreground flex justify-between text-[11px] font-semibold tracking-widest uppercase">
Sizes
</div>
<div className="space-y-3">
{sizes.map((item, i) => (
<div className="flex items-center gap-2">
<Checkbox id={`size-${i}`} />
<Label htmlFor={`size-${i}`} className="text-muted-foreground">
{item.name}
</Label>
</div>
))}
</div>
</div>
</div>
<div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3 lg:gap-6">
{products.map((product, i) => (
<Product key={i} product={product} />
))}
</div>
</div>
</div>
</div>
</section>
);
}
const Product = ({ product }: { product: Product }) => (
<Link href="#" className="group">
<figure className="relative aspect-9/16 w-full overflow-hidden object-cover">
<Image
fill
className="object-cover transition-transform duration-300 group-hover:scale-105 group-hover:rotate-2"
src={product.image}
alt={product.title}
/>
</figure>
<div className="mt-3 space-y-0.5">
<p className="font-medium">{product.title}</p>
<p className="text-muted-foreground">{product.price}</p>
</div>
</Link>
);