/**
* 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 (
);
}