first commit

This commit is contained in:
Michaël
2026-01-29 14:13:11 -03:00
commit 2302748c87
105 changed files with 93301 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
'use client';
import { ButtonHTMLAttributes, forwardRef } from 'react';
import clsx from 'clsx';
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
isLoading?: boolean;
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = 'primary', size = 'md', isLoading, children, disabled, ...props }, ref) => {
return (
<button
ref={ref}
disabled={disabled || isLoading}
className={clsx(
'inline-flex items-center justify-center font-medium transition-all duration-200 rounded-btn focus:outline-none focus:ring-2 focus:ring-offset-2',
{
// Variants
'bg-primary-yellow text-primary-dark hover:bg-yellow-400 focus:ring-yellow-400':
variant === 'primary',
'bg-primary-dark text-white hover:bg-gray-800 focus:ring-gray-800':
variant === 'secondary',
'border-2 border-primary-dark text-primary-dark bg-transparent hover:bg-gray-50 focus:ring-gray-400':
variant === 'outline',
'text-primary-dark hover:bg-gray-100 focus:ring-gray-300':
variant === 'ghost',
'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500':
variant === 'danger',
// Sizes
'text-sm px-3 py-1.5': size === 'sm',
'text-base px-5 py-2.5': size === 'md',
'text-lg px-7 py-3': size === 'lg',
// States
'opacity-50 cursor-not-allowed': disabled || isLoading,
},
className
)}
{...props}
>
{isLoading ? (
<>
<svg
className="animate-spin -ml-1 mr-2 h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
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...
</>
) : (
children
)}
</button>
);
}
);
Button.displayName = 'Button';
export default Button;

View File

@@ -0,0 +1,35 @@
'use client';
import { HTMLAttributes, forwardRef } from 'react';
import clsx from 'clsx';
interface CardProps extends HTMLAttributes<HTMLDivElement> {
variant?: 'default' | 'elevated' | 'bordered';
}
const Card = forwardRef<HTMLDivElement, CardProps>(
({ className, variant = 'default', children, ...props }, ref) => {
return (
<div
ref={ref}
className={clsx(
'bg-white rounded-card overflow-hidden',
{
'shadow-card': variant === 'default',
'shadow-card-hover hover:shadow-lg transition-shadow duration-200':
variant === 'elevated',
'border border-secondary-light-gray': variant === 'bordered',
},
className
)}
{...props}
>
{children}
</div>
);
}
);
Card.displayName = 'Card';
export default Card;

View File

@@ -0,0 +1,48 @@
'use client';
import { InputHTMLAttributes, forwardRef } from 'react';
import clsx from 'clsx';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
}
const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, label, error, id, ...props }, ref) => {
return (
<div className="w-full">
{label && (
<label
htmlFor={id}
className="block text-sm font-medium text-primary-dark mb-1.5"
>
{label}
</label>
)}
<input
ref={ref}
id={id}
className={clsx(
'w-full px-4 py-3 rounded-btn border transition-colors duration-200',
'focus:outline-none focus:ring-2 focus:ring-primary-yellow focus:border-transparent',
'placeholder:text-gray-400',
{
'border-secondary-light-gray': !error,
'border-red-500 focus:ring-red-500': error,
},
className
)}
{...props}
/>
{error && (
<p className="mt-1.5 text-sm text-red-600">{error}</p>
)}
</div>
);
}
);
Input.displayName = 'Input';
export default Input;