'use client'; import { useRef } from 'react'; import { motion, useMotionTemplate, useMotionValue } from 'framer-motion'; import { useLocale } from '@/lib/i18n/locale-context'; import { SectionHeader } from '@/components/ui/SectionHeader'; import { cn } from '@/lib/utils'; import { ServiceIcon, type ServiceIconKind } from './ServiceIcon'; const FA_DIGITS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'] as const; function num(n: number, locale: 'fa' | 'en') { const str = n.toString().padStart(2, '0'); return locale === 'fa' ? str.replace(/\d/g, (d) => FA_DIGITS[Number(d)]) : str; } const COLOR_MAP: Record< string, { text: string; ring: string; glow: string; chip: string } > = { electric: { text: 'text-electric', ring: 'group-hover:border-electric/50', glow: 'group-hover:shadow-glow-electric', chip: 'border-electric/30 bg-electric/5 text-electric/90', }, violet: { text: 'text-violet', ring: 'group-hover:border-violet/50', glow: 'group-hover:shadow-glow-violet', chip: 'border-violet/30 bg-violet/5 text-violet/90', }, magenta: { text: 'text-magenta', ring: 'group-hover:border-magenta/50', glow: 'group-hover:shadow-glow-magenta', chip: 'border-magenta/30 bg-magenta/5 text-magenta/90', }, emerald: { text: 'text-emerald', ring: 'group-hover:border-emerald/50', glow: 'group-hover:shadow-glow-emerald', chip: 'border-emerald/30 bg-emerald/5 text-emerald/90', }, cyan: { text: 'text-cyan', ring: 'group-hover:border-cyan/50', glow: 'group-hover:shadow-glow-electric', chip: 'border-cyan/30 bg-cyan/5 text-cyan/90', }, }; export function Services() { const { t, locale } = useLocale(); return ( {t.services.items.map((item, i) => ( ))} ); } function ServiceCard({ index, numLabel, title, description, tags, color, iconKind, href, locale, }: { index: number; numLabel: string; title: string; description: string; tags: readonly string[]; color: string; iconKind: ServiceIconKind; href: string; locale: 'fa' | 'en'; }) { const ref = useRef(null); const mx = useMotionValue(50); const my = useMotionValue(50); const rotateX = useMotionValue(0); const rotateY = useMotionValue(0); // Subtle 3D tilt on pointer move — keeps the card "alive" without // forcing GPU work when the cursor isn't over it. const onPointerMove = (e: React.PointerEvent) => { const el = ref.current; if (!el) return; const r = el.getBoundingClientRect(); const x = (e.clientX - r.left) / r.width; const y = (e.clientY - r.top) / r.height; mx.set(x * 100); my.set(y * 100); rotateY.set((x - 0.5) * 8); rotateX.set((0.5 - y) * 8); }; const onPointerLeave = () => { rotateX.set(0); rotateY.set(0); }; const spotlight = useMotionTemplate`radial-gradient(220px circle at ${mx}% ${my}%, rgba(255,255,255,0.08), transparent 60%)`; const c = COLOR_MAP[color] ?? COLOR_MAP.electric; return ( {/* Spotlight */} {/* Number + icon row */} {numLabel} {/* Title */} {title} {/* Description */} {description} {/* Tags */} {tags.map((tag) => ( {tag} ))} {/* Hairline */} ); }
{description}