Initial commit: CHORUS Services marketing website
Complete Next.js website with Docker containerization: - Next.js 14 with TypeScript and Tailwind CSS - Responsive design with modern UI components - Hero section, features showcase, testimonials - FAQ section with comprehensive content - Contact forms and newsletter signup - Docker production build with Nginx - Health checks and monitoring support - SEO optimization and performance tuning Ready for integration as git submodule in main CHORUS project. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
100
components/ui/Button.tsx
Normal file
100
components/ui/Button.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Button as AntButton, ButtonProps as AntButtonProps } from 'antd';
|
||||
import { motion, MotionProps } from 'framer-motion';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
// Extend Ant Design ButtonProps with custom variants
|
||||
interface CustomButtonProps {
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'gradient';
|
||||
fullWidth?: boolean;
|
||||
animated?: boolean;
|
||||
}
|
||||
|
||||
type ButtonProps = AntButtonProps & CustomButtonProps & Partial<MotionProps>;
|
||||
|
||||
const MotionButton = motion(AntButton);
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
variant = 'primary',
|
||||
fullWidth = false,
|
||||
animated = true,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const getVariantClasses = () => {
|
||||
switch (variant) {
|
||||
case 'primary':
|
||||
return 'bg-chorus-blue hover:bg-blue-600 border-chorus-blue hover:border-blue-600 text-white shadow-lg hover:shadow-xl';
|
||||
case 'secondary':
|
||||
return 'bg-chorus-green hover:bg-green-600 border-chorus-green hover:border-green-600 text-white shadow-lg hover:shadow-xl';
|
||||
case 'outline':
|
||||
return 'bg-transparent border-2 border-chorus-blue text-chorus-blue hover:bg-chorus-blue hover:text-white';
|
||||
case 'ghost':
|
||||
return 'bg-transparent border-transparent text-white hover:bg-white/10 hover:border-white/20';
|
||||
case 'gradient':
|
||||
return 'bg-gradient-chorus border-transparent text-white shadow-lg hover:shadow-xl';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
const buttonClasses = cn(
|
||||
'font-semibold transition-all duration-200 border-0 rounded-lg',
|
||||
'focus:ring-2 focus:ring-chorus-blue focus:ring-opacity-50 focus:outline-none',
|
||||
getVariantClasses(),
|
||||
fullWidth && 'w-full',
|
||||
className
|
||||
);
|
||||
|
||||
const animationProps = animated
|
||||
? {
|
||||
whileHover: { scale: 1.02 },
|
||||
whileTap: { scale: 0.98 },
|
||||
transition: { duration: 0.2 },
|
||||
}
|
||||
: {};
|
||||
|
||||
if (animated) {
|
||||
return (
|
||||
<MotionButton
|
||||
className={buttonClasses}
|
||||
{...animationProps}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MotionButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AntButton className={buttonClasses} {...props}>
|
||||
{children}
|
||||
</AntButton>
|
||||
);
|
||||
};
|
||||
|
||||
// Specific button variants for common use cases
|
||||
export const PrimaryButton: React.FC<Omit<ButtonProps, 'variant'>> = (props) => (
|
||||
<Button variant="primary" {...props} />
|
||||
);
|
||||
|
||||
export const SecondaryButton: React.FC<Omit<ButtonProps, 'variant'>> = (props) => (
|
||||
<Button variant="secondary" {...props} />
|
||||
);
|
||||
|
||||
export const OutlineButton: React.FC<Omit<ButtonProps, 'variant'>> = (props) => (
|
||||
<Button variant="outline" {...props} />
|
||||
);
|
||||
|
||||
export const GhostButton: React.FC<Omit<ButtonProps, 'variant'>> = (props) => (
|
||||
<Button variant="ghost" {...props} />
|
||||
);
|
||||
|
||||
export const GradientButton: React.FC<Omit<ButtonProps, 'variant'>> = (props) => (
|
||||
<Button variant="gradient" {...props} />
|
||||
);
|
||||
|
||||
export default Button;
|
||||
Reference in New Issue
Block a user