'use client'; /** * 스켈레톤 컴포넌트 시스템 * * 사용 가이드: * - Skeleton: 기본 스켈레톤 (커스텀 크기) * - TableRowSkeleton: 테이블 행 스켈레톤 * - TableSkeleton: 테이블 전체 스켈레톤 * - MobileCardSkeleton: 모바일 카드 스켈레톤 * - FormFieldSkeleton: 폼 필드 스켈레톤 * - DetailPageSkeleton: 상세 페이지 스켈레톤 * - StatCardSkeleton: 통계 카드 스켈레톤 * - ListPageSkeleton: 리스트 페이지 스켈레톤 */ import { cn } from '@/lib/utils'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; // ============================================ // 1. 기본 스켈레톤 (기존) // ============================================ interface SkeletonProps extends React.HTMLAttributes { className?: string; } function Skeleton({ className, ...props }: SkeletonProps) { return (
); } // ============================================ // 2. 테이블 행 스켈레톤 // ============================================ interface TableRowSkeletonProps { columns?: number; showCheckbox?: boolean; showActions?: boolean; } function TableRowSkeleton({ columns = 5, showCheckbox = true, showActions = true, }: TableRowSkeletonProps) { const totalCols = columns + (showCheckbox ? 1 : 0) + (showActions ? 1 : 0); return ( {showCheckbox && ( )} {Array.from({ length: columns }).map((_, i) => ( ))} {showActions && ( )} ); } // ============================================ // 3. 테이블 전체 스켈레톤 // ============================================ interface TableSkeletonProps { rows?: number; columns?: number; showCheckbox?: boolean; showActions?: boolean; showHeader?: boolean; } function TableSkeleton({ rows = 5, columns = 5, showCheckbox = true, showActions = true, showHeader = true, }: TableSkeletonProps) { return (
{showHeader && ( {showCheckbox && ( )} {Array.from({ length: columns }).map((_, i) => ( ))} {showActions && ( )} )} {Array.from({ length: rows }).map((_, i) => ( ))}
); } // ============================================ // 4. 모바일 카드 스켈레톤 // ============================================ interface MobileCardSkeletonProps { showCheckbox?: boolean; showBadge?: boolean; fields?: number; showActions?: boolean; } function MobileCardSkeleton({ showCheckbox = true, showBadge = true, fields = 4, showActions = true, }: MobileCardSkeletonProps) { return ( {/* 헤더 영역 */}
{showCheckbox && }
{showBadge && }
{/* 정보 그리드 */}
{Array.from({ length: fields }).map((_, i) => (
))}
{/* 액션 버튼 */} {showActions && (
)}
); } // ============================================ // 5. 모바일 카드 그리드 스켈레톤 // ============================================ interface MobileCardGridSkeletonProps { count?: number; showCheckbox?: boolean; showBadge?: boolean; fields?: number; showActions?: boolean; } function MobileCardGridSkeleton({ count = 6, showCheckbox = true, showBadge = true, fields = 4, showActions = true, }: MobileCardGridSkeletonProps) { return (
{Array.from({ length: count }).map((_, i) => ( ))}
); } // ============================================ // 6. 폼 필드 스켈레톤 // ============================================ interface FormFieldSkeletonProps { showLabel?: boolean; type?: 'input' | 'textarea' | 'select'; } function FormFieldSkeleton({ showLabel = true, type = 'input', }: FormFieldSkeletonProps) { return (
{showLabel && }
); } // ============================================ // 7. 폼 섹션 스켈레톤 // ============================================ interface FormSectionSkeletonProps { title?: boolean; fields?: number; columns?: 1 | 2 | 3; } function FormSectionSkeleton({ title = true, fields = 4, columns = 2, }: FormSectionSkeletonProps) { const gridCols = { 1: 'grid-cols-1', 2: 'grid-cols-1 md:grid-cols-2', 3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3', }; return ( {title && ( )}
{Array.from({ length: fields }).map((_, i) => ( ))}
); } // ============================================ // 8. 상세 페이지 스켈레톤 // ============================================ interface DetailPageSkeletonProps { sections?: number; fieldsPerSection?: number; showHeader?: boolean; } function DetailPageSkeleton({ sections = 2, fieldsPerSection = 6, showHeader = true, }: DetailPageSkeletonProps) { return (
{/* 페이지 헤더 */} {showHeader && (
)} {/* 섹션들 */} {Array.from({ length: sections }).map((_, i) => ( ))}
); } // ============================================ // 9. 통계 카드 스켈레톤 // ============================================ interface StatCardSkeletonProps { showIcon?: boolean; showTrend?: boolean; } function StatCardSkeleton({ showIcon = true, showTrend = true, }: StatCardSkeletonProps) { return (
{showTrend && }
{showIcon && }
); } // ============================================ // 10. 통계 카드 그리드 스켈레톤 // ============================================ interface StatCardGridSkeletonProps { count?: number; showIcon?: boolean; showTrend?: boolean; } function StatCardGridSkeleton({ count = 4, showIcon = true, showTrend = true, }: StatCardGridSkeletonProps) { return (
{Array.from({ length: count }).map((_, i) => ( ))}
); } // ============================================ // 11. 리스트 페이지 스켈레톤 (통합) // ============================================ interface ListPageSkeletonProps { showHeader?: boolean; showFilters?: boolean; showStats?: boolean; statsCount?: number; tableRows?: number; tableColumns?: number; mobileCards?: number; } function ListPageSkeleton({ showHeader = true, showFilters = true, showStats = false, statsCount = 4, tableRows = 10, tableColumns = 6, mobileCards = 6, }: ListPageSkeletonProps) { return (
{/* 페이지 헤더 */} {showHeader && (
)} {/* 통계 카드 */} {showStats && } {/* 필터 영역 */} {showFilters && (
)} {/* 데스크톱: 테이블 */}
{/* 모바일/태블릿: 카드 그리드 */}
{/* 페이지네이션 */}
); } // ============================================ // 12. 페이지 헤더 스켈레톤 // ============================================ interface PageHeaderSkeletonProps { showActions?: boolean; actionsCount?: number; } function PageHeaderSkeleton({ showActions = true, actionsCount = 2, }: PageHeaderSkeletonProps) { return (
{showActions && (
{Array.from({ length: actionsCount }).map((_, i) => ( ))}
)}
); } // ============================================ // Export // ============================================ export { Skeleton, TableRowSkeleton, TableSkeleton, MobileCardSkeleton, MobileCardGridSkeleton, FormFieldSkeleton, FormSectionSkeleton, DetailPageSkeleton, StatCardSkeleton, StatCardGridSkeleton, ListPageSkeleton, PageHeaderSkeleton, };