ai-flow-dev 1.0.1
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/LICENSE +21 -0
- package/README.md +408 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +791 -0
- package/dist/cli.js.map +1 -0
- package/dist/fs-utils.d.ts +2 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/fs-utils.js +46 -0
- package/dist/fs-utils.js.map +1 -0
- package/package.json +71 -0
- package/prompts/backend/flow-dev-feature.md +1318 -0
- package/prompts/backend/flow-dev-fix.md +903 -0
- package/prompts/backend/flow-dev-refactor.md +715 -0
- package/prompts/backend/flow-dev-review.md +401 -0
- package/prompts/backend/flow-dev-work.md +1129 -0
- package/prompts/backend/flow-docs-gen-phase-0.md +1840 -0
- package/prompts/backend/flow-docs-gen-phase-1.md +435 -0
- package/prompts/backend/flow-docs-gen-phase-2.md +460 -0
- package/prompts/backend/flow-docs-gen-phase-3.md +684 -0
- package/prompts/backend/flow-docs-gen-phase-4.md +516 -0
- package/prompts/backend/flow-docs-gen-phase-5.md +637 -0
- package/prompts/backend/flow-docs-gen-phase-6.md +465 -0
- package/prompts/backend/flow-docs-gen-phase-7.md +1207 -0
- package/prompts/backend/flow-docs-gen.md +820 -0
- package/prompts/backend/flow-docs-sync.md +526 -0
- package/prompts/backend/flow-project-init.md +248 -0
- package/prompts/backend/flow-project-roadmap.md +1159 -0
- package/prompts/frontend/flow-docs-gen-phase-0.md +494 -0
- package/prompts/frontend/flow-docs-gen-phase-1.md +449 -0
- package/prompts/frontend/flow-docs-gen-phase-2.md +983 -0
- package/prompts/frontend/flow-docs-gen-phase-3.md +685 -0
- package/prompts/frontend/flow-docs-gen-phase-4.md +480 -0
- package/prompts/frontend/flow-docs-gen-phase-5.md +483 -0
- package/prompts/frontend/flow-docs-gen-phase-6.md +570 -0
- package/prompts/frontend/flow-docs-gen-phase-7.md +582 -0
- package/prompts/frontend/flow-docs-gen.md +413 -0
- package/prompts/frontend/flow-docs-sync.md +561 -0
- package/prompts/mobile/flow-docs-gen-phase-0.md +387 -0
- package/prompts/mobile/flow-docs-gen-phase-1.md +530 -0
- package/prompts/mobile/flow-docs-gen-phase-2.md +584 -0
- package/prompts/mobile/flow-docs-gen-phase-3.md +659 -0
- package/prompts/mobile/flow-docs-gen-phase-4.md +363 -0
- package/prompts/mobile/flow-docs-gen-phase-5.md +369 -0
- package/prompts/mobile/flow-docs-gen-phase-6.md +490 -0
- package/prompts/mobile/flow-docs-gen-phase-7.md +407 -0
- package/prompts/mobile/flow-docs-gen.md +430 -0
- package/prompts/mobile/flow-docs-sync.md +634 -0
- package/templates/backend/.clauderules.template +111 -0
- package/templates/backend/.cursorrules.template +102 -0
- package/templates/backend/.env.example.template +122 -0
- package/templates/backend/README.template.md +200 -0
- package/templates/backend/ai-instructions.template.md +354 -0
- package/templates/backend/copilot-instructions.template.md +160 -0
- package/templates/backend/docs/api.template.md +251 -0
- package/templates/backend/docs/architecture.template.md +612 -0
- package/templates/backend/docs/business-flows.template.md +109 -0
- package/templates/backend/docs/code-standards.template.md +828 -0
- package/templates/backend/docs/contributing.template.md +163 -0
- package/templates/backend/docs/data-model.template.md +416 -0
- package/templates/backend/docs/operations.template.md +591 -0
- package/templates/backend/docs/testing.template.md +762 -0
- package/templates/backend/project-brief.template.md +176 -0
- package/templates/backend/specs/configuration.template.md +133 -0
- package/templates/backend/specs/security.template.md +422 -0
- package/templates/frontend/README.template.md +121 -0
- package/templates/frontend/ai-instructions.template.md +368 -0
- package/templates/frontend/docs/api-integration.template.md +390 -0
- package/templates/frontend/docs/components.template.md +567 -0
- package/templates/frontend/docs/error-handling.template.md +385 -0
- package/templates/frontend/docs/operations.template.md +123 -0
- package/templates/frontend/docs/performance.template.md +140 -0
- package/templates/frontend/docs/pwa.template.md +135 -0
- package/templates/frontend/docs/state-management.template.md +394 -0
- package/templates/frontend/docs/styling.template.md +779 -0
- package/templates/frontend/docs/testing.template.md +736 -0
- package/templates/frontend/project-brief.template.md +55 -0
- package/templates/frontend/specs/accessibility.template.md +111 -0
- package/templates/frontend/specs/configuration.template.md +520 -0
- package/templates/frontend/specs/security.template.md +197 -0
- package/templates/fullstack/README.template.md +282 -0
- package/templates/fullstack/ai-instructions.template.md +487 -0
- package/templates/fullstack/project-brief.template.md +197 -0
- package/templates/fullstack/specs/configuration.template.md +380 -0
- package/templates/mobile/AGENT.template.md +251 -0
- package/templates/mobile/README.template.md +195 -0
- package/templates/mobile/ai-instructions.template.md +221 -0
- package/templates/mobile/docs/app-store.template.md +163 -0
- package/templates/mobile/docs/architecture.template.md +100 -0
- package/templates/mobile/docs/native-features.template.md +137 -0
- package/templates/mobile/docs/navigation.template.md +81 -0
- package/templates/mobile/docs/offline-strategy.template.md +90 -0
- package/templates/mobile/docs/permissions.template.md +70 -0
- package/templates/mobile/docs/state-management.template.md +116 -0
- package/templates/mobile/docs/testing.template.md +146 -0
- package/templates/mobile/project-brief.template.md +97 -0
- package/templates/mobile/specs/build-configuration.template.md +116 -0
- package/templates/mobile/specs/deployment.template.md +114 -0
- package/templates/shared/AGENT.template.md +252 -0
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
# Styling & Design System
|
|
2
|
+
|
|
3
|
+
> CSS architecture, theming, and design patterns for {{PROJECT_NAME}}
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🎨 Styling Approach
|
|
8
|
+
|
|
9
|
+
**Solution:** {{STYLING_APPROACH}}
|
|
10
|
+
|
|
11
|
+
{{STYLING_DESCRIPTION}}
|
|
12
|
+
|
|
13
|
+
**Key Decisions:**
|
|
14
|
+
- **Design Tokens:** {{DESIGN_TOKENS}}
|
|
15
|
+
- **Theme Support:** {{THEME_SUPPORT}}
|
|
16
|
+
- **Responsive Strategy:** {{RESPONSIVE_STRATEGY}}
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📐 CSS Architecture
|
|
21
|
+
|
|
22
|
+
### Styling Solutions Comparison
|
|
23
|
+
|
|
24
|
+
| Approach | Best For | Pros | Cons |
|
|
25
|
+
|----------|----------|------|------|
|
|
26
|
+
| **Tailwind CSS** | Rapid prototyping, consistent design | Utility-first, small bundle, no naming | Learning curve, HTML verbosity |
|
|
27
|
+
| **CSS Modules** | Component isolation | Local scope, type-safe (TS), simple | Setup required, no runtime theming |
|
|
28
|
+
| **Styled Components** | Dynamic theming, React | CSS-in-JS, props-based, SSR support | Runtime cost, bundle size |
|
|
29
|
+
| **Emotion** | Flexibility, performance | Faster than SC, both runtime/compile | More boilerplate |
|
|
30
|
+
| **Sass/SCSS** | Traditional projects | Mature, powerful features | Global scope, manual optimization |
|
|
31
|
+
|
|
32
|
+
### Current Approach: {{STYLING_APPROACH}}
|
|
33
|
+
|
|
34
|
+
```{{STYLING_EXAMPLE_LANG}}
|
|
35
|
+
{{STYLING_EXAMPLE_CODE}}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Why this approach:**
|
|
39
|
+
{{STYLING_RATIONALE}}
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🎨 Design Tokens
|
|
44
|
+
|
|
45
|
+
{{#IF_DESIGN_TOKENS}}
|
|
46
|
+
|
|
47
|
+
### Token Structure
|
|
48
|
+
|
|
49
|
+
Design tokens are the single source of truth for design decisions (colors, spacing, typography, etc.).
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// tokens/colors.ts
|
|
53
|
+
export const colors = {
|
|
54
|
+
// Brand
|
|
55
|
+
primary: {
|
|
56
|
+
50: '#e3f2fd',
|
|
57
|
+
100: '#bbdefb',
|
|
58
|
+
// ... up to 900
|
|
59
|
+
DEFAULT: '#1976d2',
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Semantic
|
|
63
|
+
success: '#4caf50',
|
|
64
|
+
warning: '#ff9800',
|
|
65
|
+
error: '#f44336',
|
|
66
|
+
info: '#2196f3',
|
|
67
|
+
|
|
68
|
+
// Neutrals
|
|
69
|
+
gray: {
|
|
70
|
+
50: '#fafafa',
|
|
71
|
+
100: '#f5f5f5',
|
|
72
|
+
// ... up to 900
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// tokens/spacing.ts
|
|
77
|
+
export const spacing = {
|
|
78
|
+
0: '0',
|
|
79
|
+
1: '0.25rem', // 4px
|
|
80
|
+
2: '0.5rem', // 8px
|
|
81
|
+
3: '0.75rem', // 12px
|
|
82
|
+
4: '1rem', // 16px
|
|
83
|
+
// ... up to 96
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// tokens/typography.ts
|
|
87
|
+
export const typography = {
|
|
88
|
+
fontFamily: {
|
|
89
|
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
90
|
+
mono: ['Fira Code', 'monospace']
|
|
91
|
+
},
|
|
92
|
+
fontSize: {
|
|
93
|
+
xs: ['0.75rem', { lineHeight: '1rem' }],
|
|
94
|
+
sm: ['0.875rem', { lineHeight: '1.25rem' }],
|
|
95
|
+
base: ['1rem', { lineHeight: '1.5rem' }],
|
|
96
|
+
// ... up to 9xl
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Token Usage
|
|
102
|
+
|
|
103
|
+
**Tailwind Config:**
|
|
104
|
+
```javascript
|
|
105
|
+
// tailwind.config.js
|
|
106
|
+
import { colors, spacing, typography } from './tokens';
|
|
107
|
+
|
|
108
|
+
export default {
|
|
109
|
+
theme: {
|
|
110
|
+
extend: {
|
|
111
|
+
colors,
|
|
112
|
+
spacing,
|
|
113
|
+
...typography
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**CSS Variables:**
|
|
120
|
+
```css
|
|
121
|
+
/* global.css */
|
|
122
|
+
:root {
|
|
123
|
+
/* Colors */
|
|
124
|
+
--color-primary: #1976d2;
|
|
125
|
+
--color-success: #4caf50;
|
|
126
|
+
|
|
127
|
+
/* Spacing */
|
|
128
|
+
--spacing-1: 0.25rem;
|
|
129
|
+
--spacing-2: 0.5rem;
|
|
130
|
+
|
|
131
|
+
/* Typography */
|
|
132
|
+
--font-sans: 'Inter', system-ui, sans-serif;
|
|
133
|
+
--text-base: 1rem;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Usage */
|
|
137
|
+
.button {
|
|
138
|
+
background-color: var(--color-primary);
|
|
139
|
+
padding: var(--spacing-3) var(--spacing-6);
|
|
140
|
+
font-family: var(--font-sans);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Styled Components:**
|
|
145
|
+
```typescript
|
|
146
|
+
// theme.ts
|
|
147
|
+
export const theme = {
|
|
148
|
+
colors: { /* ... */ },
|
|
149
|
+
spacing: { /* ... */ }
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Usage
|
|
153
|
+
import styled from 'styled-components';
|
|
154
|
+
|
|
155
|
+
const Button = styled.button`
|
|
156
|
+
background: ${p => p.theme.colors.primary};
|
|
157
|
+
padding: ${p => p.theme.spacing[3]};
|
|
158
|
+
`;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
{{/IF_DESIGN_TOKENS}}
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 🌗 Theming
|
|
166
|
+
|
|
167
|
+
### Theme Implementation: {{THEME_SUPPORT}}
|
|
168
|
+
|
|
169
|
+
{{#IF_DARK_MODE}}
|
|
170
|
+
|
|
171
|
+
### Dark Mode Strategy
|
|
172
|
+
|
|
173
|
+
**Approach:** {{DARK_MODE_STRATEGY}}
|
|
174
|
+
|
|
175
|
+
#### CSS Variables Approach
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
/* themes.css */
|
|
179
|
+
:root {
|
|
180
|
+
--bg-primary: #ffffff;
|
|
181
|
+
--bg-secondary: #f5f5f5;
|
|
182
|
+
--text-primary: #212121;
|
|
183
|
+
--text-secondary: #757575;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
[data-theme="dark"] {
|
|
187
|
+
--bg-primary: #121212;
|
|
188
|
+
--bg-secondary: #1e1e1e;
|
|
189
|
+
--text-primary: #ffffff;
|
|
190
|
+
--text-secondary: #b0b0b0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Usage */
|
|
194
|
+
.card {
|
|
195
|
+
background: var(--bg-primary);
|
|
196
|
+
color: var(--text-primary);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### React Context Approach
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// ThemeContext.tsx
|
|
204
|
+
import { createContext, useContext, useState, useEffect } from 'react';
|
|
205
|
+
|
|
206
|
+
type Theme = 'light' | 'dark';
|
|
207
|
+
|
|
208
|
+
const ThemeContext = createContext<{
|
|
209
|
+
theme: Theme;
|
|
210
|
+
toggleTheme: () => void;
|
|
211
|
+
}>({ theme: 'light', toggleTheme: () => {} });
|
|
212
|
+
|
|
213
|
+
export const ThemeProvider = ({ children }) => {
|
|
214
|
+
const [theme, setTheme] = useState<Theme>(() => {
|
|
215
|
+
const saved = localStorage.getItem('theme');
|
|
216
|
+
return (saved as Theme) || 'light';
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
221
|
+
localStorage.setItem('theme', theme);
|
|
222
|
+
}, [theme]);
|
|
223
|
+
|
|
224
|
+
const toggleTheme = () => {
|
|
225
|
+
setTheme(prev => prev === 'light' ? 'dark' : 'light');
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<ThemeContext.Provider value={{ theme, toggleTheme }}>
|
|
230
|
+
{children}
|
|
231
|
+
</ThemeContext.Provider>
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const useTheme = () => useContext(ThemeContext);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### System Preference Detection
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Detect user's system preference
|
|
242
|
+
const getSystemTheme = (): Theme => {
|
|
243
|
+
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
|
244
|
+
return 'dark';
|
|
245
|
+
}
|
|
246
|
+
return 'light';
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Listen for system changes
|
|
250
|
+
useEffect(() => {
|
|
251
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
252
|
+
|
|
253
|
+
const handler = (e: MediaQueryListEvent) => {
|
|
254
|
+
setTheme(e.matches ? 'dark' : 'light');
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
mediaQuery.addEventListener('change', handler);
|
|
258
|
+
return () => mediaQuery.removeEventListener('change', handler);
|
|
259
|
+
}, []);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
{{/IF_DARK_MODE}}
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 📱 Responsive Design
|
|
267
|
+
|
|
268
|
+
### Breakpoint Strategy
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// breakpoints.ts
|
|
272
|
+
export const breakpoints = {
|
|
273
|
+
sm: '640px', // Mobile landscape
|
|
274
|
+
md: '768px', // Tablet
|
|
275
|
+
lg: '1024px', // Desktop
|
|
276
|
+
xl: '1280px', // Large desktop
|
|
277
|
+
'2xl': '1536px' // Extra large
|
|
278
|
+
};
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Responsive Patterns
|
|
282
|
+
|
|
283
|
+
#### Mobile-First Approach (Recommended)
|
|
284
|
+
|
|
285
|
+
```css
|
|
286
|
+
/* Base styles (mobile) */
|
|
287
|
+
.container {
|
|
288
|
+
padding: 1rem;
|
|
289
|
+
font-size: 0.875rem;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Tablet and up */
|
|
293
|
+
@media (min-width: 768px) {
|
|
294
|
+
.container {
|
|
295
|
+
padding: 2rem;
|
|
296
|
+
font-size: 1rem;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Desktop and up */
|
|
301
|
+
@media (min-width: 1024px) {
|
|
302
|
+
.container {
|
|
303
|
+
padding: 3rem;
|
|
304
|
+
max-width: 1200px;
|
|
305
|
+
margin: 0 auto;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### Tailwind Responsive Classes
|
|
311
|
+
|
|
312
|
+
```jsx
|
|
313
|
+
<div className="
|
|
314
|
+
text-sm md:text-base lg:text-lg
|
|
315
|
+
p-4 md:p-6 lg:p-8
|
|
316
|
+
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3
|
|
317
|
+
">
|
|
318
|
+
{/* Responsive content */}
|
|
319
|
+
</div>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Container Queries (Modern)
|
|
323
|
+
|
|
324
|
+
```css
|
|
325
|
+
/* Container-based responsive design */
|
|
326
|
+
.card-container {
|
|
327
|
+
container-type: inline-size;
|
|
328
|
+
container-name: card;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.card-title {
|
|
332
|
+
font-size: 1rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* When container is >400px wide */
|
|
336
|
+
@container card (min-width: 400px) {
|
|
337
|
+
.card-title {
|
|
338
|
+
font-size: 1.5rem;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## 🧩 Component Styling Patterns
|
|
346
|
+
|
|
347
|
+
### Pattern 1: Compound Variants (Recommended)
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// Button.tsx (using class-variance-authority)
|
|
351
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
352
|
+
|
|
353
|
+
const buttonStyles = cva(
|
|
354
|
+
// Base styles
|
|
355
|
+
'rounded font-semibold transition-colors focus:outline-none focus:ring-2',
|
|
356
|
+
{
|
|
357
|
+
variants: {
|
|
358
|
+
intent: {
|
|
359
|
+
primary: 'bg-blue-600 text-white hover:bg-blue-700',
|
|
360
|
+
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
|
|
361
|
+
danger: 'bg-red-600 text-white hover:bg-red-700'
|
|
362
|
+
},
|
|
363
|
+
size: {
|
|
364
|
+
sm: 'px-3 py-1.5 text-sm',
|
|
365
|
+
md: 'px-4 py-2 text-base',
|
|
366
|
+
lg: 'px-6 py-3 text-lg'
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
compoundVariants: [
|
|
370
|
+
{
|
|
371
|
+
intent: 'primary',
|
|
372
|
+
size: 'lg',
|
|
373
|
+
className: 'font-bold shadow-lg'
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
defaultVariants: {
|
|
377
|
+
intent: 'primary',
|
|
378
|
+
size: 'md'
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
export const Button = ({ intent, size, className, ...props }:
|
|
384
|
+
VariantProps<typeof buttonStyles> & React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
385
|
+
) => (
|
|
386
|
+
<button className={buttonStyles({ intent, size, className })} {...props} />
|
|
387
|
+
);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Pattern 2: CSS Modules with TypeScript
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// Button.module.css
|
|
394
|
+
.button {
|
|
395
|
+
border-radius: 0.25rem;
|
|
396
|
+
font-weight: 600;
|
|
397
|
+
transition: background-color 0.2s;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.primary {
|
|
401
|
+
composes: button;
|
|
402
|
+
background: var(--color-primary);
|
|
403
|
+
color: white;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.secondary {
|
|
407
|
+
composes: button;
|
|
408
|
+
background: var(--color-gray-200);
|
|
409
|
+
color: var(--color-gray-900);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.small { padding: 0.375rem 0.75rem; }
|
|
413
|
+
.medium { padding: 0.5rem 1rem; }
|
|
414
|
+
.large { padding: 0.75rem 1.5rem; }
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
// Button.tsx
|
|
419
|
+
import styles from './Button.module.css';
|
|
420
|
+
|
|
421
|
+
export const Button = ({ variant = 'primary', size = 'medium', ...props }) => (
|
|
422
|
+
<button className={`${styles[variant]} ${styles[size]}`} {...props} />
|
|
423
|
+
);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Pattern 3: Styled Components with Props
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
import styled from 'styled-components';
|
|
430
|
+
|
|
431
|
+
const Button = styled.button<{ $variant?: 'primary' | 'secondary'; $size?: 'sm' | 'md' | 'lg' }>`
|
|
432
|
+
border-radius: 0.25rem;
|
|
433
|
+
font-weight: 600;
|
|
434
|
+
transition: background-color 0.2s;
|
|
435
|
+
|
|
436
|
+
/* Variant styles */
|
|
437
|
+
background: ${p => p.$variant === 'primary' ? p.theme.colors.primary : p.theme.colors.gray[200]};
|
|
438
|
+
color: ${p => p.$variant === 'primary' ? 'white' : p.theme.colors.gray[900]};
|
|
439
|
+
|
|
440
|
+
/* Size styles */
|
|
441
|
+
padding: ${p => {
|
|
442
|
+
if (p.$size === 'sm') return '0.375rem 0.75rem';
|
|
443
|
+
if (p.$size === 'lg') return '0.75rem 1.5rem';
|
|
444
|
+
return '0.5rem 1rem';
|
|
445
|
+
}};
|
|
446
|
+
|
|
447
|
+
&:hover {
|
|
448
|
+
opacity: 0.9;
|
|
449
|
+
}
|
|
450
|
+
`;
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## ⚡ Performance Optimization
|
|
456
|
+
|
|
457
|
+
### 1. Critical CSS
|
|
458
|
+
|
|
459
|
+
Extract and inline critical CSS for above-the-fold content.
|
|
460
|
+
|
|
461
|
+
```html
|
|
462
|
+
<!-- index.html -->
|
|
463
|
+
<head>
|
|
464
|
+
<style>
|
|
465
|
+
/* Critical CSS inlined */
|
|
466
|
+
.header { /* ... */ }
|
|
467
|
+
.hero { /* ... */ }
|
|
468
|
+
</style>
|
|
469
|
+
|
|
470
|
+
<!-- Non-critical CSS loaded async -->
|
|
471
|
+
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
472
|
+
</head>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### 2. CSS Purging (Tailwind)
|
|
476
|
+
|
|
477
|
+
Remove unused CSS in production.
|
|
478
|
+
|
|
479
|
+
```javascript
|
|
480
|
+
// tailwind.config.js
|
|
481
|
+
export default {
|
|
482
|
+
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
|
483
|
+
// Tailwind automatically purges unused classes
|
|
484
|
+
};
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Result:** 3MB → 10KB CSS bundle
|
|
488
|
+
|
|
489
|
+
### 3. CSS-in-JS Optimization
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// ❌ Bad - Creates new styled component on every render
|
|
493
|
+
const Button = () => {
|
|
494
|
+
const StyledButton = styled.button`
|
|
495
|
+
background: blue;
|
|
496
|
+
`;
|
|
497
|
+
return <StyledButton>Click</StyledButton>;
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// ✅ Good - Defined outside component
|
|
501
|
+
const StyledButton = styled.button`
|
|
502
|
+
background: blue;
|
|
503
|
+
`;
|
|
504
|
+
|
|
505
|
+
const Button = () => <StyledButton>Click</StyledButton>;
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### 4. Avoid Layout Thrashing
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// ❌ Bad - Causes layout recalculation
|
|
512
|
+
elements.forEach(el => {
|
|
513
|
+
const height = el.offsetHeight; // Read
|
|
514
|
+
el.style.height = height + 10 + 'px'; // Write
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// ✅ Good - Batch reads, then writes
|
|
518
|
+
const heights = elements.map(el => el.offsetHeight); // Read all
|
|
519
|
+
elements.forEach((el, i) => {
|
|
520
|
+
el.style.height = heights[i] + 10 + 'px'; // Write all
|
|
521
|
+
});
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## ♿ Accessibility in Styling
|
|
527
|
+
|
|
528
|
+
### 1. Focus Indicators
|
|
529
|
+
|
|
530
|
+
```css
|
|
531
|
+
/* ❌ Bad - Removes focus indicator */
|
|
532
|
+
button:focus {
|
|
533
|
+
outline: none;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* ✅ Good - Custom accessible focus */
|
|
537
|
+
button:focus-visible {
|
|
538
|
+
outline: 2px solid var(--color-primary);
|
|
539
|
+
outline-offset: 2px;
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 2. Color Contrast (WCAG {{A11Y_COMPLIANCE}})
|
|
544
|
+
|
|
545
|
+
**Minimum ratios:**
|
|
546
|
+
- Normal text: 4.5:1 (AA), 7:1 (AAA)
|
|
547
|
+
- Large text (18pt+): 3:1 (AA), 4.5:1 (AAA)
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
// Validate contrast ratios
|
|
551
|
+
import { contrast } from 'wcag-contrast';
|
|
552
|
+
|
|
553
|
+
const textColor = '#757575';
|
|
554
|
+
const bgColor = '#ffffff';
|
|
555
|
+
|
|
556
|
+
const ratio = contrast(textColor, bgColor);
|
|
557
|
+
// 4.6:1 - Passes WCAG AA for normal text
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### 3. Reduced Motion
|
|
561
|
+
|
|
562
|
+
```css
|
|
563
|
+
/* Respect user's motion preferences */
|
|
564
|
+
@media (prefers-reduced-motion: reduce) {
|
|
565
|
+
* {
|
|
566
|
+
animation-duration: 0.01ms !important;
|
|
567
|
+
animation-iteration-count: 1 !important;
|
|
568
|
+
transition-duration: 0.01ms !important;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## 🎯 Common Patterns
|
|
576
|
+
|
|
577
|
+
### Layout Patterns
|
|
578
|
+
|
|
579
|
+
#### Centered Container
|
|
580
|
+
|
|
581
|
+
```css
|
|
582
|
+
.container {
|
|
583
|
+
max-width: 1200px;
|
|
584
|
+
margin: 0 auto;
|
|
585
|
+
padding: 0 1rem;
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
#### Flexbox Patterns
|
|
590
|
+
|
|
591
|
+
```css
|
|
592
|
+
/* Center content */
|
|
593
|
+
.flex-center {
|
|
594
|
+
display: flex;
|
|
595
|
+
justify-content: center;
|
|
596
|
+
align-items: center;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/* Space between items */
|
|
600
|
+
.flex-between {
|
|
601
|
+
display: flex;
|
|
602
|
+
justify-content: space-between;
|
|
603
|
+
align-items: center;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/* Responsive stack */
|
|
607
|
+
.flex-stack {
|
|
608
|
+
display: flex;
|
|
609
|
+
flex-direction: column;
|
|
610
|
+
gap: 1rem;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
@media (min-width: 768px) {
|
|
614
|
+
.flex-stack {
|
|
615
|
+
flex-direction: row;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### Grid Patterns
|
|
621
|
+
|
|
622
|
+
```css
|
|
623
|
+
/* Auto-fit responsive grid */
|
|
624
|
+
.grid-auto {
|
|
625
|
+
display: grid;
|
|
626
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
627
|
+
gap: 1rem;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/* 12-column grid */
|
|
631
|
+
.grid-12 {
|
|
632
|
+
display: grid;
|
|
633
|
+
grid-template-columns: repeat(12, 1fr);
|
|
634
|
+
gap: 1rem;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.span-6 { grid-column: span 6; }
|
|
638
|
+
.span-4 { grid-column: span 4; }
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
### Animation Patterns
|
|
642
|
+
|
|
643
|
+
```css
|
|
644
|
+
/* Smooth transitions */
|
|
645
|
+
.transition-all {
|
|
646
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/* Fade in animation */
|
|
650
|
+
@keyframes fadeIn {
|
|
651
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
652
|
+
to { opacity: 1; transform: translateY(0); }
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.fade-in {
|
|
656
|
+
animation: fadeIn 0.3s ease-out;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/* Loading spinner */
|
|
660
|
+
@keyframes spin {
|
|
661
|
+
to { transform: rotate(360deg); }
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.spinner {
|
|
665
|
+
animation: spin 1s linear infinite;
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
## ⚠️ Common Pitfalls
|
|
672
|
+
|
|
673
|
+
### 1. Over-Specificity
|
|
674
|
+
|
|
675
|
+
```css
|
|
676
|
+
/* ❌ Bad - Too specific, hard to override */
|
|
677
|
+
div.container > ul.list > li.item > a.link {
|
|
678
|
+
color: blue;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/* ✅ Good - Use classes */
|
|
682
|
+
.nav-link {
|
|
683
|
+
color: blue;
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### 2. Magic Numbers
|
|
688
|
+
|
|
689
|
+
```css
|
|
690
|
+
/* ❌ Bad - Unexplained values */
|
|
691
|
+
.box {
|
|
692
|
+
margin-top: 23px;
|
|
693
|
+
padding: 17px;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/* ✅ Good - Use design tokens */
|
|
697
|
+
.box {
|
|
698
|
+
margin-top: var(--spacing-6);
|
|
699
|
+
padding: var(--spacing-4);
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### 3. Inconsistent Units
|
|
704
|
+
|
|
705
|
+
```css
|
|
706
|
+
/* ❌ Bad - Mixing units */
|
|
707
|
+
.element {
|
|
708
|
+
padding: 10px;
|
|
709
|
+
margin: 0.5rem;
|
|
710
|
+
font-size: 14pt;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/* ✅ Good - Consistent rem/em */
|
|
714
|
+
.element {
|
|
715
|
+
padding: 0.625rem;
|
|
716
|
+
margin: 0.5rem;
|
|
717
|
+
font-size: 0.875rem;
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### 4. Inline Styles
|
|
722
|
+
|
|
723
|
+
```jsx
|
|
724
|
+
{/* ❌ Bad - Hard to maintain, no reusability */}
|
|
725
|
+
<div style={{ padding: '10px', background: 'blue', color: 'white' }}>
|
|
726
|
+
Content
|
|
727
|
+
</div>
|
|
728
|
+
|
|
729
|
+
{/* ✅ Good - Use classes or styled components */}
|
|
730
|
+
<div className="card-primary">
|
|
731
|
+
Content
|
|
732
|
+
</div>
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## 🧪 Testing Styles
|
|
738
|
+
|
|
739
|
+
### Visual Regression Testing
|
|
740
|
+
|
|
741
|
+
```typescript
|
|
742
|
+
// Using Playwright + Percy
|
|
743
|
+
import { test } from '@playwright/test';
|
|
744
|
+
import percySnapshot from '@percy/playwright';
|
|
745
|
+
|
|
746
|
+
test('button variants', async ({ page }) => {
|
|
747
|
+
await page.goto('/storybook/button');
|
|
748
|
+
await percySnapshot(page, 'Button - All Variants');
|
|
749
|
+
});
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### Accessibility Testing
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
756
|
+
|
|
757
|
+
expect.extend(toHaveNoViolations);
|
|
758
|
+
|
|
759
|
+
test('button has no a11y violations', async () => {
|
|
760
|
+
const { container } = render(<Button>Click me</Button>);
|
|
761
|
+
const results = await axe(container);
|
|
762
|
+
expect(results).toHaveNoViolations();
|
|
763
|
+
});
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
## 🔗 Related Documents
|
|
769
|
+
|
|
770
|
+
- [Component Architecture](components.md) - Component structure
|
|
771
|
+
- [AI Instructions](../ai-instructions.md) - Styling rules
|
|
772
|
+
- [Accessibility Spec](../specs/accessibility.md) - A11y requirements
|
|
773
|
+
- [Testing Strategy](testing.md) - Visual regression tests
|
|
774
|
+
|
|
775
|
+
---
|
|
776
|
+
|
|
777
|
+
**Last Updated:** {{GENERATION_DATE}}
|
|
778
|
+
|
|
779
|
+
**Styling Approach:** {{STYLING_APPROACH}}
|