54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { motion } from "framer-motion";
|
|
import { Code2 } from "lucide-react";
|
|
|
|
interface AnimatedTechItemProps {
|
|
name: string;
|
|
iconName: string | null;
|
|
index: number;
|
|
}
|
|
|
|
export function AnimatedTechItem({ name, iconName, index }: AnimatedTechItemProps) {
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
transition={{
|
|
duration: 0.4,
|
|
delay: index * 0.05,
|
|
ease: [0.25, 0.4, 0.25, 1],
|
|
}}
|
|
whileHover={{
|
|
scale: 1.06,
|
|
y: -4,
|
|
transition: { duration: 0.25, ease: "easeOut" },
|
|
}}
|
|
whileTap={{ scale: 0.97 }}
|
|
className="flex items-center gap-2.5 px-3 py-2.5 rounded-xl bg-muted/50 border border-border/30
|
|
hover:border-accent/40 hover:bg-accent/8 hover:shadow-lg hover:shadow-accent/5
|
|
transition-colors duration-300 cursor-default group/item"
|
|
>
|
|
{iconName ? (
|
|
<motion.img
|
|
src={`https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/${iconName}/${iconName}-original.svg`}
|
|
alt={name}
|
|
className="w-5 h-5 object-contain flex-shrink-0"
|
|
whileHover={{
|
|
rotate: [0, -10, 10, -5, 0],
|
|
transition: { duration: 0.5 },
|
|
}}
|
|
/>
|
|
) : (
|
|
<Code2
|
|
size={16}
|
|
className="text-muted-foreground group-hover/item:text-accent transition-colors flex-shrink-0"
|
|
/>
|
|
)}
|
|
<span className="text-xs font-mono font-medium truncate group-hover/item:text-accent transition-colors duration-300">
|
|
{name}
|
|
</span>
|
|
</motion.div>
|
|
);
|
|
}
|