docs(frontend): document skeleton (#10240)

## Changes 🏗️

<img width="800" alt="Screenshot 2025-06-25 at 17 52 38"
src="https://github.com/user-attachments/assets/18f859cf-5008-4915-925c-1912ab9cf176"
/>

- Depends on #10235 so that we can test the new Chromatic workflow with
this
- Documents our Skeleton atom which is directly
[shadcn/skeleton](https://ui.shadcn.com/docs/components/skeleton)

## Checklist 📋

#### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
  - [x] Run storybook locally
  - [x] The Skeleton stories look good
This commit is contained in:
Ubbe
2025-06-25 18:34:40 +04:00
committed by GitHub
parent 1dcf0312f2
commit 3e3db658c6

View File

@@ -0,0 +1,199 @@
import { Skeleton } from "@/components/ui/skeleton";
import type { Meta, StoryObj } from "@storybook/nextjs";
const meta: Meta<typeof Skeleton> = {
title: "Atoms/Skeleton",
tags: ["autodocs"],
component: Skeleton,
parameters: {
layout: "padded",
docs: {
description: {
component:
"Skeleton component for loading states. Use these patterns to show users that content is being loaded, providing a better perceived performance and user experience.",
},
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
// Basic skeleton
export const Default: Story = {
render: () => <Skeleton className="h-4 w-48" />,
};
// Text loading patterns
export const TextLines: Story = {
render: renderTextLines,
};
export const Paragraph: Story = {
render: renderParagraph,
};
// Card loading pattern
export const Card: Story = {
render: renderCard,
};
// Profile/Avatar pattern
export const Profile: Story = {
render: renderProfile,
};
// List items pattern
export const ListItems: Story = {
render: renderListItems,
};
// Table loading pattern
export const Table: Story = {
render: renderTable,
};
// Complete dashboard loading example
export const Dashboard: Story = {
render: renderDashboard,
};
// Render functions as function declarations
function renderTextLines() {
return (
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
</div>
);
}
function renderParagraph() {
return (
<div className="space-y-3">
<Skeleton className="h-6 w-1/3" />
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-2/3" />
</div>
</div>
);
}
function renderCard() {
return (
<div className="w-80 space-y-4 rounded-lg border p-6">
<div className="flex items-center space-x-4">
<Skeleton className="h-12 w-12 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-3 w-24" />
</div>
</div>
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-3/4" />
</div>
<Skeleton className="h-10 w-full rounded-md" />
</div>
);
}
function renderProfile() {
return (
<div className="flex items-center space-x-4">
<Skeleton className="h-16 w-16 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-5 w-48" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-3 w-24" />
</div>
</div>
);
}
function renderListItems() {
return (
<div className="space-y-4">
{Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="flex items-center space-x-3">
<Skeleton className="h-10 w-10 rounded-md" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-1/3" />
<Skeleton className="h-3 w-1/2" />
</div>
<Skeleton className="h-8 w-16 rounded-md" />
</div>
))}
</div>
);
}
function renderTable() {
return (
<div className="w-full space-y-3">
{/* Table header */}
<div className="flex space-x-4">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-5 flex-1" />
))}
</div>
{/* Table rows */}
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="flex space-x-4">
{Array.from({ length: 4 }).map((_, j) => (
<Skeleton key={j} className="h-4 flex-1" />
))}
</div>
))}
</div>
);
}
function renderDashboard() {
return (
<div className="space-y-8 p-6">
{/* Header */}
<div className="flex items-center justify-between">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-10 w-32 rounded-md" />
</div>
{/* Stats cards */}
<div className="grid grid-cols-1 gap-6 md:grid-cols-3">
{Array.from({ length: 3 }).map((_, i) => (
<div key={i} className="space-y-3 rounded-lg border p-6">
<Skeleton className="h-4 w-24" />
<Skeleton className="h-8 w-16" />
<Skeleton className="h-3 w-32" />
</div>
))}
</div>
{/* Chart area */}
<div className="rounded-lg border p-6">
<div className="space-y-4">
<Skeleton className="h-6 w-32" />
<Skeleton className="h-64 w-full rounded-md" />
</div>
</div>
{/* Recent activity */}
<div className="space-y-4">
<Skeleton className="h-6 w-40" />
{Array.from({ length: 4 }).map((_, i) => (
<div key={i} className="flex items-center space-x-4 border-b pb-3">
<Skeleton className="h-8 w-8 rounded-full" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-2/3" />
<Skeleton className="h-3 w-1/3" />
</div>
<Skeleton className="h-3 w-16" />
</div>
))}
</div>
</div>
);
}