/** * Preloader Component * * Universal loading indicator component with multiple variants * Supports inline, fullscreen, and custom layouts */ 'use client'; import { Loader2 } from 'lucide-react'; import React from 'react'; import { useAppT } from '@djangocfg/i18n'; import { cn } from '../../../lib/utils'; // Spinner is available for future use // import { Spinner } from './spinner'; export interface PreloaderProps { /** * Loading text to display * @default undefined (no text) */ text?: string; /** * Additional description/subtitle text */ description?: string; /** * Size variant * @default 'md' */ size?: 'sm' | 'md' | 'lg' | 'xl'; /** * Variant: inline (fits container) or fullscreen (fixed overlay) * @default 'inline' */ variant?: 'inline' | 'fullscreen'; /** * Show backdrop (only for fullscreen variant) * @default true */ backdrop?: boolean; /** * Backdrop opacity (0-100, only for fullscreen with backdrop) * @default 80 */ backdropOpacity?: number; /** * Additional CSS classes */ className?: string; /** * Spinner className override */ spinnerClassName?: string; } const sizeMap = { sm: 'h-4 w-4', md: 'h-6 w-6', lg: 'h-8 w-8', xl: 'h-12 w-12', }; /** * Preloader - Universal loading indicator * * Features: * - Multiple size variants (sm, md, lg, xl) * - Inline or fullscreen variants * - Optional text and description * - Optional backdrop for fullscreen * - Accessible (ARIA labels) * * @example * ```tsx * // Inline loading * * * // Fullscreen with backdrop * * * // Custom size * * * // Without text * * ``` */ export function Preloader({ text, description, size = 'md', variant = 'inline', backdrop = true, backdropOpacity = 80, className, spinnerClassName, }: PreloaderProps) { const t = useAppT() const loadingLabel = text || t('ui.states.loading') const spinnerSize = sizeMap[size]; // Fullscreen variant if (variant === 'fullscreen') { const backdropClasses = backdrop ? backdropOpacity >= 90 ? 'bg-background/95' : backdropOpacity >= 70 ? 'bg-background/90' : backdropOpacity >= 50 ? 'bg-background/80' : 'bg-background/60' : 'bg-transparent'; return (
{/* Spinner */}
); } // Inline variant return (
); } /** * PreloaderSkeleton - Loading skeleton variant * Useful for content placeholders */ export interface PreloaderSkeletonProps { /** * Number of skeleton lines * @default 3 */ lines?: number; /** * Show avatar skeleton * @default false */ showAvatar?: boolean; /** * Additional CSS classes */ className?: string; } export function PreloaderSkeleton({ lines = 3, showAvatar = false, className, }: PreloaderSkeletonProps) { return (
{showAvatar && (
)} {Array.from({ length: lines }).map((_, i) => (
))}
); }