Files
Meal-Planner/frontend/src/components/ui/Input.tsx
T
admin 6a0c9d0c4e feat: full UI redesign with design system, Nielsen heuristics compliance
- Install lucide-react, framer-motion, react-hot-toast, clsx, tailwind-merge
- Custom Tailwind config: semantic color tokens, Inter font, shadow scale,
  border radius scale, custom animations (fadeIn, slideUp, shimmer)
- Shared component library: Button, Badge, Card, Input, Select, Textarea,
  EmptyState, Skeleton, LoadingSpinner
- Global CSS with @layer components (.btn, .card, .input, .badge, .skeleton)
- Toast notification system via react-hot-toast + showToast utility
- ErrorBoundary wrapper for graceful error recovery
- Redesigned navigation: sticky, active state indicators, Lucide icons
- Dashboard: hero header, today highlighting, scrollable week grid,
  redesigned meal cards, empty states, skeleton loading
- Meal Detail: hero image with gradient overlay, metadata row with icons,
  Lucide star rating, edit-existing-feedback flow
- Pantry: inline add form, search/filter, visual quantity badges,
  expiry warnings, confirmation dialogs
- Shopping List: gradient summary cards, aisle grouping with badges,
  sale strikethrough pricing, empty state
- Login: centered card with icon, Input component, Button component
- All old gray/blue utility classes migrated to new surface/primary tokens
- TypeScript clean, production build passes
2026-05-14 10:26:53 -07:00

32 lines
903 B
TypeScript

import { forwardRef, type InputHTMLAttributes } from 'react';
import { cn } from '../../lib/utils';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
hint?: string;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ label, error, hint, className, ...props }, ref) => {
return (
<div className="w-full">
{label && <label className="label">{label}</label>}
<input
ref={ref}
className={cn(
'input',
error && 'border-danger-300 focus:border-danger-500 focus:ring-danger-100',
className
)}
{...props}
/>
{error && <p className="mt-1 text-sm text-danger-600">{error}</p>}
{hint && !error && <p className="mt-1 text-sm text-surface-500">{hint}</p>}
</div>
);
}
);
Input.displayName = 'Input';