Bonus

Skeleton loading state

Pulsing placeholders that swap for content

Live preview
Create a skeleton loading pattern with Tailwind CSS for a list of projects. Build the same card twice inside one bordered panel: a visible skeleton version and a hidden loaded version. The panel header has a title, a muted "Refresh" button, and a small status line. The skeleton holds four rows, each an avatar circle plus two grey bars of differing widths and a short bar on the right, all sharing animate-pulse and rounded-full bars in neutral-200 — vary the widths row to row so it does not read as a table. The loaded version holds the real rows: an initials avatar, a project name with a repository path underneath, a status chip (Passing, Running, Failed) and a relative timestamp. Then add JavaScript that swaps the skeleton for the content after a short delay to mimic a fetch, writes the loaded row count into the status line, and lets the Refresh button put the panel back into its skeleton state and reload so the transition can be seen again.