/ stories / Skeleton.stories.tsx
Skeleton.stories.tsx
  1  import type { Meta, StoryObj } from '@storybook/react';
  2  import { Skeleton, SkeletonText, StatSkeleton } from '../src/components/Skeleton';
  3  import { Card, CardHeader, CardContent } from '../src/components/Card/Card';
  4  
  5  const meta: Meta<typeof Skeleton> = {
  6    title: 'Components/Skeleton',
  7    component: Skeleton,
  8    parameters: {
  9      layout: 'centered',
 10    },
 11    tags: ['autodocs'],
 12    argTypes: {
 13      variant: {
 14        control: 'select',
 15        options: ['text', 'circular', 'rectangular', 'rounded'],
 16      },
 17      animation: {
 18        control: 'select',
 19        options: ['pulse', 'wave', 'none'],
 20      },
 21      width: {
 22        control: 'text',
 23      },
 24      height: {
 25        control: 'text',
 26      },
 27    },
 28  };
 29  
 30  export default meta;
 31  type Story = StoryObj<typeof Skeleton>;
 32  
 33  // Variants
 34  export const Text: Story = {
 35    args: {
 36      variant: 'text',
 37      width: 200,
 38    },
 39  };
 40  
 41  export const Circular: Story = {
 42    args: {
 43      variant: 'circular',
 44      width: 48,
 45      height: 48,
 46    },
 47  };
 48  
 49  export const Rectangular: Story = {
 50    args: {
 51      variant: 'rectangular',
 52      width: 200,
 53      height: 100,
 54    },
 55  };
 56  
 57  export const Rounded: Story = {
 58    args: {
 59      variant: 'rounded',
 60      width: 200,
 61      height: 100,
 62    },
 63  };
 64  
 65  // Animations
 66  export const Pulse: Story = {
 67    args: {
 68      variant: 'rectangular',
 69      width: 200,
 70      height: 60,
 71      animation: 'pulse',
 72    },
 73  };
 74  
 75  export const Wave: Story = {
 76    args: {
 77      variant: 'rectangular',
 78      width: 200,
 79      height: 60,
 80      animation: 'wave',
 81    },
 82  };
 83  
 84  export const NoAnimation: Story = {
 85    args: {
 86      variant: 'rectangular',
 87      width: 200,
 88      height: 60,
 89      animation: 'none',
 90    },
 91  };
 92  
 93  // Composite skeletons
 94  export const TextBlock: Story = {
 95    render: () => <SkeletonText lines={3} />,
 96  };
 97  
 98  export const TextBlockSmallGap: Story = {
 99    render: () => <SkeletonText lines={4} gap="sm" />,
100  };
101  
102  export const TextBlockLargeGap: Story = {
103    render: () => <SkeletonText lines={3} gap="lg" />,
104  };
105  
106  export const StatSkeletonDefault: Story = {
107    render: () => <StatSkeleton />,
108  };
109  
110  export const StatSkeletonNoLabel: Story = {
111    render: () => <StatSkeleton showLabel={false} />,
112  };
113  
114  // Gallery views
115  export const AllVariants: Story = {
116    render: () => (
117      <div className="flex flex-wrap gap-6 items-center">
118        <div className="text-center">
119          <Skeleton variant="text" width={120} />
120          <p className="text-xs text-gray-500 mt-2">Text</p>
121        </div>
122        <div className="text-center">
123          <Skeleton variant="circular" width={48} height={48} />
124          <p className="text-xs text-gray-500 mt-2">Circular</p>
125        </div>
126        <div className="text-center">
127          <Skeleton variant="rectangular" width={80} height={60} />
128          <p className="text-xs text-gray-500 mt-2">Rectangular</p>
129        </div>
130        <div className="text-center">
131          <Skeleton variant="rounded" width={80} height={60} />
132          <p className="text-xs text-gray-500 mt-2">Rounded</p>
133        </div>
134      </div>
135    ),
136  };
137  
138  export const AllAnimations: Story = {
139    render: () => (
140      <div className="flex flex-col gap-4">
141        <div className="flex items-center gap-4">
142          <span className="w-16 text-sm text-gray-500">Pulse</span>
143          <Skeleton variant="rounded" width={200} height={40} animation="pulse" />
144        </div>
145        <div className="flex items-center gap-4">
146          <span className="w-16 text-sm text-gray-500">Wave</span>
147          <Skeleton variant="rounded" width={200} height={40} animation="wave" />
148        </div>
149        <div className="flex items-center gap-4">
150          <span className="w-16 text-sm text-gray-500">None</span>
151          <Skeleton variant="rounded" width={200} height={40} animation="none" />
152        </div>
153      </div>
154    ),
155  };
156  
157  // Use cases
158  export const ProfileCard: Story = {
159    name: 'Use Case: Profile Card Loading',
160    render: () => (
161      <div className="flex items-center gap-4 p-4 border rounded-lg w-80">
162        <Skeleton variant="circular" width={56} height={56} />
163        <div className="flex-1">
164          <Skeleton variant="text" width="60%" className="mb-2" />
165          <Skeleton variant="text" width="40%" />
166        </div>
167      </div>
168    ),
169  };
170  
171  export const ArticleCard: Story = {
172    name: 'Use Case: Article Card Loading',
173    render: () => (
174      <div className="w-80 border rounded-lg overflow-hidden">
175        <Skeleton variant="rectangular" width="100%" height={160} />
176        <div className="p-4">
177          <Skeleton variant="text" width="80%" className="mb-3" height={20} />
178          <SkeletonText lines={2} gap="sm" />
179          <div className="flex items-center gap-2 mt-4">
180            <Skeleton variant="circular" width={24} height={24} />
181            <Skeleton variant="text" width={100} />
182          </div>
183        </div>
184      </div>
185    ),
186  };
187  
188  export const DashboardStats: Story = {
189    name: 'Use Case: Dashboard Stats Loading',
190    render: () => (
191      <div className="grid grid-cols-4 gap-4">
192        {[1, 2, 3, 4].map((i) => (
193          <Card key={i} size="sm">
194            <CardContent className="pt-4">
195              <StatSkeleton />
196            </CardContent>
197          </Card>
198        ))}
199      </div>
200    ),
201  };
202  
203  export const TableRow: Story = {
204    name: 'Use Case: Table Row Loading',
205    render: () => (
206      <div className="w-full max-w-2xl">
207        {[1, 2, 3].map((i) => (
208          <div key={i} className="flex items-center gap-4 p-4 border-b">
209            <Skeleton variant="text" width={80} />
210            <Skeleton variant="text" width={120} className="flex-1" />
211            <Skeleton variant="text" width={60} />
212            <Skeleton variant="rounded" width={80} height={28} />
213          </div>
214        ))}
215      </div>
216    ),
217  };
218  
219  export const TransactionList: Story = {
220    name: 'Use Case: Transaction List Loading',
221    render: () => (
222      <div className="w-80 space-y-3">
223        {[1, 2, 3].map((i) => (
224          <div key={i} className="flex items-center gap-3 p-3 bg-gray-50 rounded-lg">
225            <Skeleton variant="circular" width={40} height={40} />
226            <div className="flex-1">
227              <Skeleton variant="text" width="70%" className="mb-1" />
228              <Skeleton variant="text" width="50%" height={12} />
229            </div>
230            <div className="text-right">
231              <Skeleton variant="text" width={60} className="mb-1" />
232              <Skeleton variant="text" width={40} height={12} />
233            </div>
234          </div>
235        ))}
236      </div>
237    ),
238  };