"use client"; import React from 'react'; import { cn } from "../utils/cn"; import { useDynamicTheming } from '../hooks/use-dynamic-theming'; import { useThemeAware } from '../hooks/use-theme-aware'; interface DynamicSkeletonProps { /** * Type of skeleton animation */ animation?: 'pulse' | 'shimmer' | 'wave' | 'static'; /** * Skeleton variant based on content type */ variant?: 'text' | 'avatar' | 'card' | 'button' | 'image' | 'custom'; /** * Size preset for common elements */ size?: 'sm' | 'md' | 'lg' | 'xl'; /** * Custom dimensions */ width?: string | number; height?: string | number; /** * Number of lines for text skeleton */ lines?: number; /** * Platform-aware styling */ platformAware?: boolean; /** * Accessibility enhancements */ includeAriaLabel?: boolean; /** * Custom CSS classes */ className?: string; /** * Child elements (for container skeletons) */ children?: React.ReactNode; } const sizePresets = { sm: { width: '4rem', height: '1rem' }, md: { width: '8rem', height: '1.5rem' }, lg: { width: '12rem', height: '2rem' }, xl: { width: '16rem', height: '2.5rem' } }; const variantStyles = { text: 'rounded', avatar: 'rounded-full aspect-square', card: 'rounded-lg', button: 'rounded-md', image: 'rounded-lg aspect-video', custom: '' }; export function DynamicSkeleton({ animation = 'shimmer', variant = 'text', size = 'md', width, height, lines = 1, platformAware = true, includeAriaLabel = true, className, children }: DynamicSkeletonProps) { const { platform, isDark, accentColor } = useThemeAware(); // Calculate dimensions const dimensions = React.useMemo(() => { if (width || height) { return { width: typeof width === 'number' ? `${width}px` : width, height: typeof height === 'number' ? `${height}px` : height }; } if (variant === 'avatar') { const avatarSize = sizePresets[size].height; return { width: avatarSize, height: avatarSize }; } return sizePresets[size]; }, [width, height, size, variant]); // Platform-specific skeleton colors const platformStyles = React.useMemo(() => { if (!platformAware) return {}; const baseOpacity = isDark ? 0.1 : 0.15; const accentOpacity = isDark ? 0.05 : 0.08; return { '--skeleton-base': `color-mix(in srgb, var(--color-bg-skeleton) ${baseOpacity * 100}%, transparent)`, '--skeleton-highlight': `color-mix(in srgb, ${accentColor} ${accentOpacity * 100}%, var(--color-bg-skeleton))`, '--skeleton-accent': `color-mix(in srgb, ${accentColor} 10%, transparent)` } as React.CSSProperties; }, [platformAware, isDark, accentColor]); // Animation classes const animationClasses = { pulse: 'animate-pulse', shimmer: 'ods-loading-dynamic', wave: 'skeleton-wave', static: '' }; // Base skeleton classes const baseClasses = cn( 'bg-ods-skeleton', variantStyles[variant], animationClasses[animation], platformAware && `skeleton-platform-${platform}`, className ); // For text skeletons with multiple lines if (variant === 'text' && lines > 1) { return (