Problem: Skeleton.tsx exports several named skeleton components (SummaryCardSkeleton, ListSkeleton, DashboardGridSkeleton, ProjectDetailSkeleton) but the animation is not coordinated — each component declares its own animate-pulse without a shared base class. New skeleton variants are being created ad-hoc (e.g. ProjectsList.tsx constructs its own inline loading state with raw HTML). There is also no generic primitive for use in new components.
Scope: Refactor Skeleton.tsx to export a base primitive and rebuild all named variants on top of it.
Implementation guidance:
Add export function Skeleton({ className }: { className?: string }) as the base — a single div with animate-pulse bg-white/5 rounded-lg and className override support.
Rebuild SummaryCardSkeleton, ListSkeleton, etc. using the base primitive.
Remove any inline skeleton markup from ProjectsList.tsx and other components; import and use the appropriate named skeleton instead.
Acceptance criteria: All skeleton components animate consistently; no inline skeleton markup exists outside Skeleton.tsx; all skeleton exports are still importable under the same names.
Validation: Visual regression screenshot in PR.
Files to modify: frontend/src/components/Skeleton.tsx, frontend/src/components/projects/ProjectsList.tsx
Problem: Skeleton.tsx exports several named skeleton components (SummaryCardSkeleton, ListSkeleton, DashboardGridSkeleton, ProjectDetailSkeleton) but the animation is not coordinated — each component declares its own animate-pulse without a shared base class. New skeleton variants are being created ad-hoc (e.g. ProjectsList.tsx constructs its own inline loading state with raw HTML). There is also no generic primitive for use in new components.
Scope: Refactor Skeleton.tsx to export a base primitive and rebuild all named variants on top of it.
Implementation guidance:
Add export function Skeleton({ className }: { className?: string }) as the base — a single div with animate-pulse bg-white/5 rounded-lg and className override support.
Rebuild SummaryCardSkeleton, ListSkeleton, etc. using the base primitive.
Remove any inline skeleton markup from ProjectsList.tsx and other components; import and use the appropriate named skeleton instead.
Acceptance criteria: All skeleton components animate consistently; no inline skeleton markup exists outside Skeleton.tsx; all skeleton exports are still importable under the same names.
Validation: Visual regression screenshot in PR.
Files to modify: frontend/src/components/Skeleton.tsx, frontend/src/components/projects/ProjectsList.tsx