151 lines
5.4 KiB
TypeScript
151 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { motion, useSpring } from "framer-motion";
|
|
import React, { useState } from "react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface Services19Props {
|
|
className?: string;
|
|
}
|
|
|
|
const Services19 = ({ className }: Services19Props) => {
|
|
const SPRING = {
|
|
mass: 0.1,
|
|
stiffness: 100,
|
|
damping: 10,
|
|
};
|
|
|
|
const xSpring = useSpring(0, SPRING);
|
|
const ySpring = useSpring(0, SPRING);
|
|
const scaleSpring = useSpring(0, SPRING);
|
|
const opacity = useSpring(0, SPRING);
|
|
|
|
const services = [
|
|
{
|
|
title: "هویت برند",
|
|
categories: ["طراحی لوگو", "راهنمای برند"],
|
|
subcategories: ["هویت بصری", "استراتژی برند"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img1.png",
|
|
},
|
|
{
|
|
title: "طراحی رابط کاربری/تجربه کاربری",
|
|
categories: ["رابط کاربری", "تجربه کاربری"],
|
|
subcategories: ["وایرفریم", "نمونهسازی"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img2.png",
|
|
},
|
|
{
|
|
title: "توسعه وب",
|
|
categories: ["فرانتاند", "بکاند"],
|
|
subcategories: ["طراحی واکنشگرا", "یکپارچهسازی اتصال هوشمند"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img3.png",
|
|
},
|
|
{
|
|
title: "بازاریابی دیجیتال",
|
|
categories: ["بهینهسازی سئو", "استراتژی محتوا"],
|
|
subcategories: ["شبکههای اجتماعی", "تحلیل"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img4.png",
|
|
},
|
|
{
|
|
title: "طراحی گرافیک",
|
|
categories: ["طراحی چاپ", "داراییهای دیجیتال"],
|
|
subcategories: ["بروشور", "گرافیک شبکههای اجتماعی"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img5.png",
|
|
},
|
|
{
|
|
title: "مشاوره",
|
|
categories: ["برنامهریزی استراتژیک", "تحلیل کسبوکار"],
|
|
subcategories: ["تحقیق بازار", "تحلیل رقبا"],
|
|
image: "/block-media/shadcnblocks/block/guri4/img6.png",
|
|
},
|
|
];
|
|
|
|
const handlePointerMove = (e: React.PointerEvent<HTMLTableElement>) => {
|
|
const bounds = e.currentTarget.getBoundingClientRect();
|
|
xSpring.set(e.clientX - bounds.left + 20);
|
|
ySpring.set(e.clientY - bounds.top + 20);
|
|
};
|
|
|
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
|
|
return (
|
|
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
|
<div className="container">
|
|
<div className="flex flex-col items-center justify-center gap-15">
|
|
<h1 className="text-xl font-medium tracking-tighter lg:text-2xll">
|
|
خدماتی که{" "}
|
|
<span className="font-instrumentSerif text-2xll font-normal italic lg:text-2xll">
|
|
ارائه میدهیم
|
|
</span>
|
|
<sup className="ps-2 align-top text-sm font-normal tracking-normal">
|
|
[۰۴]
|
|
</sup>
|
|
</h1>
|
|
<div className="relative w-full">
|
|
<table
|
|
onPointerMove={handlePointerMove}
|
|
onPointerEnter={() => {
|
|
opacity.set(1);
|
|
scaleSpring.set(1);
|
|
}}
|
|
onPointerLeave={() => {
|
|
opacity.set(0);
|
|
scaleSpring.set(0);
|
|
}}
|
|
className="w-full"
|
|
>
|
|
<tbody>
|
|
{services.map((service, index) => (
|
|
<tr
|
|
key={index}
|
|
onPointerEnter={() => {
|
|
setCurrentIndex(index);
|
|
}}
|
|
className="group relative cursor-pointer border-b"
|
|
>
|
|
<td className="py-5">
|
|
<h3 className="text-xl font-medium tracking-tight lg:text-xl">
|
|
{service.title}
|
|
</h3>
|
|
</td>
|
|
<td className="hidden lg:table-cell">
|
|
<div className="w-full max-w-2xs pe-5 text-center text-sm tracking-tighter text-foreground/30 group-hover:text-foreground lg:text-base">
|
|
<p>{service.categories[0]}</p>
|
|
<p>{service.categories[1]}</p>
|
|
</div>
|
|
</td>
|
|
<td className="text-end text-sm tracking-tighter text-foreground/30 group-hover:text-foreground lg:text-base">
|
|
<div>
|
|
<p>{service.subcategories[0]}</p>
|
|
<p>{service.subcategories[1]}</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
{/* Cursor-following image */}
|
|
<motion.div
|
|
className="pointer-events-none absolute top-0 start-0 hidden size-40 border sm:block"
|
|
style={{
|
|
x: xSpring,
|
|
y: ySpring,
|
|
opacity: opacity,
|
|
scale: scaleSpring,
|
|
}}
|
|
>
|
|
<img
|
|
src={services[currentIndex].image}
|
|
alt={services[currentIndex].title}
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Services19 };
|