first commit
This commit is contained in:
27
components/skeletons/CartItemSkeleton.tsx
Normal file
27
components/skeletons/CartItemSkeleton.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { Card } from "@/components/ui/card"
|
||||
|
||||
export default function CartItemSkeleton() {
|
||||
return (
|
||||
<Card className="p-4 rounded-xl">
|
||||
<div className="flex gap-4">
|
||||
{/* Product Image */}
|
||||
<Skeleton className="w-24 h-24 rounded-lg flex-shrink-0 bg-gray-200" />
|
||||
|
||||
{/* Product Info */}
|
||||
<div className="flex-1 space-y-2">
|
||||
<Skeleton className="h-4 w-3/4 bg-gray-200" />
|
||||
<Skeleton className="h-4 w-1/2 bg-gray-200" />
|
||||
<Skeleton className="h-6 w-20 bg-gray-200 mt-2" />
|
||||
</div>
|
||||
|
||||
{/* Quantity Controls */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="w-8 h-8 rounded-lg bg-gray-200" />
|
||||
<Skeleton className="w-8 h-8 bg-gray-200" />
|
||||
<Skeleton className="w-8 h-8 rounded-lg bg-gray-200" />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
17
components/skeletons/CategorySkeleton.tsx
Normal file
17
components/skeletons/CategorySkeleton.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { CardContent } from "@/components/ui/card"
|
||||
|
||||
export default function CategorySkeleton() {
|
||||
return (
|
||||
<Card className="overflow-hidden rounded-xl">
|
||||
{/* Image */}
|
||||
<Skeleton className="w-full h-36 bg-gray-200" />
|
||||
|
||||
{/* Name */}
|
||||
<CardContent className="py-2">
|
||||
<Skeleton className="h-4 w-3/4 bg-gray-200" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
30
components/skeletons/HomeSkeleton.tsx
Normal file
30
components/skeletons/HomeSkeleton.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import ProductGridSkeleton from "./ProductGridSkeleton"
|
||||
import CategorySkeleton from "./CategorySkeleton"
|
||||
|
||||
export default function HomeSkeleton() {
|
||||
return (
|
||||
<div className="px-4 md:px-8 lg:px-12 pt-8 pb-12 space-y-8">
|
||||
{/* Hero Carousel Skeleton */}
|
||||
<section className="rounded-2xl overflow-hidden">
|
||||
<Skeleton className="w-full h-[200px] sm:h-[300px] md:h-[420px] bg-gray-200" />
|
||||
</section>
|
||||
|
||||
{/* Categories Section Skeleton */}
|
||||
<section className="bg-white rounded-2xl shadow-sm p-6">
|
||||
<Skeleton className="h-6 w-32 mb-4 bg-gray-200" />
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<CategorySkeleton key={i} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Products Section Skeleton */}
|
||||
<section className="bg-white rounded-2xl shadow-sm p-6">
|
||||
<Skeleton className="h-6 w-32 mb-4 bg-gray-200" />
|
||||
<ProductGridSkeleton count={10} columns="5" />
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
129
components/skeletons/PageLoader.tsx
Normal file
129
components/skeletons/PageLoader.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import ProductGridSkeleton from "./ProductGridSkeleton"
|
||||
import CartItemSkeleton from "./CartItemSkeleton" // Added import for CartItemSkeleton
|
||||
|
||||
interface PageLoaderProps {
|
||||
/**
|
||||
* Type of page loading skeleton
|
||||
* home, products, category, search, cart, favorites, orders, profile
|
||||
*/
|
||||
type?: "home" | "products" | "category" | "search" | "cart" | "favorites" | "orders" | "profile"
|
||||
}
|
||||
|
||||
export default function PageLoader({ type = "products" }: PageLoaderProps) {
|
||||
switch (type) {
|
||||
case "home":
|
||||
return (
|
||||
<div className="px-4 md:px-8 lg:px-12 pt-8 pb-12 space-y-8">
|
||||
{/* Hero Banner */}
|
||||
<Skeleton className="w-full h-[300px] rounded-2xl bg-gray-200" />
|
||||
|
||||
{/* Categories */}
|
||||
<div className="space-y-4">
|
||||
<Skeleton className="h-6 w-32 bg-gray-200" />
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<Skeleton key={i} className="aspect-square bg-gray-200 rounded-xl" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Products */}
|
||||
<div className="space-y-4">
|
||||
<Skeleton className="h-6 w-32 bg-gray-200" />
|
||||
<ProductGridSkeleton count={8} columns="5" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
case "products":
|
||||
case "search":
|
||||
return (
|
||||
<div className="px-4 md:px-8 lg:px-12 py-8">
|
||||
<div className="space-y-4 mb-6">
|
||||
<Skeleton className="h-8 w-40 bg-gray-200" />
|
||||
</div>
|
||||
<ProductGridSkeleton count={12} columns="5" />
|
||||
</div>
|
||||
)
|
||||
|
||||
case "category":
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex gap-6">
|
||||
{/* Filters Sidebar */}
|
||||
<div className="hidden sm:block w-[280px] space-y-6">
|
||||
{Array.from({ length: 3 }).map((_, i) => (
|
||||
<div key={i} className="space-y-2">
|
||||
<Skeleton className="h-5 w-24 bg-gray-200" />
|
||||
<Skeleton className="h-4 w-full bg-gray-200" />
|
||||
<Skeleton className="h-4 w-full bg-gray-200" />
|
||||
<Skeleton className="h-4 w-3/4 bg-gray-200" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Products */}
|
||||
<div className="flex-1">
|
||||
<ProductGridSkeleton count={12} columns="5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
case "cart":
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<Skeleton className="h-8 w-40 mb-6 bg-gray-200" />
|
||||
<div className="flex flex-col md:flex-row gap-6">
|
||||
<div className="flex-1 space-y-4">
|
||||
{Array.from({ length: 3 }).map((_, i) => (
|
||||
<CartItemSkeleton key={i} />
|
||||
))}
|
||||
</div>
|
||||
{/* Order Summary */}
|
||||
<div className="lg:w-[420px]">
|
||||
<div className="space-y-4 bg-gray-50 p-6 rounded-xl">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-4 w-full bg-gray-200" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
case "orders":
|
||||
case "favorites":
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<Skeleton className="h-8 w-40 mb-6 bg-gray-200" />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{Array.from({ length: 6 }).map((_, i) => (
|
||||
<Skeleton key={i} className="h-64 w-full bg-gray-200 rounded-xl" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
case "profile":
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 p-4 pt-20">
|
||||
<div className="container mx-auto max-w-2xl">
|
||||
<Skeleton className="h-8 w-40 mb-6 bg-gray-200" />
|
||||
<div className="bg-white p-6 rounded-xl space-y-4">
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<div key={i} className="space-y-2">
|
||||
<Skeleton className="h-4 w-32 bg-gray-200" />
|
||||
<Skeleton className="h-10 w-full bg-gray-200 rounded-lg" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
default:
|
||||
return <ProductGridSkeleton count={12} columns="5" />
|
||||
}
|
||||
}
|
||||
23
components/skeletons/ProductCardSkeleton.tsx
Normal file
23
components/skeletons/ProductCardSkeleton.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { Card } from "@/components/ui/card"
|
||||
|
||||
export default function ProductCardSkeleton() {
|
||||
return (
|
||||
<Card className="overflow-hidden rounded-xl">
|
||||
{/* Image Skeleton */}
|
||||
<Skeleton className="aspect-square w-full bg-gray-200" />
|
||||
|
||||
{/* Content Skeleton */}
|
||||
<div className="p-3 space-y-3">
|
||||
{/* Title skeleton - 2 lines */}
|
||||
<div className="space-y-2">
|
||||
<Skeleton className="h-4 w-full bg-gray-200" />
|
||||
<Skeleton className="h-4 w-3/4 bg-gray-200" />
|
||||
</div>
|
||||
|
||||
{/* Price skeleton */}
|
||||
<Skeleton className="h-6 w-1/2 bg-gray-200" />
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
24
components/skeletons/ProductGridSkeleton.tsx
Normal file
24
components/skeletons/ProductGridSkeleton.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import ProductCardSkeleton from "./ProductCardSkeleton"
|
||||
|
||||
interface ProductGridSkeletonProps {
|
||||
count?: number
|
||||
columns?: "2" | "3" | "4" | "5"
|
||||
}
|
||||
|
||||
export default function ProductGridSkeleton({ count = 8, columns = "4" }: ProductGridSkeletonProps) {
|
||||
const gridClass =
|
||||
{
|
||||
"2": "grid-cols-2",
|
||||
"3": "md:grid-cols-3",
|
||||
"4": "md:grid-cols-4 lg:grid-cols-4",
|
||||
"5": "md:grid-cols-4 xl:grid-cols-5",
|
||||
}[columns] || "md:grid-cols-4"
|
||||
|
||||
return (
|
||||
<div className={`grid grid-cols-2 sm:grid-cols-3 ${gridClass} gap-4`}>
|
||||
{Array.from({ length: count }).map((_, i) => (
|
||||
<ProductCardSkeleton key={i} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user