storybook-stories
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStorybook Stories
Storybook 故事
This skill enforces consistent Storybook story creation patterns across the application. It ensures that all components have proper documentation, interactive examples, and follow the established project structure.
<critical_component_usage>
MANDATORY: Always Use Base UI Components from @agh/ui
CRITICAL REQUIREMENTS:
- ✅ ALWAYS import components from package (
@agh/ui)packages/ui - ✅ ALWAYS use existing base UI components instead of creating new ones from scratch
- ✅ ALWAYS follow design system rules from and
@.cursor/rules/react.mdc@.cursor/rules/shadcn.mdc - ✅ ALWAYS use design tokens (e.g., ,
bg-background,text-foreground) instead of explicit colorsborder-border - ❌ NEVER create components from scratch when a base component exists in
@agh/ui - ❌ NEVER use explicit color values (e.g., ,
bg-white) - always use design tokenstext-black - ❌ NEVER duplicate component logic - compose from base components
- ❌ NEVER set or enable Storybook autodocs on any story meta (
tags: ["autodocs"],packages/ui, orweb/src/components/ui). Useweb/src/systems/**, JSDoc on stories, and the Docs addon manually if needed.parameters.docs.description.component
Available Base Components:
All components from are available via :
packages/ui/src/components@agh/ui- Button, Card, Dialog, Input, Select, Badge, Avatar, Accordion, Alert, etc.
- See for complete list of exports
packages/ui/src/index.ts
Design System Rules:
- Follow React best practices:
@.cursor/rules/react.mdc - Follow Shadcn UI patterns:
@.cursor/rules/shadcn.mdc - Use design tokens for theming: ,
bg-background,text-foreground, etc. </critical_component_usage>border-border
本技能确保应用程序中Storybook故事的创建模式保持一致,保证所有组件具备完善的文档、交互式示例,并遵循既定的项目结构。
<critical_component_usage>
强制要求:始终使用来自@agh/ui的基础UI组件
关键要求:
- ✅ 始终从包(
@agh/ui)导入组件packages/ui - ✅ 始终使用现有基础UI组件,而非从头创建新组件
- ✅ 始终遵循和
@.cursor/rules/react.mdc中的设计系统规则@.cursor/rules/shadcn.mdc - ✅ 始终使用设计令牌(如、
bg-background、text-foreground)而非明确的颜色值border-border - ❌ 禁止在已有基础组件的情况下从头创建新组件
@agh/ui - ❌ 禁止使用明确的颜色值(如、
bg-white)——务必使用设计令牌text-black - ❌ 禁止重复组件逻辑——通过基础组件组合实现
- ❌ 禁止在任何故事元数据(、
packages/ui或web/src/components/ui)中设置web/src/systems/**或启用Storybook自动文档功能。如需使用,可手动使用tags: ["autodocs"]、故事上的JSDoc以及Docs插件。parameters.docs.description.component
可用基础组件:
中的所有组件均可通过访问:
packages/ui/src/components@agh/ui- Button、Card、Dialog、Input、Select、Badge、Avatar、Accordion、Alert等
- 完整导出列表请查看
packages/ui/src/index.ts
设计系统规则:
- 遵循React最佳实践:
@.cursor/rules/react.mdc - 遵循Shadcn UI模式:
@.cursor/rules/shadcn.mdc - 使用设计令牌实现主题化:、
bg-background、text-foreground等 </critical_component_usage>border-border
Instructions
操作说明
-
File Location & Naming
- Place story files in a folder within the same category folder as the component.
stories/ - Example: ->
src/components/base/accordion.tsx.src/components/base/stories/accordion.stories.tsx - Use the Storybook instance that matches the layer:
- for
packages/ui/.storybookpackages/ui/src/components/*.stories.tsx - for
web/.storybookandweb/src/components/ui/**/*.stories.tsxweb/src/systems/**/components/stories/*.stories.tsx
- Place story files in a
-
Component Imports
- MANDATORY: Import base UI components from
@agh/ui - Use:
import { Button, Card, Dialog } from "@agh/ui"; - Only import custom/domain-specific components from local files
- Check to see available components before creating new ones
packages/ui/src/index.ts
- MANDATORY: Import base UI components from
-
Meta Configuration
- Title should follow the directory structure: or
components/custom/ComponentName.components/ui/ComponentName - Include in the meta object.
component - Set to
parameters.layoutby default."centered" - Add to describe the component.
parameters.docs.description.component - Use if the component requires a specific container width or context.
decorators - MANDATORY: Use explicit type annotation:
const meta: Meta<typeof Component> = { ... } - MANDATORY: Do not add to meta (any layer). Autodocs inflates generated docs noise and is forbidden in this repo.
tags: ["autodocs"] - system stories may rely on the shared QueryClient + router + MSW decorators from
web; prefer those global decorators over per-story provider duplication.web/.storybook/preview.ts
- Title should follow the directory structure:
-
Story Definition
- Define a helper type: .
type Story = StoryObj<typeof meta>; - Export stories as named constants (PascalCase).
- Always add JSDoc comments above each story export; these appear in the Storybook UI.
- Use the story as the primary example.
Default - MANDATORY: All stories must include property, even if empty:
argsargs: {} - Keep it concise: Create only essential stories (2-5 max per component). Avoid over-engineering with excessive variations or complex scenarios.
- For system stories, keep titles aligned to the domain surface: .
systems/<name>/<ComponentName>
- Define a helper type:
-
Render vs Args
- Use functions for compound components (like Accordion, Dialog, Select) that require children composition.
render - Use for simple components (like Button, Badge) where props define the variation.
args - MANDATORY: Even when using , include
renderpropertyargs: {}
- Use
-
Design System Compliance
- ALWAYS use design tokens for colors: ,
bg-background,text-foregroundborder-border - NEVER use explicit colors: ,
bg-white,text-blackborder-gray-200 - Follow accessibility guidelines from
@.cursor/rules/shadcn.mdc - Use semantic HTML elements and proper ARIA attributes
- ALWAYS use design tokens for colors:
-
文件位置与命名
- 将故事文件放置在组件所在分类文件夹内的目录中。
stories/ - 示例:->
src/components/base/accordion.tsx。src/components/base/stories/accordion.stories.tsx - 使用与层级匹配的Storybook实例:
- 用于
packages/ui/.storybookpackages/ui/src/components/*.stories.tsx - 用于
web/.storybook和web/src/components/ui/**/*.stories.tsxweb/src/systems/**/components/stories/*.stories.tsx
- 将故事文件放置在组件所在分类文件夹内的
-
组件导入
- 强制要求:从导入基础UI组件
@agh/ui - 正确用法:
import { Button, Card, Dialog } from "@agh/ui"; - 仅从本地文件导入自定义/领域特定组件
- 创建新组件前,请先查看确认可用组件
packages/ui/src/index.ts
- 强制要求:从
-
元数据配置
- 标题应遵循目录结构:或
components/custom/ComponentName。components/ui/ComponentName - 在元对象中包含属性。
component - 默认将设置为
parameters.layout。"centered" - 添加来描述组件。
parameters.docs.description.component - 如果组件需要特定容器宽度或上下文,使用。
decorators - 强制要求:使用显式类型注解:
const meta: Meta<typeof Component> = { ... } - 强制要求:不要在元数据中添加(任何层级)。自动文档会增加生成文档的冗余信息,本仓库禁止使用。
tags: ["autodocs"] - 系统故事可依赖
web中的共享QueryClient + 路由 + MSW装饰器;优先使用这些全局装饰器,而非每个故事重复添加提供者。web/.storybook/preview.ts
- 标题应遵循目录结构:
-
故事定义
- 定义辅助类型:。
type Story = StoryObj<typeof meta>; - 使用大驼峰命名的常量导出故事。
- 每个故事导出上方务必添加JSDoc注释;这些注释会显示在Storybook界面中。
- 使用故事作为主要示例。
Default - 强制要求:所有故事必须包含属性,即使为空:
argsargs: {} - 保持简洁:每个组件仅创建必要的故事(最多2-5个)。避免过度设计,添加过多变体或复杂场景。
- 系统故事的标题需与领域范围对齐:。
systems/<name>/<ComponentName>
- 定义辅助类型:
-
Render与Args的使用
- 对于需要子组件组合的复合组件(如Accordion、Dialog、Select),使用函数。
render - 对于通过props定义变体的简单组件(如Button、Badge),使用。
args - 强制要求:即使使用,也需包含
render属性args: {}
- 对于需要子组件组合的复合组件(如Accordion、Dialog、Select),使用
-
设计系统合规性
- 始终使用设计令牌设置颜色:、
bg-background、text-foregroundborder-border - 禁止使用明确颜色值:、
bg-white、text-blackborder-gray-200 - 遵循中的无障碍指南
@.cursor/rules/shadcn.mdc - 使用语义化HTML元素和正确的ARIA属性
- 始终使用设计令牌设置颜色:
Example Template
示例模板
Using Base UI Components from @agh/ui
使用来自@agh/ui的基础UI组件
tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button, Card, CardHeader, CardTitle, CardContent } from "@agh/ui";
import { MyCustomComponent } from "./my-custom-component";
const meta: Meta<typeof MyCustomComponent> = {
title: "components/custom/MyCustomComponent",
component: MyCustomComponent,
parameters: {
layout: "centered",
docs: {
description: {
component: "A custom component that composes base UI components from @agh/ui.",
},
},
},
// Optional decorator using design tokens
decorators: [
Story => (
<div className="w-[400px] p-4 bg-background border border-border rounded-lg">
<Story />
</div>
),
],
};
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default usage showing the standard behavior
* Uses base Button and Card components from @agh/ui
*/
export const Default: Story = {
args: {},
render: () => (
<Card>
<CardHeader>
<CardTitle>My Custom Component</CardTitle>
</CardHeader>
<CardContent>
<MyCustomComponent>
<Button variant="default">Action</Button>
</MyCustomComponent>
</CardContent>
</Card>
),
};
/**
* Variation with specific props
* All styling uses design tokens (bg-background, text-foreground, etc.)
*/
export const WithVariant: Story = {
args: {},
render: () => (
<div className="bg-card border border-border rounded-lg p-4">
<MyCustomComponent variant="secondary">
<Button variant="outline">Secondary Action</Button>
</MyCustomComponent>
</div>
),
};tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button, Card, CardHeader, CardTitle, CardContent } from "@agh/ui";
import { MyCustomComponent } from "./my-custom-component";
const meta: Meta<typeof MyCustomComponent> = {
title: "components/custom/MyCustomComponent",
component: MyCustomComponent,
parameters: {
layout: "centered",
docs: {
description: {
component: "A custom component that composes base UI components from @agh/ui.",
},
},
},
// Optional decorator using design tokens
decorators: [
Story => (
<div className="w-[400px] p-4 bg-background border border-border rounded-lg">
<Story />
</div>
),
],
};
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default usage showing the standard behavior
* Uses base Button and Card components from @agh/ui
*/
export const Default: Story = {
args: {},
render: () => (
<Card>
<CardHeader>
<CardTitle>My Custom Component</CardTitle>
</CardHeader>
<CardContent>
<MyCustomComponent>
<Button variant="default">Action</Button>
</MyCustomComponent>
</CardContent>
</Card>
),
};
/**
* Variation with specific props
* All styling uses design tokens (bg-background, text-foreground, etc.)
*/
export const WithVariant: Story = {
args: {},
render: () => (
<div className="bg-card border border-border rounded-lg p-4">
<MyCustomComponent variant="secondary">
<Button variant="outline">Secondary Action</Button>
</MyCustomComponent>
</div>
),
};Story for Base UI Component (from @agh/ui)
基础UI组件的故事(来自@agh/ui)
tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@agh/ui";
const meta: Meta<typeof Button> = {
title: "components/ui/Button",
component: Button,
parameters: {
layout: "centered",
docs: {
description: {
component: "A button component with multiple variants and sizes.",
},
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default button with standard styling
*/
export const Default: Story = {
args: {
children: "Button",
variant: "default",
size: "default",
},
};
/**
* All variants using design tokens
*/
export const AllVariants: Story = {
args: {},
render: () => (
<div className="flex flex-wrap gap-4 bg-background p-4 rounded-lg">
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="muted">Muted</Button>
</div>
),
};tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@agh/ui";
const meta: Meta<typeof Button> = {
title: "components/ui/Button",
component: Button,
parameters: {
layout: "centered",
docs: {
description: {
component: "A button component with multiple variants and sizes.",
},
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default button with standard styling
*/
export const Default: Story = {
args: {
children: "Button",
variant: "default",
size: "default",
},
};
/**
* All variants using design tokens
*/
export const AllVariants: Story = {
args: {},
render: () => (
<div className="flex flex-wrap gap-4 bg-background p-4 rounded-lg">
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="muted">Muted</Button>
</div>
),
};Best Practices
最佳实践
Autodocs (forbidden)
自动文档(禁止使用)
Do not use Storybook autodocs. Never set on for , , or stories. Rationale: autodocs-generated pages add noise and duplicate what we already express with concise stories, , and per-story JSDoc. If a component needs richer prose, write it in the description fields and keep the canvas as the source of truth.
tags: ["autodocs"]metapackages/uiweb/src/components/uiweb/src/systems/**parameters.docs.description.component请勿使用Storybook自动文档功能。切勿在、或的故事元数据中设置。原因:自动文档生成的页面会增加冗余信息,与我们通过简洁故事、和每个故事的JSDoc所表达的内容重复。如果组件需要更丰富的描述,可在描述字段中编写,并将画布作为信息来源的基准。
packages/uiweb/src/components/uiweb/src/systems/**tags: ["autodocs"]parameters.docs.description.componentConciseness & Simplicity
简洁性与简易性
<critical>
**MANDATORY: Keep Stories Concise and Focused**
- ✅ DO: Create only essential stories that demonstrate core functionality
- ✅ DO: Use minimal, realistic examples that show the component's purpose
- ✅ DO: Focus on one concept per story
- ❌ DON'T: Create excessive variations that don't add value
- ❌ DON'T: Over-engineer with complex mock data or elaborate scenarios
- ❌ DON'T: Create stories for every possible prop combination
- ❌ DON'T: Add unnecessary decorators or wrappers unless required
Story Count Guidelines:
- Simple components (Button, Badge): 2-3 stories max (Default + 1-2 key variations)
- Medium components (Card, Dialog): 3-4 stories max (Default + key use cases)
- Complex components: 4-5 stories max (Default + essential scenarios)
- Never create more than 5 stories per component unless absolutely necessary </critical>
<critical>
**强制要求:保持故事简洁且聚焦**
- ✅ 务必仅创建展示核心功能的必要故事
- ✅ 务必使用最小化、贴近真实的示例来展示组件用途
- ✅ 务必每个故事聚焦一个概念
- ❌ 禁止创建无价值的过多变体
- ❌ 禁止过度设计,添加复杂的模拟数据或繁琐场景
- ❌ 禁止为每个可能的props组合创建故事
- ❌ 禁止添加不必要的装饰器或包装器,除非必须
故事数量指南:
- 简单组件(Button、Badge):最多2-3个故事(默认示例 + 1-2个关键变体)
- 中等组件(Card、Dialog):最多3-4个故事(默认示例 + 关键用例)
- 复杂组件:最多4-5个故事(默认示例 + 核心场景)
- 除非绝对必要,每个组件的故事数量不得超过5个 </critical>
Component Usage
组件使用
- Base Components First: Always check for existing components before creating new ones
@agh/ui - Composition Over Creation: Compose complex components from base UI components
- Compound Components: Always demonstrate the full structure (Parent + Children) when using compound components from
@agh/ui - Design Tokens: Always use design tokens (,
bg-background, etc.) instead of explicit colorstext-foreground
- 优先使用基础组件:创建新组件前,务必先检查是否已有对应组件
@agh/ui - 组合优先于创建:通过基础UI组件组合实现复杂组件
- 复合组件:使用中的复合组件时,务必展示完整结构(父组件 + 子组件)
@agh/ui - 设计令牌:始终使用设计令牌(、
bg-background等)而非明确颜色值text-foreground
Story Structure
故事结构
- Mock Data: Keep mock data minimal and realistic - only include what's necessary to demonstrate the component
- Interactivity: For components like Accordion or Dialog, ensure the function sets up the component in a way that allows interaction (e.g., not force-controlled unless necessary)
render - Cleanliness: Remove unused imports and generic "template" comments
- Type Safety: Always use explicit type annotation for :
metaconst meta: Meta<typeof Component> - Args Property: Always include in all stories, even when using custom
args: {}functionsrender - One Story Per Concept: Each story should demonstrate one clear use case or variation, not multiple concepts
- 模拟数据:保持模拟数据最小化且贴近真实——仅包含展示组件所需的内容
- 交互性:对于Accordion或Dialog等组件,确保函数设置的组件允许交互(例如,除非必要,不要强制受控)
render - 整洁性:移除未使用的导入和通用的“模板”注释
- 类型安全:始终为使用显式类型注解:
metaconst meta: Meta<typeof Component> - Args属性:所有故事务必包含,即使使用自定义
args: {}函数render - 每个故事一个概念:每个故事应展示一个清晰的用例或变体,而非多个概念
Design System Compliance
设计系统合规性
- Follow React Rules: Adhere to patterns in
@.cursor/rules/react.mdc - Follow Shadcn Rules: Adhere to patterns in
@.cursor/rules/shadcn.mdc - Accessibility: Use semantic HTML and proper ARIA attributes
- Theme Support: All stories should work in both light and dark themes using design tokens
- 遵循React规则:遵守中的模式
@.cursor/rules/react.mdc - 遵循Shadcn规则:遵守中的模式
@.cursor/rules/shadcn.mdc - 无障碍性:使用语义化HTML和正确的ARIA属性
- 主题支持:所有故事应通过设计令牌适配亮色和暗色主题
Common Mistakes to Avoid
需避免的常见错误
❌ Creating components from scratch when base components exist:
tsx
// ❌ BAD: Creating a button from scratch
export const Bad: Story = {
render: () => <button className="bg-blue-500 text-white px-4 py-2 rounded">Click me</button>,
};
// ✅ GOOD: Using base Button from @agh/ui
import { Button } from "@agh/ui";
export const Good: Story = {
args: {},
render: () => <Button variant="default">Click me</Button>,
};❌ Enabling autodocs on meta:
tsx
// ❌ BAD: autodocs tag (forbidden in this repo)
const meta: Meta<typeof Button> = {
title: "ui/Button",
component: Button,
tags: ["autodocs"],
};
// ✅ GOOD: no autodocs tag; describe the component in parameters.docs
const meta: Meta<typeof Button> = {
title: "ui/Button",
component: Button,
parameters: {
layout: "centered",
docs: {
description: {
component: "Primary action button with variants and sizes.",
},
},
},
};❌ Using explicit colors instead of design tokens:
tsx
// ❌ BAD: Using explicit colors
<div className="bg-white text-black border-gray-200">
// ✅ GOOD: Using design tokens
<div className="bg-background text-foreground border-border">❌ Missing args property:
tsx
// ❌ BAD: Missing args property
export const Bad: Story = {
render: () => <Button>Click</Button>,
};
// ✅ GOOD: Including args property
export const Good: Story = {
args: {},
render: () => <Button>Click</Button>,
};❌ Missing explicit type annotation:
tsx
// ❌ BAD: Type inference
const meta = {
title: "Components/Button",
component: Button,
} satisfies Meta<typeof Button>;
// ✅ GOOD: Explicit type annotation
const meta: Meta<typeof Button> = {
title: "Components/Button",
component: Button,
};❌ Over-engineering stories with unnecessary examples:
tsx
// ❌ BAD: Too many stories with similar variations
export const Default: Story = { ... };
export const WithIcon: Story = { ... };
export const WithIconLeft: Story = { ... };
export const WithIconRight: Story = { ... };
export const WithLongText: Story = { ... };
export const WithShortText: Story = { ... };
export const Disabled: Story = { ... };
export const Loading: Story = { ... };
export const WithTooltip: Story = { ... };
export const InCard: Story = { ... };
export const InDialog: Story = { ... };
// ... 10+ stories for a simple button
// ✅ GOOD: Concise, focused stories
export const Default: Story = {
args: {
children: "Button",
variant: "default",
},
};
export const Variants: Story = {
args: {},
render: () => (
<div className="flex gap-2">
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
</div>
),
};
export const Disabled: Story = {
args: {
children: "Disabled",
disabled: true,
},
};
// Only 3 stories covering essential use cases❌ Over-complicated mock data or scenarios:
tsx
// ❌ BAD: Unnecessarily complex mock data
const mockUsers = [
{ id: "1", name: "John Doe", email: "john@example.com", role: "admin", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
{ id: "2", name: "Jane Smith", email: "jane@example.com", role: "user", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
// ... 10 more users with full data
];
// ✅ GOOD: Minimal, realistic data
const mockUsers = [
{ id: "1", name: "John Doe", email: "john@example.com" },
{ id: "2", name: "Jane Smith", email: "jane@example.com" },
];❌ 已有基础组件时仍从头创建组件:
tsx
// ❌ 错误:从头创建按钮
export const Bad: Story = {
render: () => <button className="bg-blue-500 text-white px-4 py-2 rounded">Click me</button>,
};
// ✅ 正确:使用来自@agh/ui的基础Button组件
import { Button } from "@agh/ui";
export const Good: Story = {
args: {},
render: () => <Button variant="default">Click me</Button>,
};❌ 在元数据中启用自动文档:
tsx
// ❌ 错误:使用autodocs标签(本仓库禁止)
const meta: Meta<typeof Button> = {
title: "ui/Button",
component: Button,
tags: ["autodocs"],
};
// ✅ 正确:不使用autodocs标签;在parameters.docs中描述组件
const meta: Meta<typeof Button> = {
title: "ui/Button",
component: Button,
parameters: {
layout: "centered",
docs: {
description: {
component: "Primary action button with variants and sizes.",
},
},
},
};❌ 使用明确颜色值而非设计令牌:
tsx
// ❌ 错误:使用明确颜色值
<div className="bg-white text-black border-gray-200">
// ✅ 正确:使用设计令牌
<div className="bg-background text-foreground border-border">❌ 缺少args属性:
tsx
// ❌ 错误:缺少args属性
export const Bad: Story = {
render: () => <Button>Click</Button>,
};
// ✅ 正确:包含args属性
export const Good: Story = {
args: {},
render: () => <Button>Click</Button>,
};❌ 缺少显式类型注解:
tsx
// ❌ 错误:类型推断
const meta = {
title: "Components/Button",
component: Button,
} satisfies Meta<typeof Button>;
// ✅ 正确:显式类型注解
const meta: Meta<typeof Button> = {
title: "Components/Button",
component: Button,
};❌ 过度设计故事,添加不必要的示例:
tsx
// ❌ 错误:过多相似变体的故事
export const Default: Story = { ... };
export const WithIcon: Story = { ... };
export const WithIconLeft: Story = { ... };
export const WithIconRight: Story = { ... };
export const WithLongText: Story = { ... };
export const WithShortText: Story = { ... };
export const Disabled: Story = { ... };
export const Loading: Story = { ... };
export const WithTooltip: Story = { ... };
export const InCard: Story = { ... };
export const InDialog: Story = { ... };
// ... 一个简单按钮有10多个故事
// ✅ 正确:简洁、聚焦的故事
export const Default: Story = {
args: {
children: "Button",
variant: "default",
},
};
export const Variants: Story = {
args: {},
render: () => (
<div className="flex gap-2">
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
</div>
),
};
export const Disabled: Story = {
args: {
children: "Disabled",
disabled: true,
},
};
// 仅3个故事,覆盖核心用例❌ 过度复杂的模拟数据或场景:
tsx
// ❌ 错误:不必要的复杂模拟数据
const mockUsers = [
{ id: "1", name: "John Doe", email: "john@example.com", role: "admin", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
{ id: "2", name: "Jane Smith", email: "jane@example.com", role: "user", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
// ... 另外10个包含完整数据的用户
];
// ✅ 正确:最小化、贴近真实的数据
const mockUsers = [
{ id: "1", name: "John Doe", email: "john@example.com" },
{ id: "2", name: "Jane Smith", email: "jane@example.com" },
];",