63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { motion } from 'framer-motion';
|
|
import { useReducedMotion } from '@/hooks/use-reduced-motion';
|
|
import Link from 'next/link';
|
|
import { ArrowRight } from 'lucide-react';
|
|
|
|
export type ServiceColor = 'brand' | 'blue' | 'teal' | 'amber' | 'purple';
|
|
|
|
interface ServiceCardProps {
|
|
number?: string;
|
|
title: string;
|
|
description: string;
|
|
color?: ServiceColor;
|
|
href: string;
|
|
className?: string;
|
|
delay?: number;
|
|
}
|
|
|
|
export function ServiceCard({
|
|
number: _number,
|
|
title,
|
|
description,
|
|
color: _color = 'brand',
|
|
href,
|
|
className = '',
|
|
delay = 0,
|
|
}: ServiceCardProps) {
|
|
const shouldReduceMotion = useReducedMotion();
|
|
|
|
return (
|
|
<motion.div
|
|
className={`group relative bg-[var(--color-bg-primary)] border border-[var(--color-border-primary)] rounded-[var(--radius-lg)] overflow-hidden transition-all duration-normal ease-ink hover:-translate-y-1 hover:shadow-[var(--shadow-lg)] hover:border-[var(--color-brand)]/20 ${className}`}
|
|
initial={shouldReduceMotion ? {} : { opacity: 0, y: 24 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: '-40px' }}
|
|
transition={{ duration: 0.6, delay, ease: [0.22, 1, 0.36, 1] }}
|
|
>
|
|
<div className="p-6 md:p-8">
|
|
{/* Title */}
|
|
<h3 className="text-xl md:text-2xl font-bold mb-3 leading-tight text-[var(--color-text-primary)]">
|
|
{title}
|
|
</h3>
|
|
|
|
{/* Description */}
|
|
<p className="text-sm md:text-base leading-relaxed mb-6 text-[var(--color-text-secondary)]">
|
|
{description}
|
|
</p>
|
|
|
|
{/* Link */}
|
|
<Link
|
|
href={href}
|
|
className="inline-flex items-center text-sm font-medium transition-all duration-fast group-hover:gap-2.5 text-[var(--color-brand)]"
|
|
style={{ minHeight: '44px', minWidth: '44px' }}
|
|
>
|
|
<span>了解详情</span>
|
|
<ArrowRight className="w-4 h-4 transform transition-transform duration-fast group-hover:translate-x-1" />
|
|
</Link>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
}
|