/** * PageSkeleton — pixel-perfect loading skeletons that EXACTLY match each page's * actual DOM structure. * * KEY PRINCIPLE: When the real content loads and replaces the skeleton, there * must be ZERO layout shift. Every skeleton block has the same width, height, * padding, margin, border-radius, and position as its real counterpart. * * The shimmer class is defined in globals.css. */ type Variant = | 'home' | 'categories' | 'product' | 'cart' | 'checkout' | 'orders' | 'search' | 'profile' | 'login' | 'ai-chat' | 'videos' | 'live' | 'group-buy' | 'wishlist' | 'link-account' | 'telegram' | 'payment' | 'seller-dashboard' | 'seller-products' | 'seller-orders' | 'seller-profile' | 'seller-go-live' | 'seller-videos' | 'seller-stories' | 'seller-settings' | 'seller-academy' | 'become-seller' | 'settings' | 'messenger' | 'notifications' | 'create' | 'minimal'; export function PageSkeleton({ variant = 'minimal' }: { variant?: Variant }) { switch (variant) { case 'home': return ; case 'categories': return ; case 'product': return ; case 'cart': return ; case 'checkout': return ; case 'orders': return ; case 'search': return ; case 'profile': return ; case 'login': return ; case 'ai-chat': return ; case 'videos': return ; case 'live': return ; case 'group-buy': return ; case 'wishlist': return ; case 'link-account': return ; case 'telegram': return ; case 'payment': return ; case 'seller-dashboard': return ; case 'seller-products': return ; case 'seller-orders': return ; case 'seller-profile': return ; case 'seller-go-live': return ; case 'seller-videos': return ; case 'seller-stories': return ; case 'seller-settings': return ; case 'seller-academy': return ; case 'become-seller': return ; case 'settings': return ; case 'messenger': return ; case 'notifications': return ; case 'create': return ; default: return ; } } // ---- Reusable shimmer block ---- function S({ className = '' }: { className?: string }) { return
; } // ============================================================ // HOME (feed) — matches page.tsx exactly: // top bar (logo+search+icons) → stories bar → live banner → feed posts // ============================================================ function HomeSkeleton() { return (
{/* Top bar: logo + search + icons */}
{/* Stories bar */}
{Array.from({ length: 6 }).map((_, i) => (
))}
{/* Live banner */}
{/* Feed posts — match FeedPostCard structure */} {Array.from({ length: 2 }).map((_, i) => (
{/* Seller header */}
{/* Media — aspect-square */} {/* Action bar */}
{/* Likes + caption */}
))}
); } // ============================================================ // CATEGORIES — matches categories/page.tsx: // search bar (sticky) → category tabs → subcategory grid → sort bar → 2-col grid // ============================================================ function CategoriesSkeleton() { return (
{/* Search bar */}
{/* Category tabs */}
{Array.from({ length: 7 }).map((_, i) => ( ))}
{/* Subcategory grid (5-col) */}
{Array.from({ length: 10 }).map((_, i) => (
))}
{/* Sort bar */}
{/* Product grid 2-col — matches MobileCategoryProductCard */}
{Array.from({ length: 8 }).map((_, i) => (
))}
); } // ============================================================ // PRODUCT DETAIL — matches product/page.tsx: // back btn → image gallery → price → title → trust badges → seller card → // group buy banner → reviews → details → bottom action bar // ============================================================ function ProductSkeleton() { return (
{/* Top bar with back button */}
{/* Image gallery — aspect-square */} {/* Image dots */}
{Array.from({ length: 4 }).map((_, i) => ( ))}
{/* Price + title */}
{/* Trust badges */}
{/* Group buy banner */}
{/* Seller card */}
{/* Reviews section */}
{/* Bottom action bar — fixed */}
); } // ============================================================ // CART — matches cart/page.tsx: // header → cart items (image + name + qty controls) → summary // ============================================================ function CartSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => (
))} {/* Summary */}
); } // ============================================================ // CHECKOUT — matches checkout/page.tsx: // header → shipping form fields → payment method card → place order button // ============================================================ function CheckoutSkeleton() { return (
{/* Shipping form */}
{/* Payment method */} {/* Place order button */}
); } // ============================================================ // ORDERS — matches orders/page.tsx: // header → order cards (header + item thumbnails + total) // ============================================================ function OrdersSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
{/* Order header */}
{/* Item thumbnails */}
{/* Total */}
))}
); } // ============================================================ // SEARCH — matches search/page.tsx: // header (search bar + tabs) → AI answer bubble → product grid → follow-up input // ============================================================ function SearchSkeleton() { return (
{/* Header with search + tabs */}
{/* User query bubble */}
{/* AI answer */}
{/* Product recommendations */}
{Array.from({ length: 4 }).map((_, i) => (
))}
{/* Follow-up input bar */}
); } // ============================================================ // PROFILE — matches profile/page.tsx: // header → user card → stats grid → menu items → logout // ============================================================ function ProfileSkeleton() { return (
{/* User card */}
{/* Stats grid */}
{Array.from({ length: 3 }).map((_, i) => (
))}
{/* Menu items */} {Array.from({ length: 5 }).map((_, i) => (
))}
); } // ============================================================ // LOGIN — matches login/page.tsx: // centered logo → title → tab switcher → email/password form → submit button // ============================================================ function LoginSkeleton() { return (
{/* Tab switcher */} {/* Form fields */}
); } // ============================================================ // AI CHAT — matches ai-chat/page.tsx: // header → messages (user bubble + AI bubble) → suggestion chips → input bar // ============================================================ function AIChatSkeleton() { return (
{/* Header */}
{/* Messages */}
{/* Suggestion chips */}
{Array.from({ length: 3 }).map((_, i) => ( ))}
{/* Input bar */}
); } // ============================================================ // VIDEOS — TikTok-style vertical feed: // full-screen video cards with right action rail + bottom caption // ============================================================ function VideosSkeleton() { return (
{Array.from({ length: 2 }).map((_, i) => (
{/* Right action rail */}
{/* Bottom caption */}
))}
); } // ============================================================ // LIVE — matches live/page.tsx: // header → "LIVE NOW" section → grid of live session cards // ============================================================ function LiveSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => (
))}
); } // ============================================================ // GROUP BUY — matches group-buy/page.tsx: // back link → group buy banner → product card → join section // ============================================================ function GroupBuySkeleton() { return (
{/* Group buy banner */} {/* Product card */}
{/* Join section */}
); } // ============================================================ // WISHLIST — matches wishlist/page.tsx: // header → list of product cards (image + name + price + remove) // ============================================================ function WishlistSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
); } // ============================================================ // LINK ACCOUNT — matches link-account/page.tsx: // back link → header card → info card → steps // ============================================================ function LinkAccountSkeleton() { return (
); } // ============================================================ // TELEGRAM — matches telegram/page.tsx: // back link → header → channel info card → features list // ============================================================ function TelegramSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => ( ))}
); } // ============================================================ // PAYMENT — matches payment/page.tsx: // steps indicator → payment details card → status card // ============================================================ function PaymentSkeleton() { return (
{/* Steps indicator */}
{Array.from({ length: 3 }).map((_, i) => ( ))}
{/* Payment details */} {/* Status */}
); } // ============================================================ // SELLER DASHBOARD — matches seller-dashboard/page.tsx: // header → store profile card → stats grid → menu sections // ============================================================ function SellerDashboardSkeleton() { return (
{/* Store header */}
{/* Stats grid */}
{Array.from({ length: 4 }).map((_, i) => (
))}
{/* Menu sections */} {Array.from({ length: 3 }).map((_, section) => (
{Array.from({ length: 3 }).map((_, i) => (
))}
))}
); } // ============================================================ // SELLER PRODUCTS — matches seller/products/page.tsx: // header → search bar → product grid with edit/delete overlays // ============================================================ function SellerProductsSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => (
))}
); } // ============================================================ // SELLER ORDERS — matches seller/orders/page.tsx: // header → order list with item breakdown // ============================================================ function SellerOrdersSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
); } // ============================================================ // SELLER PROFILE (edit) — matches seller/profile/page.tsx: // header → logo upload → form fields → save button // ============================================================ function SellerProfileSkeleton() { return (
); } // ============================================================ // SELLER GO LIVE — matches seller/go-live/page.tsx: // header → form → active session card // ============================================================ function SellerGoLiveSkeleton() { return (
); } // ============================================================ // SELLER VIDEOS — matches seller/videos/page.tsx: // header → post form → video list // ============================================================ function SellerVideosSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => (
))}
); } // ============================================================ // SELLER STORIES — matches seller/stories/page.tsx: // header → story type selector → form // ============================================================ function SellerStoriesSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => ( ))}
); } // ============================================================ // SELLER SETTINGS — matches seller/settings/page.tsx: // header → account → notifications → region → security → danger zone // ============================================================ function SellerSettingsSkeleton() { return (
{Array.from({ length: 4 }).map((_, section) => (
{Array.from({ length: 3 }).map((_, i) => (
))}
))}
); } // ============================================================ // SELLER ACADEMY — matches seller/academy/page.tsx: // header → hero card → course cards grid // ============================================================ function SellerAcademySkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
); } // ============================================================ // BECOME SELLER — matches become-seller/page.tsx: // header + progress bar → form fields // ============================================================ function BecomeSellerSkeleton() { return (
{Array.from({ length: 3 }).map((_, i) => ( ))}
{Array.from({ length: 3 }).map((_, i) => ( ))}
); } // ============================================================ // SETTINGS — matches settings/page.tsx: // header → account → preferences → selling → support → security // ============================================================ function SettingsSkeleton() { return (
{Array.from({ length: 5 }).map((_, section) => (
{Array.from({ length: 3 }).map((_, i) => (
))}
))}
); } // ============================================================ // MESSENGER — matches messenger/page.tsx: // header → tabs → conversation list // ============================================================ function MessengerSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => ( ))}
{Array.from({ length: 5 }).map((_, i) => (
))}
); } // ============================================================ // NOTIFICATIONS — matches notifications/page.tsx: // header → notification list with typed icons // ============================================================ function NotificationsSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => (
))}
); } // ============================================================ // CREATE — matches create/page.tsx: // header → option cards // ============================================================ function CreateSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
); } // ============================================================ // MINIMAL (fallback) // ============================================================ function MinimalSkeleton() { return (
); }