ogt-docs-rules-code-front

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OGT Docs - Rules Code Front

OGT 文档 - 前端代码规则

Frontend-specific coding standards for React/TypeScript applications.
适用于React/TypeScript应用的前端专属编码规范。

Overview

概述

Frontend rules establish consistent patterns for React components, state management, styling, and client-side architecture.
mermaid
flowchart TB
    subgraph front ["docs/rules/code/front/"]
        COMP["components/"]
        STATE["state/"]
        HOOKS["hooks/"]
        STYLE["styling/"]
        ROUTE["routing/"]
        FETCH["data_fetching/"]
    end

    COMP --> |patterns| C1["composition"]
    COMP --> |patterns| C2["props"]
    STATE --> |patterns| S1["context"]
    STATE --> |patterns| S2["local"]
    HOOKS --> |patterns| H1["custom"]
    STYLE --> |patterns| ST1["css-in-js"]
前端规则为React组件、状态管理、样式及客户端架构建立统一模式。
mermaid
flowchart TB
    subgraph front ["docs/rules/code/front/"]
        COMP["components/"]
        STATE["state/"]
        HOOKS["hooks/"]
        STYLE["styling/"]
        ROUTE["routing/"]
        FETCH["data_fetching/"]
    end

    COMP --> |patterns| C1["composition"]
    COMP --> |patterns| C2["props"]
    STATE --> |patterns| S1["context"]
    STATE --> |patterns| S2["local"]
    HOOKS --> |patterns| H1["custom"]
    STYLE --> |patterns| ST1["css-in-js"]

When to Use

适用场景

  • Creating React component standards
  • Defining state management patterns
  • Establishing styling conventions
  • Writing custom hook guidelines
  • Setting data fetching patterns
  • Defining routing conventions
  • 创建React组件规范
  • 定义状态管理模式
  • 建立样式约定
  • 编写自定义Hook指南
  • 设置数据获取模式
  • 定义路由约定

Folder Structure

目录结构

docs/rules/code/front/
├── components/                     # Component patterns
│   ├── composition/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── props/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   └── file_structure/
│       ├── rule.md
│       └── examples.md
├── state/                          # State management
│   ├── local_state/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── context/
│   │   ├── rule.md
│   │   └── examples.md
│   └── derived_state/
│       ├── rule.md
│       └── examples.md
├── hooks/                          # Custom hooks
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── dependencies/
│   │   ├── rule.md
│   │   └── examples.md
│   └── patterns/
│       ├── rule.md
│       └── examples.md
├── styling/                        # CSS/Styling
│   ├── approach/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   └── responsive/
│       ├── rule.md
│       └── examples.md
├── data_fetching/                  # Data fetching
│   ├── patterns/
│   │   ├── rule.md
│   │   └── examples.md
│   └── error_handling/
│       ├── rule.md
│       └── examples.md
└── routing/                        # Routing
    ├── structure/
    │   ├── rule.md
    │   └── examples.md
    └── navigation/
        ├── rule.md
        └── examples.md

docs/rules/code/front/
├── components/                     # 组件模式
│   ├── composition/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── props/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   └── file_structure/
│       ├── rule.md
│       └── examples.md
├── state/                          # 状态管理
│   ├── local_state/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── context/
│   │   ├── rule.md
│   │   └── examples.md
│   └── derived_state/
│       ├── rule.md
│       └── examples.md
├── hooks/                          # 自定义Hook
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── dependencies/
│   │   ├── rule.md
│   │   └── examples.md
│   └── patterns/
│       ├── rule.md
│       └── examples.md
├── styling/                        # CSS/样式
│   ├── approach/
│   │   ├── rule.md
│   │   └── examples.md
│   ├── naming/
│   │   ├── rule.md
│   │   └── examples.md
│   └── responsive/
│       ├── rule.md
│       └── examples.md
├── data_fetching/                  # 数据获取
│   ├── patterns/
│   │   ├── rule.md
│   │   └── examples.md
│   └── error_handling/
│       ├── rule.md
│       └── examples.md
└── routing/                        # 路由
    ├── structure/
    │   ├── rule.md
    │   └── examples.md
    └── navigation/
        ├── rule.md
        └── examples.md

Example: docs/rules/code/front/components/composition/

示例:docs/rules/code/front/components/composition/

Component composition patterns.
组件组合模式。

rule.md

rule.md

markdown
undefined
markdown
undefined

Rule: Component Composition

规则:组件组合

Summary

概述

Components MUST use composition over prop drilling for flexible, reusable designs.
为实现灵活、可复用的设计,组件必须优先使用组合而非属性透传。

Rationale

设计理由

Composition patterns:
  • Reduce prop drilling
  • Increase reusability
  • Improve testability
  • Enable flexible layouts
组合模式:
  • 减少属性透传
  • 提升复用性
  • 增强可测试性
  • 支持灵活布局

The Rules

具体规则

1. Prefer Children Over Props

1. 优先使用Children而非Props

SHOULD pass content via children rather than render props.
tsx
// PREFERRED
<Card>
  <CardHeader>Title</CardHeader>
  <CardBody>Content</CardBody>
</Card>

// AVOID
<Card
  header={<span>Title</span>}
  body={<span>Content</span>}
/>
undefined
通过children传递内容,而非渲染属性。
tsx
// 推荐写法
<Card>
  <CardHeader>Title</CardHeader>
  <CardBody>Content</CardBody>
</Card>

// 避免写法
<Card
  header={<span>Title</span>}
  body={<span>Content</span>}
/>
undefined

2. Use Compound Components

2. 使用复合组件

SHOULD use compound component pattern for related components.
tsx
// CORRECT - compound components
<Select>
  <Select.Option value="a">Option A</Select.Option>
  <Select.Option value="b">Option B</Select.Option>
</Select>

// AVOID - array of objects
<Select options={[
  { value: 'a', label: 'Option A' },
  { value: 'b', label: 'Option B' },
]} />
为关联组件使用复合组件模式。
tsx
// 正确写法 - 复合组件
<Select>
  <Select.Option value="a">Option A</Select.Option>
  <Select.Option value="b">Option B</Select.Option>
</Select>

// 避免写法 - 对象数组形式
<Select options={[
  { value: 'a', label: 'Option A' },
  { value: 'b', label: 'Option B' },
]} />

3. Avoid Prop Drilling

3. 避免属性透传

MUST NOT pass props more than 2 levels deep. Use context or composition.
tsx
// BAD - prop drilling
<App user={user}>
  <Layout user={user}>
    <Header user={user}>
      <UserMenu user={user} />  // 4 levels!
    </Header>
  </Layout>
</App>

// GOOD - context
<UserProvider user={user}>
  <App>
    <Layout>
      <Header>
        <UserMenu />  // Uses useUser()
      </Header>
    </Layout>
  </App>
</UserProvider>
严禁将属性透传超过2层。应使用Context或组合模式替代。
tsx
// 错误写法 - 属性透传
<App user={user}>
  <Layout user={user}>
    <Header user={user}>
      <UserMenu user={user} />  // 透传了4层!
    </Header>
  </Layout>
</App>

// 推荐写法 - Context
<UserProvider user={user}>
  <App>
    <Layout>
      <Header>
        <UserMenu />  // 使用useUser()获取
      </Header>
    </Layout>
  </App>
</UserProvider>

4. Single Responsibility

4. 单一职责

Each component MUST have one clear purpose.
  • Display components: render UI
  • Container components: manage state/data
  • Layout components: arrange children
每个组件必须只有一个明确的职责。
  • 展示组件:负责渲染UI
  • 容器组件:负责管理状态/数据
  • 布局组件:负责排列子组件

Examples

示例

Correct: Flexible Card Component

正确示例:灵活的Card组件

tsx
// Compound component pattern
const Card = ({ children, className }: CardProps) => (
  <div className={cn("card", className)}>{children}</div>
);

Card.Header = ({ children }: { children: ReactNode }) => (
  <div className="card-header">{children}</div>
);

Card.Body = ({ children }: { children: ReactNode }) => (
  <div className="card-body">{children}</div>
);

Card.Footer = ({ children }: { children: ReactNode }) => (
  <div className="card-footer">{children}</div>
);

// Usage - flexible composition
<Card>
  <Card.Header>
    <h2>Title</h2>
    <IconButton icon="close" />
  </Card.Header>
  <Card.Body>
    <p>Any content here</p>
  </Card.Body>
</Card>;
tsx
// 复合组件模式
const Card = ({ children, className }: CardProps) => (
  <div className={cn("card", className)}>{children}</div>
);

Card.Header = ({ children }: { children: ReactNode }) => (
  <div className="card-header">{children}</div>
);

Card.Body = ({ children }: { children: ReactNode }) => (
  <div className="card-body">{children}</div>
);

Card.Footer = ({ children }: { children: ReactNode }) => (
  <div className="card-footer">{children}</div>
);

// 使用方式 - 灵活组合
<Card>
  <Card.Header>
    <h2>Title</h2>
    <IconButton icon="close" />
  </Card.Header>
  <Card.Body>
    <p>可放置任意内容</p>
  </Card.Body>
</Card>;

Incorrect: Inflexible Props-Based

错误示例:灵活性不足的Props写法

tsx
// BAD - limited flexibility
interface CardProps {
  title: string;
  subtitle?: string;
  body: string;
  footer?: string;
  showCloseButton?: boolean;
  onClose?: () => void;
  headerIcon?: ReactNode;
  // Props multiply as requirements grow...
}

const Card = ({ title, subtitle, body, ... }: CardProps) => (
  // Complex conditional rendering
);
tsx
// 错误写法 - 灵活性受限
interface CardProps {
  title: string;
  subtitle?: string;
  body: string;
  footer?: string;
  showCloseButton?: boolean;
  onClose?: () => void;
  headerIcon?: ReactNode;
  // 需求增长时,Props会不断增加...
}

const Card = ({ title, subtitle, body, ... }: CardProps) => (
  // 复杂的条件渲染
);

Enforcement

落地执行

  • Code review checklist
  • ESLint custom rules for prop drilling detection

---
  • 代码审查检查清单
  • 自定义ESLint规则检测属性透传

---

Example: docs/rules/code/front/state/local_state/

示例:docs/rules/code/front/state/local_state/

Local state management rules.
本地状态管理规则。

rule.md

rule.md

markdown
undefined
markdown
undefined

Rule: Local State Management

规则:本地状态管理

Summary

概述

Component state MUST be kept as local as possible and lifted only when necessary.
组件状态必须尽可能保持本地化,仅在必要时才向上提升。

Rationale

设计理由

Local state:
  • Improves performance (fewer re-renders)
  • Reduces complexity
  • Makes components self-contained
  • Easier to test
本地状态:
  • 提升性能(减少重渲染次数)
  • 降低复杂度
  • 使组件具备独立性
  • 更易于测试

The Rules

具体规则

1. Start Local

1. 从本地状态开始

MUST start with local state and lift only when needed.
tsx
// START HERE - local state
const [count, setCount] = useState(0);

// LIFT when siblings need it
// LIFT when parent needs it
// LIFT when distant components need it
必须先使用本地状态,仅在需要时再向上提升。
tsx
// 初始写法 - 本地状态
const [count, setCount] = useState(0);

// 当兄弟组件需要时再提升
// 当父组件需要时再提升
// 当跨层级组件需要时再提升

2. Colocation

2. 就近原则

MUST keep state close to where it's used.
tsx
// CORRECT - state in component that uses it
function SearchInput() {
  const [query, setQuery] = useState("");
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}

// INCORRECT - state lifted unnecessarily
function App() {
  const [searchQuery, setSearchQuery] = useState("");
  return <SearchInput query={searchQuery} setQuery={setSearchQuery} />;
}
必须将状态放在其使用位置附近。
tsx
// 正确写法 - 状态在使用它的组件中
function SearchInput() {
  const [query, setQuery] = useState("");
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}

// 错误写法 - 不必要的状态提升
function App() {
  const [searchQuery, setSearchQuery] = useState("");
  return <SearchInput query={searchQuery} setQuery={setSearchQuery} />;
}

3. Derive Don't Duplicate

3. 推导而非复制

MUST derive state from existing state rather than duplicating.
tsx
// CORRECT - derived
const [items, setItems] = useState<Item[]>([]);
const completedCount = items.filter((i) => i.completed).length;

// INCORRECT - duplicated state
const [items, setItems] = useState<Item[]>([]);
const [completedCount, setCompletedCount] = useState(0);
// Now you have to keep them in sync!
必须从现有状态推导新状态,而非复制状态。
tsx
// 正确写法 - 推导状态
const [items, setItems] = useState<Item[]>([]);
const completedCount = items.filter((i) => i.completed).length;

// 错误写法 - 重复状态
const [items, setItems] = useState<Item[]>([]);
const [completedCount, setCompletedCount] = useState(0);
// 现在你需要手动保持两者同步!

4. Use Appropriate Hook

4. 使用合适的Hook

ScenarioHook
Simple value
useState
Complex object with many updates
useReducer
Previous value needed
useRef
+
useState
Derived async data
useMemo
or data fetching library
场景Hook
简单值
useState
包含多个更新操作的复杂对象
useReducer
需要获取之前的值
useRef
+
useState
异步推导数据
useMemo
或数据获取库

Examples

示例

Correct: Appropriate State Location

正确示例:状态位置合理

tsx
// Form with local state
function ContactForm() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [message, setMessage] = useState("");

  // Derived state
  const isValid = name.length > 0 && email.includes("@");

  return (
    <form>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <textarea value={message} onChange={(e) => setMessage(e.target.value)} />
      <button disabled={!isValid}>Submit</button>
    </form>
  );
}
tsx
// 带本地状态的表单
function ContactForm() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [message, setMessage] = useState("");

  // 推导状态
  const isValid = name.length > 0 && email.includes("@");

  return (
    <form>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <textarea value={message} onChange={(e) => setMessage(e.target.value)} />
      <button disabled={!isValid}>提交</button>
    </form>
  );
}

Correct: useReducer for Complex State

正确示例:使用useReducer处理复杂状态

tsx
type State = {
  items: Item[];
  filter: "all" | "active" | "completed";
  editingId: string | null;
};

type Action =
  | { type: "ADD_ITEM"; payload: Item }
  | { type: "TOGGLE_ITEM"; payload: string }
  | { type: "SET_FILTER"; payload: State["filter"] }
  | { type: "START_EDITING"; payload: string };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "ADD_ITEM":
      return { ...state, items: [...state.items, action.payload] };
    // ... other cases
  }
}

function TodoList() {
  const [state, dispatch] = useReducer(reducer, initialState);
  // ...
}
tsx
type State = {
  items: Item[];
  filter: "all" | "active" | "completed";
  editingId: string | null;
};

type Action =
  | { type: "ADD_ITEM"; payload: Item }
  | { type: "TOGGLE_ITEM"; payload: string }
  | { type: "SET_FILTER"; payload: State["filter"] }
  | { type: "START_EDITING"; payload: string };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "ADD_ITEM":
      return { ...state, items: [...state.items, action.payload] };
    // ... 其他case
  }
}

function TodoList() {
  const [state, dispatch] = useReducer(reducer, initialState);
  // ...
}

Enforcement

落地执行

  • Code review
  • ESLint react-hooks/exhaustive-deps

---
  • 代码审查
  • ESLint规则react-hooks/exhaustive-deps

---

Example: docs/rules/code/front/hooks/naming/

示例:docs/rules/code/front/hooks/naming/

Custom hook naming rules.
自定义Hook命名规则。

rule.md

rule.md

markdown
undefined
markdown
undefined

Rule: Custom Hook Naming

规则:自定义Hook命名

Summary

概述

Custom hooks MUST be named with
use
prefix and describe their purpose.
自定义Hook必须以
use
为前缀,并清晰描述其用途。

Rationale

设计理由

Consistent naming:
  • Enables React's hooks linting
  • Communicates purpose clearly
  • Follows React conventions
  • Makes hooks discoverable
统一命名:
  • 支持React的Hook语法检查
  • 清晰传达Hook用途
  • 遵循React约定
  • 便于Hook的发现和使用

The Rules

具体规则

1. Use Prefix Required

1. 必须使用use前缀

MUST start with
use
followed by PascalCase description.
typescript
// CORRECT
useUserData
useLocalStorage
useDebounce
useCreatureList

// INCORRECT
getUserData      // Not a hook name
UseUserData      // Wrong case
use_user_data    // Wrong format
必须
use
开头,后跟大驼峰式描述。
typescript
// 正确写法
useUserData
useLocalStorage
useDebounce
useCreatureList

// 错误写法
getUserData      // 不是Hook命名方式
UseUserData      // 大小写错误
use_user_data    // 格式错误

2. Describe the Data or Action

2. 描述数据或操作

SHOULD name after what it returns or does.
Hook ReturnsName Pattern
User data
useUser
,
useCurrentUser
List of items
useItems
,
useCreatures
Boolean state
useIsOpen
,
useIsLoading
Toggle function
useToggle
,
useDisclosure
Async operation
useFetch
,
useQuery
根据Hook返回的内容或执行的操作命名。
Hook返回内容命名模式
用户数据
useUser
,
useCurrentUser
项目列表
useItems
,
useCreatures
布尔状态
useIsOpen
,
useIsLoading
切换函数
useToggle
,
useDisclosure
异步操作
useFetch
,
useQuery

3. File Naming

3. 文件命名

MUST match file name to hook name in kebab-case.
hooks/
  use-user-data.ts      -> export function useUserData()
  use-local-storage.ts  -> export function useLocalStorage()
  use-debounce.ts       -> export function useDebounce()
必须使文件名与Hook名称匹配,采用短横线分隔式(kebab-case)。
hooks/
  use-user-data.ts      -> export function useUserData()
  use-local-storage.ts  -> export function useLocalStorage()
  use-debounce.ts       -> export function useDebounce()

Examples

示例

Correct

正确示例

typescript
// use-creature-data.ts
export function useCreatureData(slug: string) {
  const [creature, setCreature] = useState<Creature | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetchCreature(slug)
      .then(setCreature)
      .finally(() => setIsLoading(false));
  }, [slug]);

  return { creature, isLoading };
}

// use-toggle.ts
export function useToggle(initial = false) {
  const [value, setValue] = useState(initial);
  const toggle = useCallback(() => setValue((v) => !v), []);
  const setTrue = useCallback(() => setValue(true), []);
  const setFalse = useCallback(() => setValue(false), []);

  return { value, toggle, setTrue, setFalse };
}
typescript
// use-creature-data.ts
export function useCreatureData(slug: string) {
  const [creature, setCreature] = useState<Creature | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetchCreature(slug)
      .then(setCreature)
      .finally(() => setIsLoading(false));
  }, [slug]);

  return { creature, isLoading };
}

// use-toggle.ts
export function useToggle(initial = false) {
  const [value, setValue] = useState(initial);
  const toggle = useCallback(() => setValue((v) => !v), []);
  const setTrue = useCallback(() => setValue(true), []);
  const setFalse = useCallback(() => setValue(false), []);

  return { value, toggle, setTrue, setFalse };
}

Incorrect

错误示例

typescript
// BAD - not descriptive
export function useData() { ... }

// BAD - wrong prefix
export function fetchUserData() { ... }  // Looks like regular function

// BAD - file mismatch
// File: userData.ts
export function useUserData() { ... }  // Should be use-user-data.ts
typescript
// 错误写法 - 描述不清晰
export function useData() { ... }

// 错误写法 - 前缀错误
export function fetchUserData() { ... }  // 看起来像普通函数

// 错误写法 - 文件与Hook名称不匹配
// 文件: userData.ts
export function useUserData() { ... }  // 应为use-user-data.ts

Enforcement

落地执行

  • ESLint react-hooks/rules-of-hooks
  • File naming linter

---
  • ESLint规则react-hooks/rules-of-hooks
  • 文件命名检查工具

---

Example: docs/rules/code/front/styling/approach/

示例:docs/rules/code/front/styling/approach/

Styling approach rules.
样式方案规则。

rule.md

rule.md

markdown
undefined
markdown
undefined

Rule: Styling Approach

规则:样式方案

Summary

概述

Projects MUST use a consistent styling approach and SHOULD prefer CSS-in-JS or utility classes.
项目必须使用统一的样式方案,且应优先选择CSS-in-JS或工具类方案。

Rationale

设计理由

Consistent styling:
  • Reduces context switching
  • Enables type-safe styles
  • Improves maintainability
  • Colocates styles with components
统一的样式方案:
  • 减少上下文切换
  • 支持类型安全的样式
  • 提升可维护性
  • 样式与组件就近存放

The Rules

具体规则

1. Choose One Approach

1. 选择一种方案

MUST use one primary styling approach per project:
ApproachWhen to Use
Tailwind CSSUtility-first, rapid development
CSS ModulesScoped CSS, traditional CSS knowledge
styled-componentsComponent-based, dynamic styles
Vanilla ExtractType-safe, zero runtime
必须为每个项目选择一种主要的样式方案:
方案适用场景
Tailwind CSS工具类优先,快速开发
CSS Modules作用域CSS,适合熟悉传统CSS的团队
styled-components组件级样式,支持动态样式
Vanilla Extract类型安全,零运行时

2. Consistent Application

2. 统一应用

MUST apply chosen approach consistently across all components.
必须在所有组件中一致地应用所选方案。

3. Component-Scoped Styles

3. 组件作用域样式

MUST NOT use global styles except for:
  • CSS reset/normalize
  • CSS variables (design tokens)
  • Base typography
严禁使用全局样式,以下场景除外:
  • CSS重置/标准化样式
  • CSS变量(设计令牌)
  • 基础排版

4. Design Tokens

4. 设计令牌

SHOULD use design tokens for colors, spacing, typography.
tsx
// CORRECT - using tokens
<div className="p-4 bg-primary text-white" />
<div style={{ padding: tokens.spacing.md }} />

// INCORRECT - magic values
<div style={{ padding: '16px', backgroundColor: '#3b82f6' }} />
使用设计令牌定义颜色、间距、排版等样式属性。
tsx
// 正确写法 - 使用令牌
<div className="p-4 bg-primary text-white" />
<div style={{ padding: tokens.spacing.md }} />

// 错误写法 - 魔法值
<div style={{ padding: '16px', backgroundColor: '#3b82f6' }} />

Examples

示例

Tailwind CSS Approach

Tailwind CSS方案

tsx
// Component with Tailwind
function Card({ title, children }: CardProps) {
  return (
    <div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
      <h2 className="mb-2 text-lg font-semibold text-gray-900">{title}</h2>
      <div className="text-gray-600">{children}</div>
    </div>
  );
}

// With cn() for conditional classes
function Button({ variant, children }: ButtonProps) {
  return (
    <button
      className={cn(
        "rounded px-4 py-2 font-medium transition-colors",
        variant === "primary" && "bg-blue-500 text-white hover:bg-blue-600",
        variant === "secondary" &&
          "bg-gray-200 text-gray-900 hover:bg-gray-300",
      )}
    >
      {children}
    </button>
  );
}
tsx
// 使用Tailwind的组件
function Card({ title, children }: CardProps) {
  return (
    <div className="rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
      <h2 className="mb-2 text-lg font-semibold text-gray-900">{title}</h2>
      <div className="text-gray-600">{children}</div>
    </div>
  );
}

// 使用cn()处理条件类名
function Button({ variant, children }: ButtonProps) {
  return (
    <button
      className={cn(
        "rounded px-4 py-2 font-medium transition-colors",
        variant === "primary" && "bg-blue-500 text-white hover:bg-blue-600",
        variant === "secondary" &&
          "bg-gray-200 text-gray-900 hover:bg-gray-300",
      )}
    >
      {children}
    </button>
  );
}

CSS Modules Approach

CSS Modules方案

tsx
// Card.module.css
.card {
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  padding: var(--spacing-md);
}

.title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
}

// Card.tsx
import styles from './Card.module.css';

function Card({ title, children }: CardProps) {
  return (
    <div className={styles.card}>
      <h2 className={styles.title}>{title}</h2>
      {children}
    </div>
  );
}
tsx
// Card.module.css
.card {
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  padding: var(--spacing-md);
}

.title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
}

// Card.tsx
import styles from './Card.module.css';

function Card({ title, children }: CardProps) {
  return (
    <div className={styles.card}>
      <h2 className={styles.title}>{title}</h2>
      {children}
    </div>
  );
}

Enforcement

落地执行

  • ESLint Tailwind plugin (if using Tailwind)
  • Code review

---
  • ESLint Tailwind插件(若使用Tailwind)
  • 代码审查

---

Creating Frontend Rules

创建前端规则

mermaid
flowchart TD
    A[Identify Pattern] --> B{Category}

    B -->|Components| C[components/]
    B -->|State| D[state/]
    B -->|Hooks| E[hooks/]
    B -->|Styling| F[styling/]
    B -->|Data| G[data_fetching/]
    B -->|Routes| H[routing/]

    C --> I[Create Rule Folder]
    D --> I
    E --> I
    F --> I
    G --> I
    H --> I

    I --> J[Write rule.md]
    J --> K[Add examples.md]
    K --> L[Configure ESLint if applicable]
    L --> M[Add to review checklist]

mermaid
flowchart TD
    A[识别模式] --> B{分类}

    B -->|组件| C[components/]
    B -->|状态| D[state/]
    B -->|Hook| E[hooks/]
    B -->|样式| F[styling/]
    B -->|数据| G[data_fetching/]
    B -->|路由| H[routing/]

    C --> I[创建规则目录]
    D --> I
    E --> I
    F --> I
    G --> I
    H --> I

    I --> J[编写rule.md]
    J --> K[添加examples.md]
    K --> L[配置ESLint(如适用)]
    L --> M[加入审查检查清单]

Signal Files Reference

标识文件参考

SignalContentPurpose
.version
JSONSchema version
.enforced_by
ListTools that enforce
.eslint_rule
Rule nameESLint rule if applicable
.react_version
VersionReact version requirement

标识文件内容格式用途
.version
JSON架构版本
.enforced_by
列表执行工具集合
.eslint_rule
规则名称对应的ESLint规则(如适用)
.react_version
版本号React版本要求

Frontend Rule Checklist

前端规则检查清单

  • Rule is React/frontend specific
  • Examples use TypeScript + React
  • Shows correct and incorrect patterns
  • Mentions relevant ESLint rules
  • Considers React best practices
  • References React documentation if applicable
  • Performance implications noted
  • 规则为React/前端专属
  • 示例使用TypeScript + React
  • 展示正确和错误的模式
  • 提及相关的ESLint规则
  • 考虑React最佳实践
  • 如适用,参考React官方文档
  • 标注性能影响