Task: Create Reusable Loading and Error State Components
Overview
Every data-driven page needs consistent loading spinners, skeleton placeholders, and error retry UI. Build shared primitives now so feature pages stay thin later.
Goals
LoadingSpinner — inline and full-page variants
PageSkeleton — generic skeleton for dashboard cards
ErrorState — message + optional retry button
EmptyState — illustration/icon + title + CTA slot
- Use Tailwind animations already in the project
Deliverables
components/ui/loading-spinner.tsx
components/ui/page-skeleton.tsx
components/ui/error-state.tsx
components/ui/empty-state.tsx
- Example usage in
dashboard/page.tsx (toggle via query flag or mock)
Acceptance Criteria
- Components accept
className for layout flexibility
- Error state supports
onRetry callback prop
- Skeleton matches approximate dashboard card dimensions
- All components render without client-only hooks unless necessary
- Documented in a short comment block or README section
Task: Create Reusable Loading and Error State Components
Overview
Every data-driven page needs consistent loading spinners, skeleton placeholders, and error retry UI. Build shared primitives now so feature pages stay thin later.
Goals
LoadingSpinner— inline and full-page variantsPageSkeleton— generic skeleton for dashboard cardsErrorState— message + optional retry buttonEmptyState— illustration/icon + title + CTA slotDeliverables
components/ui/loading-spinner.tsxcomponents/ui/page-skeleton.tsxcomponents/ui/error-state.tsxcomponents/ui/empty-state.tsxdashboard/page.tsx(toggle via query flag or mock)Acceptance Criteria
classNamefor layout flexibilityonRetrycallback prop