feat: image filter

This commit is contained in:
VizoleLabs 2024-04-08 06:22:33 +00:00
parent 7242a0afab
commit 67fe4ba060
10 changed files with 38350 additions and 1079 deletions

View file

@ -0,0 +1,26 @@
export const FilterableData = [
{
name: "Web",
src: "/images/site01.png",
title: "Mountains",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
},
{
name: "UI/UX",
src: "/images/site02.png",
title: "BMW",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
},
{
name: "Web",
src: "/images/site03.png",
title: "Modeller",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
},
{
name: "Web",
src: "/images/site04.png",
title: "Billing App",
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
},
]

View file

@ -0,0 +1,59 @@
"use client"
import { Button } from "components/Button/Button"
import { useState } from "react"
import { Image } from "./image"
import { FilterableData } from "./FilterableData"
import { motion } from "framer-motion" // Import motion
const ImageFilter = () => {
const [activeFilter, setActiveFilter] = useState<string>("all")
const buttonCaptions = ["all", "Web", "Mobile App", "UI/UX"]
const handleFilterClick = (filter: string) => {
setActiveFilter(filter)
}
return (
<section className="mb-3 flex w-full flex-col gap-12 px-5 py-16 md:px-10 lg:px-16">
<div className="flex w-full flex-wrap items-start gap-3 md:justify-center md:gap-6">
{buttonCaptions.map((filter) => (
<button
key={filter}
onClick={() => handleFilterClick(filter)}
type="button"
className={`mb-2 rounded-lg border-2 border-[#F0B37D] px-5 py-2.5 text-sm font-medium capitalize text-white hover:bg-[#F0B37D] focus:outline-none ${
activeFilter === filter ? "bg-[#F0B37D]" : " "
}`}
>
{filter === "all" ? "Show all" : filter}
</button>
))}
{/* filtered cards display */}
</div>
<main className="grid w-full gap-x-5 gap-y-8 md:mt-8 md:grid-cols-2 lg:grid-cols-3">
{FilterableData.map((item, index) => (
<motion.div
key={index}
layout
className={`w-full cursor-pointer rounded-lg border border-gray-600 bg-gray-800 shadow ${
activeFilter === "all" || activeFilter === item.name
? "" /* Show card */
: "hidden" /* Hide if not matched */
}`}
>
<Image
className="h-[400px] w-full overflow-hidden rounded-lg"
image={item.src}
alt={item.name}
objectCover="object-cover"
/>
</motion.div>
))}
</main>
</section>
)
}
export default ImageFilter

View file

@ -0,0 +1,25 @@
type ImageOwnProps<T extends React.ElementType> = {
className: string
image: string
alt: string
objectCover?: string
as?: T
}
type ImageProps<T extends React.ElementType> = ImageOwnProps<T> & Omit<React.ComponentProps<T>, keyof ImageOwnProps<T>>
export const Image = <T extends React.ElementType = "div">({
className,
image,
alt,
objectCover,
as,
...rest
}: ImageProps<T>) => {
const Component = as || "div"
return (
<Component className={className} {...rest}>
<img src={image} alt={alt} className={`h-full w-full ${objectCover}`} />
</Component>
)
}