All files / src/entities/project/ui/project-card ProjectCardButton.tsx

66.66% Statements 4/6
50% Branches 1/2
33.33% Functions 1/3
66.66% Lines 4/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56                      9x             39x   39x                     39x                                                
import { AnimatePresence, motion } from 'framer-motion';
import React, { type ReactNode, useState } from 'react';
 
interface ProjectCardButtonProps {
	label: string;
	icon: ReactNode;
	color: 'indigo' | 'rose';
	onClick: () => void;
	testId: string;
}
 
export const ProjectCardButton = React.memo(function ProjectCardButton({
	label,
	icon,
	color,
	onClick,
	testId,
}: ProjectCardButtonProps) {
	const [hovered, setHovered] = useState(false);
 
	const colorMap = {
		indigo: {
			text: 'text-indigo-600 hover:text-indigo-700',
			bg: 'from-indigo-400/20 to-indigo-500/20',
		},
		rose: {
			text: 'text-rose-600 hover:text-rose-700',
			bg: 'from-rose-400/20 to-rose-500/20',
		},
	};
 
	const colors = colorMap[color];
 
	return (
		<motion.button
			aria-label={`${label.toLowerCase()} project`}
			data-testid={testId}
			whileHover={{ scale: 1.05 }}
			whileTap={{ scale: 0.96 }}
			onMouseEnter={() => setHovered(true)}
			onMouseLeave={() => setHovered(false)}
			onClick={onClick}
			className={`relative group flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md overflow-hidden cursor-pointer transition-all duration-300 focus:outline-none ${colors.text}`}
		>
			<span className="relative z-10 flex items-center gap-1">
				{label}
				<AnimatePresence>{hovered && icon}</AnimatePresence>
			</span>
 
			<span
				className={`absolute inset-0 bg-gradient-to-r ${colors.bg} opacity-0 group-hover:opacity-60 blur-md transition-opacity rounded-md`}
			/>
		</motion.button>
	);
});