Files
my-loves-calendar/components/Button.tsx
drjones c373bbdab4 first commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 21:05:27 -08:00

52 lines
2.0 KiB
TypeScript

import React from 'react';
import { motion } from 'framer-motion';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
roleTheme?: 'mom' | 'dad' | 'neutral';
isLoading?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
roleTheme = 'neutral',
isLoading,
className = '',
...props
}) => {
let baseStyles = "px-6 py-3 rounded-2xl font-bold transition-all duration-200 flex items-center justify-center gap-2 outline-none focus:ring-4 disabled:opacity-50 disabled:cursor-not-allowed";
const getThemeColors = () => {
if (variant === 'ghost') return "bg-transparent hover:bg-gray-100 text-gray-600 focus:ring-gray-200";
if (variant === 'danger') return "bg-red-100 text-red-600 hover:bg-red-200 focus:ring-red-100";
if (variant === 'secondary') return "bg-white text-gray-700 border-2 border-gray-100 hover:border-gray-200 focus:ring-gray-100";
switch (roleTheme) {
case 'mom':
return "bg-mom-primary text-white hover:bg-pink-500 shadow-lg shadow-pink-200 focus:ring-pink-200";
case 'dad':
return "bg-dad-primary text-white hover:bg-blue-500 shadow-lg shadow-blue-200 focus:ring-blue-200";
default:
return "bg-gray-800 text-white hover:bg-gray-900 shadow-lg shadow-gray-300 focus:ring-gray-200";
}
};
return (
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.95 }}
className={`${baseStyles} ${getThemeColors()} ${className}`}
disabled={isLoading || props.disabled}
{...props}
>
{isLoading ? (
<svg className="animate-spin h-5 w-5" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
) : children}
</motion.button>
);
};