feat(frontend): add skeleton loading state for dashboard

Replace simple spinner with skeleton loading placeholders that match
the dashboard layout structure, providing better visual feedback during
data loading.
This commit is contained in:
Radosław Gierwiało
2025-11-21 21:37:05 +01:00
parent 87b0079b84
commit c15031db9f
3 changed files with 124 additions and 12 deletions

View File

@@ -0,0 +1,115 @@
/**
* Skeleton loading components for dashboard
*/
// Base skeleton with animation
const SkeletonBase = ({ className = '' }) => (
<div className={`animate-pulse bg-gray-200 rounded ${className}`} />
);
// Skeleton for event cards
export const EventCardSkeleton = () => (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-start justify-between mb-3">
<SkeletonBase className="h-6 w-48" />
<SkeletonBase className="h-5 w-16 rounded-full" />
</div>
<div className="space-y-2 mb-3">
<div className="flex items-center gap-2">
<SkeletonBase className="h-4 w-4" />
<SkeletonBase className="h-4 w-32" />
</div>
<div className="flex items-center gap-2">
<SkeletonBase className="h-4 w-4" />
<SkeletonBase className="h-4 w-40" />
</div>
<div className="flex items-center gap-2">
<SkeletonBase className="h-4 w-4" />
<SkeletonBase className="h-4 w-28" />
</div>
</div>
<SkeletonBase className="h-10 w-full" />
</div>
);
// Skeleton for match cards
export const MatchCardSkeleton = () => (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-start gap-4">
<SkeletonBase className="h-12 w-12 rounded-full" />
<div className="flex-1">
<SkeletonBase className="h-5 w-36 mb-1" />
<SkeletonBase className="h-4 w-24 mb-2" />
<SkeletonBase className="h-4 w-32 mb-3" />
<div className="flex gap-4">
<SkeletonBase className="h-4 w-24" />
<SkeletonBase className="h-4 w-24" />
</div>
</div>
<SkeletonBase className="h-10 w-20" />
</div>
</div>
);
// Skeleton for request cards
export const RequestCardSkeleton = () => (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-start gap-4">
<SkeletonBase className="h-10 w-10 rounded-full" />
<div className="flex-1">
<SkeletonBase className="h-5 w-32 mb-1" />
<SkeletonBase className="h-4 w-24 mb-1" />
<SkeletonBase className="h-4 w-28" />
</div>
<div className="flex gap-2">
<SkeletonBase className="h-8 w-8 rounded-full" />
<SkeletonBase className="h-8 w-8 rounded-full" />
</div>
</div>
</div>
);
// Dashboard skeleton layout
export const DashboardSkeleton = () => (
<div className="max-w-5xl mx-auto">
{/* Header skeleton */}
<div className="mb-8">
<SkeletonBase className="h-9 w-48 mb-2" />
<SkeletonBase className="h-5 w-64" />
</div>
{/* Events section */}
<section className="mb-8">
<div className="flex items-center justify-between mb-4">
<SkeletonBase className="h-7 w-36" />
<SkeletonBase className="h-5 w-24" />
</div>
<div className="grid gap-4 md:grid-cols-2">
<EventCardSkeleton />
<EventCardSkeleton />
</div>
</section>
{/* Matches section */}
<section className="mb-8">
<div className="flex items-center justify-between mb-4">
<SkeletonBase className="h-7 w-40" />
<SkeletonBase className="h-5 w-20" />
</div>
<div className="space-y-3">
<MatchCardSkeleton />
<MatchCardSkeleton />
</div>
</section>
{/* Requests section */}
<section className="mb-8">
<SkeletonBase className="h-7 w-44 mb-4" />
<div className="space-y-3">
<RequestCardSkeleton />
</div>
</section>
</div>
);
export default DashboardSkeleton;