128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
'use client'
|
|
|
|
import { Suspense, lazy, ComponentType } from 'react'
|
|
import { Skeleton } from '@/components/ui/skeleton'
|
|
|
|
interface LazyComponentProps {
|
|
fallback?: React.ReactNode
|
|
className?: string
|
|
}
|
|
|
|
// Generic lazy loading wrapper
|
|
export function createLazyComponent<T extends ComponentType<any>>(
|
|
importFunction: () => Promise<{ default: T }>,
|
|
fallback?: React.ReactNode
|
|
) {
|
|
const LazyComponent = lazy(importFunction)
|
|
|
|
return function LazyWrapper(props: React.ComponentProps<T> & LazyComponentProps) {
|
|
const { fallback: customFallback, className, ...componentProps } = props
|
|
|
|
const defaultFallback = (
|
|
<div className={className}>
|
|
<Skeleton className="w-full h-64 rounded-lg" />
|
|
</div>
|
|
)
|
|
|
|
return (
|
|
<Suspense fallback={customFallback || defaultFallback}>
|
|
<LazyComponent {...(componentProps as React.ComponentProps<T>)} />
|
|
</Suspense>
|
|
)
|
|
}
|
|
}
|
|
|
|
// Product Grid Skeleton
|
|
export function ProductGridSkeleton({ count = 8 }: { count?: number }) {
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
|
{Array.from({ length: count }).map((_, i) => (
|
|
<div key={i} className="space-y-3">
|
|
<Skeleton className="w-full h-48 rounded-lg" />
|
|
<Skeleton className="h-4 w-3/4" />
|
|
<Skeleton className="h-4 w-1/2" />
|
|
<div className="flex items-center space-x-2">
|
|
<Skeleton className="h-6 w-16" />
|
|
<Skeleton className="h-6 w-20" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Chart Skeleton
|
|
export function ChartSkeleton({ className }: { className?: string }) {
|
|
return (
|
|
<div className={className}>
|
|
<div className="space-y-4">
|
|
<Skeleton className="h-6 w-32" />
|
|
<Skeleton className="h-64 w-full rounded-lg" />
|
|
<div className="flex space-x-4">
|
|
<Skeleton className="h-4 w-16" />
|
|
<Skeleton className="h-4 w-16" />
|
|
<Skeleton className="h-4 w-16" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Dashboard Stats Skeleton
|
|
export function DashboardStatsSkeleton() {
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
{Array.from({ length: 4 }).map((_, i) => (
|
|
<div key={i} className="p-6 bg-white rounded-lg border space-y-2">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="h-8 w-16" />
|
|
<Skeleton className="h-3 w-20" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Table Skeleton
|
|
export function TableSkeleton({ rows = 5, cols = 4 }: { rows?: number, cols?: number }) {
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* Header */}
|
|
<div className="flex space-x-4">
|
|
{Array.from({ length: cols }).map((_, i) => (
|
|
<Skeleton key={i} className="h-4 flex-1" />
|
|
))}
|
|
</div>
|
|
|
|
{/* Rows */}
|
|
{Array.from({ length: rows }).map((_, rowIndex) => (
|
|
<div key={rowIndex} className="flex space-x-4">
|
|
{Array.from({ length: cols }).map((_, colIndex) => (
|
|
<Skeleton key={colIndex} className="h-8 flex-1" />
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Form Skeleton
|
|
export function FormSkeleton() {
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="h-10 w-full" />
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-32" />
|
|
<Skeleton className="h-24 w-full" />
|
|
</div>
|
|
<div className="flex space-x-4">
|
|
<Skeleton className="h-10 w-24" />
|
|
<Skeleton className="h-10 w-20" />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|