From fc4d7f65867fa185e4180ea77b573482ea904649 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Tue, 5 Aug 2025 22:55:41 +0000 Subject: [PATCH] Create skeleton components for content loading cgen-3c3a5014756149c49ecb7a03bce3a4db --- client/components/Skeleton.tsx | 183 +++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 client/components/Skeleton.tsx diff --git a/client/components/Skeleton.tsx b/client/components/Skeleton.tsx new file mode 100644 index 00000000..c9dbb39a --- /dev/null +++ b/client/components/Skeleton.tsx @@ -0,0 +1,183 @@ +import { cn } from "@/lib/utils"; + +interface SkeletonProps { + className?: string; + variant?: 'text' | 'avatar' | 'card' | 'button' | 'image'; + lines?: number; + animate?: boolean; +} + +export function Skeleton({ className, variant = 'text', lines = 1, animate = true }: SkeletonProps) { + const baseClasses = cn( + "bg-muted rounded", + animate && "skeleton", + className + ); + + switch (variant) { + case 'avatar': + return
; + + case 'button': + return
; + + case 'image': + return
; + + case 'card': + return ( +
+
+
+
+
+ ); + + case 'text': + default: + return ( +
+ {Array.from({ length: lines }).map((_, i) => ( +
+ ))} +
+ ); + } +} + +export function SkeletonCard() { + return ( +
+
+ +
+ + +
+
+ +
+ + +
+
+ ); +} + +export function SkeletonStats() { + return ( +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+
+ +
+
+ + +
+
+ ))} +
+ ); +} + +export function SkeletonUserPath() { + return ( +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+
+ +
+ + +
+
+
+ {Array.from({ length: 4 }).map((_, j) => ( + + ))} +
+ +
+ ))} +
+ ); +} + +export function SkeletonOnboardingStep() { + return ( +
+
+ + +
+ +
+
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ + +
+ ))} +
+
+ +
+ + +
+
+ ); +} + +export function SkeletonLayout() { + return ( +
+ {/* Header Skeleton */} +
+
+
+ + +
+
+ {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+
+ + +
+
+
+ + {/* Content Skeleton */} +
+
+
+ + +
+ + +
+
+ + + +
+
+
+ ); +}