diff --git a/app/page.tsx b/app/page.tsx index b33db20..4cfacf0 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -332,7 +332,7 @@ export default function Web() { -
+

Contact Us diff --git a/components/ImageFilter/ImageFilter.tsx b/components/ImageFilter/ImageFilter.tsx index 701e584..9c8f796 100644 --- a/components/ImageFilter/ImageFilter.tsx +++ b/components/ImageFilter/ImageFilter.tsx @@ -4,6 +4,7 @@ import { Button } from "components/Button/Button" import { useState } from "react" import { Image } from "./image" import { FilterableData } from "./FilterableData" +import { CardBody, CardContainer, CardItem } from "components/Ui/Card" import { motion } from "framer-motion" // Import motion const ImageFilter = () => { @@ -43,12 +44,16 @@ const ImageFilter = () => { : "hidden" /* Hide if not matched */ }`} > - {item.name} + + + {item.name} + + ))} diff --git a/components/Ui/Card.tsx b/components/Ui/Card.tsx new file mode 100644 index 0000000..a82c9bb --- /dev/null +++ b/components/Ui/Card.tsx @@ -0,0 +1,125 @@ +"use client" + +import { cn } from "./../../utils/cn" +import Image from "next/image" +import React, { createContext, useState, useContext, useRef, useEffect } from "react" + +const MouseEnterContext = createContext<[boolean, React.Dispatch>] | undefined>(undefined) + +export const CardContainer = ({ + children, + className, + containerClassName, +}: { + children?: React.ReactNode + className?: string + containerClassName?: string +}) => { + const containerRef = useRef(null) + const [isMouseEntered, setIsMouseEntered] = useState(false) + + const handleMouseMove = (e: React.MouseEvent) => { + if (!containerRef.current) return + const { left, top, width, height } = containerRef.current.getBoundingClientRect() + const x = (e.clientX - left - width / 2) / 25 + const y = (e.clientY - top - height / 2) / 25 + containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)` + } + + const handleMouseEnter = (e: React.MouseEvent) => { + setIsMouseEntered(true) + if (!containerRef.current) return + } + + const handleMouseLeave = (e: React.MouseEvent) => { + if (!containerRef.current) return + setIsMouseEntered(false) + containerRef.current.style.transform = `rotateY(0deg) rotateX(0deg)` + } + return ( + +
+
+ {children} +
+
+
+ ) +} + +export const CardBody = ({ children, className }: { children: React.ReactNode; className?: string }) => { + return ( +
*]:[transform-style:preserve-3d]", className)}> + {children} +
+ ) +} + +export const CardItem = ({ + as: Tag = "div", + children, + className, + translateX = 0, + translateY = 0, + translateZ = 0, + rotateX = 0, + rotateY = 0, + rotateZ = 0, + ...rest +}: { + as?: React.ElementType + children: React.ReactNode + className?: string + translateX?: number | string + translateY?: number | string + translateZ?: number | string + rotateX?: number | string + rotateY?: number | string + rotateZ?: number | string + [key: string]: any +}) => { + const ref = useRef(null) + const [isMouseEntered] = useMouseEnter() + + useEffect(() => { + handleAnimations() + }, [isMouseEntered]) + + const handleAnimations = () => { + if (!ref.current) return + if (isMouseEntered) { + ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)` + } else { + ref.current.style.transform = `translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)` + } + } + + return ( + + {children} + + ) +} + +// Create a hook to use the context +export const useMouseEnter = () => { + const context = useContext(MouseEnterContext) + if (context === undefined) { + throw new Error("useMouseEnter must be used within a MouseEnterProvider") + } + return context +} diff --git a/yarn.lock b/yarn.lock index b1aaa48..ce2af29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,6 +45,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz" integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== +"@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.16.0", "@babel/core@^7.21.3", "@babel/core@^7.22.0", "@babel/core@^7.22.5", "@babel/core@^7.22.9", "@babel/core@^7.23.3", "@babel/core@^7.7.5": "@babel/core@^7.0.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.16.0", "@babel/core@^7.21.3", "@babel/core@^7.22.0", "@babel/core@^7.22.5", "@babel/core@^7.22.9", "@babel/core@^7.23.3", "@babel/core@^7.7.5": version "7.24.3" resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz" @@ -17365,6 +17366,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"