- Add Button component with CVA variants (primary, secondary, destructive, ghost, link) - Add Input, Textarea, FormField, and Skeleton UI primitives - Add focus trapping to Modal for WCAG accessibility compliance - Add prefers-reduced-motion media query for motion-sensitive users - Add route-level ErrorBoundary wrapping via page() helper in router - Add route prefetching on sidebar nav hover for instant navigation - Add PageMeta component with OG/Twitter meta tags (react-helmet-async) - Add PageMeta to SharedSessionPage and SurveyPage for social sharing - Replace lodash with custom debounce utility (saves ~71KB bundle) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import { cn } from '@/lib/utils'
|
|
|
|
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
|
|
export function Skeleton({ className, ...props }: SkeletonProps) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'animate-pulse rounded-lg bg-[rgba(255,255,255,0.06)]',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export function CardSkeleton({ className }: { className?: string }) {
|
|
return (
|
|
<div className={cn('glass-card-static p-5 space-y-3', className)}>
|
|
<Skeleton className="h-5 w-3/4" />
|
|
<Skeleton className="h-4 w-1/2" />
|
|
<div className="flex gap-2 mt-4">
|
|
<Skeleton className="h-6 w-16 rounded-full" />
|
|
<Skeleton className="h-6 w-20 rounded-full" />
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function TableRowSkeleton({ cols = 4 }: { cols?: number }) {
|
|
return (
|
|
<div className="flex items-center gap-4 px-4 py-3">
|
|
{Array.from({ length: cols }).map((_, i) => (
|
|
<Skeleton
|
|
key={i}
|
|
className="h-4"
|
|
style={{ width: `${20 + Math.random() * 30}%` }}
|
|
/>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function ListSkeleton({ count = 5, className }: { count?: number; className?: string }) {
|
|
return (
|
|
<div className={cn('space-y-3', className)}>
|
|
{Array.from({ length: count }).map((_, i) => (
|
|
<div key={i} className="flex items-center gap-3 px-4 py-3 rounded-lg bg-[rgba(255,255,255,0.02)]">
|
|
<Skeleton className="size-8 rounded-full shrink-0" />
|
|
<div className="flex-1 space-y-2">
|
|
<Skeleton className="h-4 w-2/3" />
|
|
<Skeleton className="h-3 w-1/3" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|