desktop-team-doc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -0
- package/content/docs/README.md +227 -0
- package/content/docs/index.md +352 -0
- package/content/docs/instructions/coding-conventions/.clang-format +65 -0
- package/content/docs/instructions/coding-conventions/cpp.md +132 -0
- package/content/docs/instructions/coding-conventions/frontend.md +612 -0
- package/content/docs/instructions/coding-conventions/team-wide.md +176 -0
- package/content/docs/instructions/workflows/assets/jira-1.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-comment.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-release-note.png +0 -0
- package/content/docs/instructions/workflows/assets/jira-tag.png +0 -0
- package/content/docs/instructions/workflows/code-review.md +451 -0
- package/content/docs/instructions/workflows/git-branch-convention.md +246 -0
- package/content/docs/instructions/workflows/git-commit.md +95 -0
- package/content/docs/instructions/workflows/jira-process.md +173 -0
- package/content/docs/instructions/workflows/jira-ticket-guide.md +105 -0
- package/content/docs/instructions/workflows/pull-request-generation.md +319 -0
- package/content/docs/instructions/workflows/scrum-process.md +104 -0
- package/content/docs/instructions/workflows/survey-project-setup.md +76 -0
- package/content/docs/knowledge/architecture/README.md +11 -0
- package/content/docs/knowledge/architecture/audio-plugin-architecture.md +213 -0
- package/content/docs/knowledge/architecture/cross-platform-design.md +176 -0
- package/content/docs/knowledge/architecture/frontend-native-bridge.md +193 -0
- package/content/docs/knowledge/architecture/native-command.md +189 -0
- package/content/docs/knowledge/architecture/state-management-architecture.md +105 -0
- package/content/docs/knowledge/component-library/ControlComponent/README.md +281 -0
- package/content/docs/knowledge/component-library/ControlComponent/accessibility/accessibility-implementation.md +503 -0
- package/content/docs/knowledge/component-library/ControlComponent/common-mechanisms.md +278 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/error-handling.md +451 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/native-interface.md +515 -0
- package/content/docs/knowledge/component-library/ControlComponent/core/state-management.md +509 -0
- package/content/docs/knowledge/component-library/ControlComponent/creating-new-controls.md +654 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/api-design-reference.md +1142 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/design-principles.md +336 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/styling-architecture.md +595 -0
- package/content/docs/knowledge/component-library/ControlComponent/design/visual-feedback.md +456 -0
- package/content/docs/knowledge/component-library/ControlComponent/development-environment.md +213 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/gesture-algorithms.md +705 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/touch-support.md +525 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/value-processing-patterns.md +801 -0
- package/content/docs/knowledge/component-library/ControlComponent/interaction/velocity-damping-systems.md +741 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/architecture.md +490 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/how-to-use.md +304 -0
- package/content/docs/knowledge/component-library/ControlComponent/knob/index.md +105 -0
- package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-benchmarks.md +535 -0
- package/content/docs/knowledge/component-library/ControlComponent/optimization/performance-optimization.md +1092 -0
- package/content/docs/knowledge/component-library/ControlComponent/quick-start.md +345 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/architecture.md +444 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/how-to-use.md +470 -0
- package/content/docs/knowledge/component-library/ControlComponent/slider/index.md +107 -0
- package/content/docs/knowledge/component-library/ControlComponent/testing-guide.md +950 -0
- package/content/docs/knowledge/component-library/ControlComponent/troubleshooting.md +657 -0
- package/content/docs/knowledge/component-library/frontend-develop/LICENSE.txt +176 -0
- package/content/docs/knowledge/component-library/frontend-develop/SKILL.md +124 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/code-organization.md +620 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/coding-standards.md +275 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/component-reusability.md +559 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/examples.md +554 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/layout-separation.md +638 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/performance-optimization.md +678 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/state-management.md +331 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/styling-guidelines.md +349 -0
- package/content/docs/knowledge/component-library/frontend-develop/references/type-safety.md +493 -0
- package/content/docs/knowledge/development/assets/cyberduck-aws-credentials.png +0 -0
- package/content/docs/knowledge/development/assets/postman-environment-setup.png +0 -0
- package/content/docs/knowledge/development/aws-storage.md +95 -0
- package/content/docs/knowledge/development/crm-system.md +22 -0
- package/content/docs/knowledge/development/glossary.md +246 -0
- package/content/docs/knowledge/development/pg-api-guide.md +71 -0
- package/content/docs/knowledge/development/staging-license-management.md +44 -0
- package/content/docs/knowledge/development/tech-stack.md +240 -0
- package/content/docs/knowledge/domain/popup-system.md +106 -0
- package/content/docs/knowledge/domain/sigpath.md +264 -0
- package/content/docs/knowledge/environment-setup/aax-signing-update.md +149 -0
- package/content/docs/knowledge/environment-setup/assets/aax-1.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-2.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-3.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-4.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-5.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-6.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/aax-7.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-1.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-10.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-11.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-12.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-13.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-14.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-2.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-3.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-4.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-5.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-6.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-7.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-8.png +0 -0
- package/content/docs/knowledge/environment-setup/assets/buildmachine-9.png +0 -0
- package/content/docs/knowledge/environment-setup/build-machine-setup.md +224 -0
- package/content/docs/knowledge/environment-setup/build-machine-troubleshooting.md +193 -0
- package/content/docs/knowledge/implementation-guides/adding-amp.md +190 -0
- package/content/docs/knowledge/implementation-guides/adding-fx.md +111 -0
- package/content/docs/knowledge/implementation-guides/cab-integration.md +194 -0
- package/content/docs/knowledge/implementation-guides/custom-pedal-integration.md +309 -0
- package/content/docs/knowledge/projects/BIAS_ONE_GUI/README.md +17 -0
- package/content/manifest.json +122 -0
- package/content/rules/cpp.mdc +135 -0
- package/content/rules/frontend.mdc +615 -0
- package/content/rules/index.mdc +256 -0
- package/content/rules/knowledge.mdc +46 -0
- package/content/rules/team-wide.mdc +179 -0
- package/content/rules/workflows.mdc +43 -0
- package/content/tools/agents/context-compressor.md +357 -0
- package/content/tools/agents/context-writer.md +328 -0
- package/content/tools/agents/release-notes-generator.md +389 -0
- package/content/tools/agents/srs-writer-agent.md +63 -0
- package/content/tools/mcp/README.md +25 -0
- package/content/tools/mcp/mcp-desktop-team.example.json +13 -0
- package/content/tools/skills/frontend-develop/LICENSE.txt +176 -0
- package/content/tools/skills/frontend-develop/SKILL.md +124 -0
- package/content/tools/skills/frontend-develop/references/code-organization.md +620 -0
- package/content/tools/skills/frontend-develop/references/coding-standards.md +275 -0
- package/content/tools/skills/frontend-develop/references/component-reusability.md +559 -0
- package/content/tools/skills/frontend-develop/references/examples.md +554 -0
- package/content/tools/skills/frontend-develop/references/layout-separation.md +638 -0
- package/content/tools/skills/frontend-develop/references/performance-optimization.md +678 -0
- package/content/tools/skills/frontend-develop/references/state-management.md +331 -0
- package/content/tools/skills/frontend-develop/references/styling-guidelines.md +349 -0
- package/content/tools/skills/frontend-develop/references/type-safety.md +493 -0
- package/content/tools/slash-commands/commit.md +17 -0
- package/content/tools/slash-commands/context-compress.md +149 -0
- package/content/tools/slash-commands/context-write.md +92 -0
- package/content/tools/slash-commands/jira.md +12 -0
- package/content/tools/slash-commands/pr-gen.md +12 -0
- package/content/tools/slash-commands/pr-review.md +12 -0
- package/dist/commands/detect.d.ts +1 -0
- package/dist/commands/detect.js +33 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +100 -0
- package/dist/commands/uninstall.d.ts +1 -0
- package/dist/commands/uninstall.js +132 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/lib/detect-env.d.ts +3 -0
- package/dist/lib/detect-env.js +52 -0
- package/dist/lib/prompt-env.d.ts +3 -0
- package/dist/lib/prompt-env.js +16 -0
- package/dist/lib/resolve-doc-repo.d.ts +14 -0
- package/dist/lib/resolve-doc-repo.js +61 -0
- package/dist/lib/symlink.d.ts +7 -0
- package/dist/lib/symlink.js +60 -0
- package/dist/lib/sync-from-manifest.d.ts +8 -0
- package/dist/lib/sync-from-manifest.js +64 -0
- package/package.json +46 -0
package/content/docs/knowledge/component-library/frontend-develop/references/state-management.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# State Management Guidelines
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive guidelines for state management in React applications, including when to use Redux or local state.
|
|
4
|
+
|
|
5
|
+
## Priority Order
|
|
6
|
+
|
|
7
|
+
**State Management Priority**: Redux > Local State
|
|
8
|
+
|
|
9
|
+
**Zustand 政策**: Zustand 僅既有程式保留使用;新 state 一律使用 Redux 或 Local State。
|
|
10
|
+
|
|
11
|
+
Choose state management solution based on:
|
|
12
|
+
|
|
13
|
+
1. **Scope**: Where is the state used?
|
|
14
|
+
2. **Persistence**: Does state need to persist?
|
|
15
|
+
3. **Complexity**: How complex is the state logic?
|
|
16
|
+
4. **Sharing**: How many components need access?
|
|
17
|
+
|
|
18
|
+
## Redux (Preferred for Global State)
|
|
19
|
+
|
|
20
|
+
### When to Use Redux
|
|
21
|
+
|
|
22
|
+
Use Redux when:
|
|
23
|
+
|
|
24
|
+
- State is global and shared across many components
|
|
25
|
+
- State needs to persist across navigation
|
|
26
|
+
- State needs time-travel debugging
|
|
27
|
+
- Complex state updates with middleware
|
|
28
|
+
- State needs to be synchronized with external systems
|
|
29
|
+
|
|
30
|
+
### Redux Toolkit Patterns
|
|
31
|
+
|
|
32
|
+
**Slice Creation**:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
36
|
+
|
|
37
|
+
interface AppState {
|
|
38
|
+
isOpen: boolean;
|
|
39
|
+
currentUser: string | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const initialState: AppState = {
|
|
43
|
+
isOpen: false,
|
|
44
|
+
currentUser: null,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const appSlice = createSlice({
|
|
48
|
+
name: 'app',
|
|
49
|
+
initialState,
|
|
50
|
+
reducers: {
|
|
51
|
+
setOpen: (state, action: PayloadAction<boolean>) => {
|
|
52
|
+
state.isOpen = action.payload;
|
|
53
|
+
},
|
|
54
|
+
setUser: (state, action: PayloadAction<string>) => {
|
|
55
|
+
state.currentUser = action.payload;
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const { setOpen, setUser } = appSlice.actions;
|
|
61
|
+
export default appSlice.reducer;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Usage in Components**:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
68
|
+
import { setOpen } from './appSlice';
|
|
69
|
+
|
|
70
|
+
function Component() {
|
|
71
|
+
const isOpen = useSelector((state: RootState) => state.app.isOpen);
|
|
72
|
+
const dispatch = useDispatch();
|
|
73
|
+
|
|
74
|
+
const handleOpen = () => {
|
|
75
|
+
dispatch(setOpen(true));
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return <div>{/* Component JSX */}</div>;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Async Operations with createAsyncThunk**:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
|
|
86
|
+
|
|
87
|
+
export const fetchUserData = createAsyncThunk('user/fetchUserData', async (userId: string) => {
|
|
88
|
+
const response = await fetch(`/api/users/${userId}`);
|
|
89
|
+
return response.json();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const userSlice = createSlice({
|
|
93
|
+
name: 'user',
|
|
94
|
+
initialState: { data: null, loading: false, error: null },
|
|
95
|
+
reducers: {},
|
|
96
|
+
extraReducers: (builder) => {
|
|
97
|
+
builder
|
|
98
|
+
.addCase(fetchUserData.pending, (state) => {
|
|
99
|
+
state.loading = true;
|
|
100
|
+
})
|
|
101
|
+
.addCase(fetchUserData.fulfilled, (state, action) => {
|
|
102
|
+
state.loading = false;
|
|
103
|
+
state.data = action.payload;
|
|
104
|
+
})
|
|
105
|
+
.addCase(fetchUserData.rejected, (state, action) => {
|
|
106
|
+
state.loading = false;
|
|
107
|
+
state.error = action.error.message;
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Local State (Preferred for Component-Specific State)
|
|
114
|
+
|
|
115
|
+
### When to Use Local State
|
|
116
|
+
|
|
117
|
+
Use local state when:
|
|
118
|
+
|
|
119
|
+
- State is component-specific
|
|
120
|
+
- State doesn't need to be shared
|
|
121
|
+
- Simple state management
|
|
122
|
+
- UI-only state (modals, form inputs, toggles)
|
|
123
|
+
|
|
124
|
+
### useState Pattern
|
|
125
|
+
|
|
126
|
+
**Simple State**:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
function Component() {
|
|
130
|
+
const [isTypingMode, setIsTypingMode] = useState(false);
|
|
131
|
+
const [inputValue, setInputValue] = useState('');
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div>
|
|
135
|
+
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### useReducer Pattern
|
|
142
|
+
|
|
143
|
+
**Complex State**:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
interface State {
|
|
147
|
+
count: number;
|
|
148
|
+
step: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' } | { type: 'setStep'; step: number };
|
|
152
|
+
|
|
153
|
+
function reducer(state: State, action: Action): State {
|
|
154
|
+
switch (action.type) {
|
|
155
|
+
case 'increment':
|
|
156
|
+
return { ...state, count: state.count + state.step };
|
|
157
|
+
case 'decrement':
|
|
158
|
+
return { ...state, count: state.count - state.step };
|
|
159
|
+
case 'reset':
|
|
160
|
+
return { ...state, count: 0 };
|
|
161
|
+
case 'setStep':
|
|
162
|
+
return { ...state, step: action.step };
|
|
163
|
+
default:
|
|
164
|
+
return state;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function Component() {
|
|
169
|
+
const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div>
|
|
173
|
+
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
|
|
174
|
+
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
|
|
175
|
+
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
|
|
176
|
+
</div>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Zustand(既有功能保留)
|
|
182
|
+
|
|
183
|
+
Zustand 僅用於既有模組,新 state 一律使用 Redux 或 Local State。既有程式若使用 Zustand,可參考 [Zustand Documentation](https://github.com/pmndrs/zustand) 了解訂閱與使用方式。
|
|
184
|
+
|
|
185
|
+
## Decision Tree
|
|
186
|
+
|
|
187
|
+
### State Management Decision Flow
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
Is state used by multiple components?
|
|
191
|
+
├─ No → Use Local State (useState/useReducer)
|
|
192
|
+
└─ Yes
|
|
193
|
+
├─ Is state global/shared across many components?
|
|
194
|
+
│ ├─ Yes → Use Redux
|
|
195
|
+
│ └─ No
|
|
196
|
+
│ ├─ Is state module-specific?
|
|
197
|
+
│ │ ├─ Yes → Use Redux or Local State (lift state up)
|
|
198
|
+
│ │ └─ No → Use Local State (lift state up)
|
|
199
|
+
│ └─ Does state need persistence?
|
|
200
|
+
│ ├─ Yes → Use Redux
|
|
201
|
+
│ └─ No → Use Local State
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Best Practices
|
|
205
|
+
|
|
206
|
+
### State Colocation
|
|
207
|
+
|
|
208
|
+
**Rule**: Keep state as close to where it's used as possible.
|
|
209
|
+
|
|
210
|
+
**Bad**:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// State in root component
|
|
214
|
+
function App() {
|
|
215
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
216
|
+
return (
|
|
217
|
+
<>
|
|
218
|
+
<Header />
|
|
219
|
+
<Content />
|
|
220
|
+
<Modal open={modalOpen} onClose={() => setModalOpen(false)} />
|
|
221
|
+
</>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Good**:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// State colocated with component that uses it
|
|
230
|
+
function App() {
|
|
231
|
+
return (
|
|
232
|
+
<>
|
|
233
|
+
<Header />
|
|
234
|
+
<Content />
|
|
235
|
+
<ModalContainer />
|
|
236
|
+
</>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function ModalContainer() {
|
|
241
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
242
|
+
return <Modal open={modalOpen} onClose={() => setModalOpen(false)} />;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### State Normalization
|
|
247
|
+
|
|
248
|
+
**Rule**: Normalize nested state structures.
|
|
249
|
+
|
|
250
|
+
**Bad**:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
interface State {
|
|
254
|
+
users: {
|
|
255
|
+
[id: string]: {
|
|
256
|
+
id: string;
|
|
257
|
+
name: string;
|
|
258
|
+
posts: {
|
|
259
|
+
[id: string]: {
|
|
260
|
+
id: string;
|
|
261
|
+
title: string;
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Good**:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
interface State {
|
|
273
|
+
users: {
|
|
274
|
+
[id: string]: {
|
|
275
|
+
id: string;
|
|
276
|
+
name: string;
|
|
277
|
+
postIds: string[];
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
posts: {
|
|
281
|
+
[id: string]: {
|
|
282
|
+
id: string;
|
|
283
|
+
userId: string;
|
|
284
|
+
title: string;
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Derived State
|
|
291
|
+
|
|
292
|
+
**Rule**: Compute derived state instead of storing it.
|
|
293
|
+
|
|
294
|
+
**Bad**:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
298
|
+
const [filteredItems, setFilteredItems] = useState<Item[]>([]);
|
|
299
|
+
|
|
300
|
+
useEffect(() => {
|
|
301
|
+
setFilteredItems(items.filter((item) => item.active));
|
|
302
|
+
}, [items]);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Good**:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
309
|
+
|
|
310
|
+
// Compute derived state directly
|
|
311
|
+
const filteredItems = items.filter((item) => item.active);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Summary Checklist
|
|
315
|
+
|
|
316
|
+
When choosing state management, ensure:
|
|
317
|
+
|
|
318
|
+
- [ ] State scope evaluated (local vs global)
|
|
319
|
+
- [ ] Redux used for global/shared state
|
|
320
|
+
- [ ] Local state used for component-specific state
|
|
321
|
+
- [ ] State colocated close to usage
|
|
322
|
+
- [ ] State normalized when nested
|
|
323
|
+
- [ ] Derived state computed, not stored
|
|
324
|
+
- [ ] Redux Toolkit patterns followed
|
|
325
|
+
- [ ] Async operations use createAsyncThunk
|
|
326
|
+
|
|
327
|
+
## References
|
|
328
|
+
|
|
329
|
+
- [Redux Toolkit Documentation](https://redux-toolkit.js.org/)
|
|
330
|
+
- [React State Management](https://react.dev/learn/managing-state)
|
|
331
|
+
- Project Coding Standards: `desktop-team-documentation/instructions/coding-conventions/frontend.md`
|
package/content/docs/knowledge/component-library/frontend-develop/references/styling-guidelines.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Styling Guidelines
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive guidelines for styling in React applications, including TailwindCSS priority strategy and style organization.
|
|
4
|
+
|
|
5
|
+
## Styling Priority
|
|
6
|
+
|
|
7
|
+
**Styling Priority**: TailwindCSS > Custom CSS
|
|
8
|
+
|
|
9
|
+
## TailwindCSS (Primary)
|
|
10
|
+
|
|
11
|
+
### Utility-First Approach
|
|
12
|
+
|
|
13
|
+
**Rule**: Prefer Tailwind utilities over custom CSS.
|
|
14
|
+
|
|
15
|
+
**Example**:
|
|
16
|
+
```typescript
|
|
17
|
+
function Component() {
|
|
18
|
+
return (
|
|
19
|
+
<div className="p-4 bg-white rounded-lg shadow-md">
|
|
20
|
+
<h2 className="text-xl font-bold mb-2">Title</h2>
|
|
21
|
+
<p className="text-gray-600">Content</p>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Class Merging
|
|
28
|
+
|
|
29
|
+
**Rule**: Use `twMerge` to merge conflicting Tailwind classes.
|
|
30
|
+
|
|
31
|
+
**Example**:
|
|
32
|
+
```typescript
|
|
33
|
+
import { twMerge } from 'tailwind-merge';
|
|
34
|
+
|
|
35
|
+
interface ComponentProps {
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function Component({ className }: ComponentProps) {
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
className={twMerge(
|
|
43
|
+
'p-4 bg-white rounded-lg',
|
|
44
|
+
className // Can override previous classes
|
|
45
|
+
)}
|
|
46
|
+
>
|
|
47
|
+
Content
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Conditional Classes
|
|
54
|
+
|
|
55
|
+
**Rule**: Use `clsx` for conditional class names.
|
|
56
|
+
|
|
57
|
+
**Example**:
|
|
58
|
+
```typescript
|
|
59
|
+
import clsx from 'clsx';
|
|
60
|
+
|
|
61
|
+
function Button({ active, disabled }: Props) {
|
|
62
|
+
return (
|
|
63
|
+
<button
|
|
64
|
+
className={clsx(
|
|
65
|
+
'x-btn',
|
|
66
|
+
{
|
|
67
|
+
'x-btn-active': active,
|
|
68
|
+
'x-btn-disabled': disabled,
|
|
69
|
+
}
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
Click
|
|
73
|
+
</button>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Design System Classes
|
|
79
|
+
|
|
80
|
+
**Rule**: Use predefined design system classes.
|
|
81
|
+
|
|
82
|
+
**Typography Classes**:
|
|
83
|
+
- `.x-heading-14`, `.x-heading-16`, `.x-heading-18`
|
|
84
|
+
- `.x-body-3`, `.x-body-4`
|
|
85
|
+
- `.heading-14`, `.body-16`
|
|
86
|
+
|
|
87
|
+
**Component Classes**:
|
|
88
|
+
- `.x-btn`, `.x-btn-active`, `.x-btn-disabled`
|
|
89
|
+
- `.x-red-dot`
|
|
90
|
+
- `.pg-scroll-bar`
|
|
91
|
+
|
|
92
|
+
**Example**:
|
|
93
|
+
```typescript
|
|
94
|
+
function Component() {
|
|
95
|
+
return (
|
|
96
|
+
<div>
|
|
97
|
+
<h1 className="x-heading-18">Title</h1>
|
|
98
|
+
<p className="x-body-4">Content</p>
|
|
99
|
+
<button className="x-btn x-btn-active">Click</button>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Responsive Design
|
|
106
|
+
|
|
107
|
+
**Rule**: Use Tailwind breakpoint prefixes.
|
|
108
|
+
|
|
109
|
+
**Breakpoints**:
|
|
110
|
+
- `sm:` - 640px
|
|
111
|
+
- `md:` - 768px
|
|
112
|
+
- `lg:` - 1024px
|
|
113
|
+
- `xl:` - 1280px
|
|
114
|
+
- `2xl:` - 1536px
|
|
115
|
+
|
|
116
|
+
**Example**:
|
|
117
|
+
```typescript
|
|
118
|
+
function Component() {
|
|
119
|
+
return (
|
|
120
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
121
|
+
<div>Item 1</div>
|
|
122
|
+
<div>Item 2</div>
|
|
123
|
+
<div>Item 3</div>
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 關於 Emotion / styled-components
|
|
130
|
+
|
|
131
|
+
專案因效能考量已不再使用 Emotion 與 styled-components。新樣式請使用 Tailwind;既有程式若仍使用 Emotion 可逐步遷移。
|
|
132
|
+
|
|
133
|
+
## Custom CSS
|
|
134
|
+
|
|
135
|
+
### When to Use Custom CSS
|
|
136
|
+
|
|
137
|
+
Use custom CSS only when:
|
|
138
|
+
- Global styles needed
|
|
139
|
+
- Complex animations that can't be done with Tailwind
|
|
140
|
+
- Third-party library overrides
|
|
141
|
+
- Design system utilities
|
|
142
|
+
|
|
143
|
+
### Global Styles
|
|
144
|
+
|
|
145
|
+
**Rule**: Define global styles in Tailwind config or global CSS files.
|
|
146
|
+
|
|
147
|
+
**tailwind.config.js**:
|
|
148
|
+
```javascript
|
|
149
|
+
module.exports = {
|
|
150
|
+
theme: {
|
|
151
|
+
extend: {
|
|
152
|
+
colors: {
|
|
153
|
+
primary: '#your-color',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**global.css**:
|
|
161
|
+
```css
|
|
162
|
+
@tailwind base;
|
|
163
|
+
@tailwind components;
|
|
164
|
+
@tailwind utilities;
|
|
165
|
+
|
|
166
|
+
@layer base {
|
|
167
|
+
body {
|
|
168
|
+
@apply font-sans antialiased;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Style Organization
|
|
174
|
+
|
|
175
|
+
### Component Styles
|
|
176
|
+
|
|
177
|
+
**Rule**: Keep styles close to components.
|
|
178
|
+
|
|
179
|
+
**Structure**:
|
|
180
|
+
```
|
|
181
|
+
Component.tsx
|
|
182
|
+
Component.module.css (if needed)
|
|
183
|
+
Component.test.tsx
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Theme Variables
|
|
187
|
+
|
|
188
|
+
**Rule**: Use Tailwind theme configuration for design tokens.
|
|
189
|
+
|
|
190
|
+
**tailwind.config.js**:
|
|
191
|
+
```javascript
|
|
192
|
+
module.exports = {
|
|
193
|
+
theme: {
|
|
194
|
+
extend: {
|
|
195
|
+
colors: {
|
|
196
|
+
primary: {
|
|
197
|
+
50: '#f0f9ff',
|
|
198
|
+
500: '#3b82f6',
|
|
199
|
+
900: '#1e3a8a',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
spacing: {
|
|
203
|
+
'18': '4.5rem',
|
|
204
|
+
'88': '22rem',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Custom Utilities
|
|
212
|
+
|
|
213
|
+
**Rule**: Define custom utilities in Tailwind config using plugins.
|
|
214
|
+
|
|
215
|
+
**tailwind.config.js**:
|
|
216
|
+
```javascript
|
|
217
|
+
const plugin = require('tailwindcss/plugin');
|
|
218
|
+
|
|
219
|
+
module.exports = {
|
|
220
|
+
plugins: [
|
|
221
|
+
plugin(function ({ addUtilities }) {
|
|
222
|
+
addUtilities({
|
|
223
|
+
'.scrollbar-hide': {
|
|
224
|
+
'-ms-overflow-style': 'none',
|
|
225
|
+
'scrollbar-width': 'none',
|
|
226
|
+
'&::-webkit-scrollbar': {
|
|
227
|
+
display: 'none',
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}),
|
|
232
|
+
],
|
|
233
|
+
};
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Performance Considerations
|
|
237
|
+
|
|
238
|
+
### CSS Performance
|
|
239
|
+
|
|
240
|
+
**Rule**: Optimize CSS for performance.
|
|
241
|
+
|
|
242
|
+
**Best Practices**:
|
|
243
|
+
- Use Tailwind's purging to remove unused styles
|
|
244
|
+
- Avoid deeply nested selectors
|
|
245
|
+
- Use CSS transforms for animations
|
|
246
|
+
- Minimize layout thrashing
|
|
247
|
+
|
|
248
|
+
See [Performance Optimization](./performance-optimization.md) for detailed CSS performance guidelines.
|
|
249
|
+
|
|
250
|
+
## Common Patterns
|
|
251
|
+
|
|
252
|
+
### Pattern 1: Variant Styling
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { twMerge } from 'tailwind-merge';
|
|
256
|
+
import clsx from 'clsx';
|
|
257
|
+
|
|
258
|
+
interface ButtonProps {
|
|
259
|
+
variant?: 'primary' | 'secondary';
|
|
260
|
+
size?: 'small' | 'medium' | 'large';
|
|
261
|
+
className?: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function Button({
|
|
265
|
+
variant = 'primary',
|
|
266
|
+
size = 'medium',
|
|
267
|
+
className,
|
|
268
|
+
...props
|
|
269
|
+
}: ButtonProps) {
|
|
270
|
+
return (
|
|
271
|
+
<button
|
|
272
|
+
className={twMerge(
|
|
273
|
+
'rounded font-medium transition',
|
|
274
|
+
variant === 'primary' && 'bg-blue-500 text-white hover:bg-blue-600',
|
|
275
|
+
variant === 'secondary' && 'bg-gray-200 text-gray-800 hover:bg-gray-300',
|
|
276
|
+
size === 'small' && 'px-2 py-1 text-sm',
|
|
277
|
+
size === 'medium' && 'px-4 py-2 text-base',
|
|
278
|
+
size === 'large' && 'px-6 py-3 text-lg',
|
|
279
|
+
className
|
|
280
|
+
)}
|
|
281
|
+
{...props}
|
|
282
|
+
/>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Pattern 2: Conditional Styling
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import clsx from 'clsx';
|
|
291
|
+
|
|
292
|
+
function Component({ isActive, isDisabled }: Props) {
|
|
293
|
+
return (
|
|
294
|
+
<div
|
|
295
|
+
className={clsx(
|
|
296
|
+
'base-class',
|
|
297
|
+
{
|
|
298
|
+
'active-class': isActive,
|
|
299
|
+
'disabled-class': isDisabled,
|
|
300
|
+
}
|
|
301
|
+
)}
|
|
302
|
+
>
|
|
303
|
+
Content
|
|
304
|
+
</div>
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Pattern 3: Responsive Styling
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
function Component() {
|
|
313
|
+
return (
|
|
314
|
+
<div className="
|
|
315
|
+
grid
|
|
316
|
+
grid-cols-1
|
|
317
|
+
sm:grid-cols-2
|
|
318
|
+
md:grid-cols-3
|
|
319
|
+
lg:grid-cols-4
|
|
320
|
+
gap-4
|
|
321
|
+
p-4
|
|
322
|
+
md:p-6
|
|
323
|
+
lg:p-8
|
|
324
|
+
">
|
|
325
|
+
{/* Content */}
|
|
326
|
+
</div>
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Summary Checklist
|
|
332
|
+
|
|
333
|
+
When styling components, ensure:
|
|
334
|
+
|
|
335
|
+
- [ ] TailwindCSS used as primary styling approach
|
|
336
|
+
- [ ] `twMerge` used for class merging
|
|
337
|
+
- [ ] `clsx` used for conditional classes
|
|
338
|
+
- [ ] Design system classes used when available
|
|
339
|
+
- [ ] Responsive design with breakpoint prefixes
|
|
340
|
+
- [ ] Custom CSS minimized
|
|
341
|
+
- [ ] Styles organized close to components
|
|
342
|
+
- [ ] Theme variables in Tailwind config
|
|
343
|
+
- [ ] Performance considerations applied
|
|
344
|
+
|
|
345
|
+
## References
|
|
346
|
+
|
|
347
|
+
- [TailwindCSS Documentation](https://tailwindcss.com/docs)
|
|
348
|
+
- Project Coding Standards: `desktop-team-documentation/instructions/coding-conventions/frontend.md`
|
|
349
|
+
- [Performance Optimization](./performance-optimization.md)
|