sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files: - Quote wizard frontend (all components, hooks, types, config) - API updates (config, models, routers, schemas, services) - Client work (bg-builders, gurushow) - Scripts (BGB Lesley termination, CIPP, Datto, migration) - Temp files (Bardach contacts, VWP investigation, misc) - Credentials and session logs - Email service, PHP API, session logs Machine: ACG-M-L5090 Timestamp: 2026-03-10 19:11:00 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,32 +22,33 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
ref
|
||||
) => {
|
||||
const baseStyles =
|
||||
'inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
|
||||
'inline-flex items-center justify-center font-semibold rounded-xl transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-40 disabled:cursor-not-allowed';
|
||||
|
||||
const variants = {
|
||||
primary:
|
||||
'bg-[#fe7400] text-white hover:bg-[#e56800] focus-visible:ring-[#fe7400] shadow-sm hover:shadow-md',
|
||||
'bg-gradient-accent text-white hover:brightness-110 focus-visible:ring-[#fe7400] shadow-sm hover:shadow-md active:brightness-95',
|
||||
secondary:
|
||||
'bg-[#333d49] text-white hover:bg-[#252d36] focus-visible:ring-[#333d49] shadow-sm hover:shadow-md',
|
||||
outline:
|
||||
'border-2 border-[#333d49] text-[#333d49] hover:bg-[#333d49] hover:text-white focus-visible:ring-[#333d49]',
|
||||
'border-2 border-gray-200 text-[#333d49] hover:border-[#333d49] hover:bg-gray-50 focus-visible:ring-[#333d49]',
|
||||
ghost:
|
||||
'text-[#333d49] hover:bg-gray-100 focus-visible:ring-[#333d49]',
|
||||
'text-[#333d49] hover:bg-gray-100/80 focus-visible:ring-[#333d49]',
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
sm: 'px-3 py-1.5 text-sm',
|
||||
md: 'px-5 py-2.5 text-base',
|
||||
lg: 'px-7 py-3.5 text-lg',
|
||||
sm: 'px-4 py-2 text-sm',
|
||||
md: 'px-6 py-2.5 text-sm',
|
||||
lg: 'px-8 py-3.5 text-base',
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.button
|
||||
ref={ref}
|
||||
whileHover={{ scale: disabled || isLoading ? 1 : 1.02 }}
|
||||
whileTap={{ scale: disabled || isLoading ? 1 : 0.98 }}
|
||||
whileHover={{ scale: disabled || isLoading ? 1 : 1.015 }}
|
||||
whileTap={{ scale: disabled || isLoading ? 1 : 0.985 }}
|
||||
className={cn(baseStyles, variants[variant], sizes[size], className)}
|
||||
disabled={disabled || isLoading}
|
||||
style={{ fontFamily: "'Plus Jakarta Sans', sans-serif" }}
|
||||
{...props}
|
||||
>
|
||||
{isLoading ? (
|
||||
@@ -72,7 +73,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
/>
|
||||
</svg>
|
||||
Loading...
|
||||
Processing...
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
|
||||
@@ -23,13 +23,20 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const baseStyles = 'rounded-xl transition-all duration-200';
|
||||
const baseStyles = 'rounded-2xl transition-all duration-300';
|
||||
|
||||
const variants = {
|
||||
default: 'bg-white border border-gray-200',
|
||||
elevated: 'bg-white shadow-lg',
|
||||
outlined: 'bg-transparent border-2 border-[#333d49]',
|
||||
highlighted: 'bg-white border-2 border-[#fe7400] shadow-lg',
|
||||
default: 'bg-white border border-gray-200/80',
|
||||
elevated: 'bg-white border border-gray-200/60',
|
||||
outlined: 'bg-transparent border-2 border-[#333d49]/20',
|
||||
highlighted: 'bg-white border-2 border-[#fe7400] ring-1 ring-[#fe7400]/10',
|
||||
};
|
||||
|
||||
const shadowStyles: Record<string, React.CSSProperties> = {
|
||||
default: { boxShadow: '0 1px 2px rgba(17,53,89,0.04), 0 4px 12px rgba(17,53,89,0.06)' },
|
||||
elevated: { boxShadow: '0 4px 6px rgba(17,53,89,0.04), 0 12px 32px rgba(17,53,89,0.08)' },
|
||||
outlined: {},
|
||||
highlighted: { boxShadow: '0 4px 6px rgba(17,53,89,0.04), 0 12px 32px rgba(17,53,89,0.08)' },
|
||||
};
|
||||
|
||||
const paddings = {
|
||||
@@ -40,15 +47,15 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
};
|
||||
|
||||
const hoverStyles = hoverable
|
||||
? 'cursor-pointer hover:shadow-xl hover:-translate-y-1'
|
||||
? 'cursor-pointer hover:-translate-y-0.5'
|
||||
: '';
|
||||
|
||||
if (hoverable) {
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
whileHover={{ scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
whileHover={{ scale: 1.01, boxShadow: '0 2px 4px rgba(17,53,89,0.06), 0 8px 24px rgba(17,53,89,0.1)' }}
|
||||
whileTap={{ scale: 0.995 }}
|
||||
className={cn(
|
||||
baseStyles,
|
||||
variants[variant],
|
||||
@@ -56,6 +63,7 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
hoverStyles,
|
||||
className
|
||||
)}
|
||||
style={shadowStyles[variant]}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
@@ -72,6 +80,7 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
paddings[padding],
|
||||
className
|
||||
)}
|
||||
style={shadowStyles[variant]}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
@@ -82,7 +91,6 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||
|
||||
Card.displayName = 'Card';
|
||||
|
||||
// Card subcomponents
|
||||
const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div
|
||||
@@ -99,6 +107,7 @@ const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingEleme
|
||||
<h3
|
||||
ref={ref}
|
||||
className={cn('text-xl font-semibold text-[#333d49]', className)}
|
||||
style={{ fontFamily: "'Plus Jakarta Sans', sans-serif" }}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -109,7 +118,7 @@ const CardDescription = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLPara
|
||||
({ className, ...props }, ref) => (
|
||||
<p
|
||||
ref={ref}
|
||||
className={cn('text-sm text-gray-500 mt-1', className)}
|
||||
className={cn('text-sm text-gray-400 mt-1', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -16,7 +16,8 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="block text-sm font-medium text-[#333d49] mb-1.5"
|
||||
className="block text-sm font-medium text-[#333d49] mb-2"
|
||||
style={{ fontFamily: "'Plus Jakarta Sans', sans-serif" }}
|
||||
>
|
||||
{label}
|
||||
</label>
|
||||
@@ -26,13 +27,13 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
type={type}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'w-full px-4 py-2.5 rounded-lg border transition-all duration-200',
|
||||
'text-[#333d49] placeholder-gray-400',
|
||||
'w-full px-4 py-3 rounded-xl border transition-all duration-200',
|
||||
'text-[#333d49] placeholder-gray-400 bg-white',
|
||||
'focus:outline-none focus:ring-2 focus:ring-offset-0',
|
||||
error
|
||||
? 'border-red-500 focus:border-red-500 focus:ring-red-200'
|
||||
: 'border-gray-300 focus:border-[#fe7400] focus:ring-[#fe7400]/20',
|
||||
'disabled:bg-gray-50 disabled:text-gray-500 disabled:cursor-not-allowed',
|
||||
? 'border-red-400 focus:border-red-400 focus:ring-red-100'
|
||||
: 'border-gray-200 hover:border-gray-300 focus:border-[#fe7400] focus:ring-[#fe7400]/15',
|
||||
'disabled:bg-gray-50 disabled:text-gray-400 disabled:cursor-not-allowed',
|
||||
className
|
||||
)}
|
||||
aria-invalid={error ? 'true' : 'false'}
|
||||
@@ -42,12 +43,15 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
{...props}
|
||||
/>
|
||||
{error && (
|
||||
<p id={`${inputId}-error`} className="mt-1.5 text-sm text-red-500">
|
||||
<p id={`${inputId}-error`} className="mt-2 text-sm text-red-500 flex items-center gap-1.5">
|
||||
<svg className="w-3.5 h-3.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
{helperText && !error && (
|
||||
<p id={`${inputId}-helper`} className="mt-1.5 text-sm text-gray-500">
|
||||
<p id={`${inputId}-helper`} className="mt-2 text-sm text-gray-400">
|
||||
{helperText}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -19,26 +19,26 @@ export function ProgressBar({
|
||||
const clampedProgress = Math.min(100, Math.max(0, progress));
|
||||
|
||||
const sizes = {
|
||||
sm: 'h-1.5',
|
||||
md: 'h-2.5',
|
||||
lg: 'h-4',
|
||||
sm: 'h-1',
|
||||
md: 'h-1.5',
|
||||
lg: 'h-2.5',
|
||||
};
|
||||
|
||||
const variants = {
|
||||
default: 'bg-[#333d49]',
|
||||
accent: 'bg-[#fe7400]',
|
||||
accent: 'bg-gradient-accent',
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('w-full', className)}>
|
||||
{showLabel && (
|
||||
<div className="flex justify-between items-center mb-1.5">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm font-medium text-[#333d49]">Progress</span>
|
||||
<span className="text-sm font-medium text-[#333d49]">{clampedProgress}%</span>
|
||||
<span className="text-sm font-semibold text-[#fe7400]">{clampedProgress}%</span>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn('w-full bg-gray-200 rounded-full overflow-hidden', sizes[size])}
|
||||
className={cn('w-full bg-gray-100 rounded-full overflow-hidden', sizes[size])}
|
||||
role="progressbar"
|
||||
aria-valuenow={clampedProgress}
|
||||
aria-valuemin={0}
|
||||
@@ -48,7 +48,7 @@ export function ProgressBar({
|
||||
className={cn('h-full rounded-full', variants[variant])}
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${clampedProgress}%` }}
|
||||
transition={{ duration: 0.5, ease: 'easeOut' }}
|
||||
transition={{ duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user