@mikulgohil/ai-kit 1.0.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 +73 -0
- package/commands/accessibility-audit.md +143 -0
- package/commands/api-route.md +203 -0
- package/commands/commit-msg.md +127 -0
- package/commands/dep-check.md +148 -0
- package/commands/design-tokens.md +146 -0
- package/commands/document.md +175 -0
- package/commands/env-setup.md +165 -0
- package/commands/error-boundary.md +254 -0
- package/commands/extract-hook.md +237 -0
- package/commands/figma-to-code.md +152 -0
- package/commands/fix-bug.md +112 -0
- package/commands/migrate.md +174 -0
- package/commands/new-component.md +121 -0
- package/commands/new-page.md +113 -0
- package/commands/optimize.md +120 -0
- package/commands/pre-pr.md +159 -0
- package/commands/prompt-help.md +175 -0
- package/commands/refactor.md +219 -0
- package/commands/responsive-check.md +164 -0
- package/commands/review.md +120 -0
- package/commands/security-check.md +175 -0
- package/commands/sitecore-debug.md +216 -0
- package/commands/test.md +154 -0
- package/commands/token-tips.md +72 -0
- package/commands/type-fix.md +224 -0
- package/commands/understand.md +84 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1425 -0
- package/dist/index.js.map +1 -0
- package/docs-scaffolds/component-doc.md +35 -0
- package/docs-scaffolds/decisions-log.md +15 -0
- package/docs-scaffolds/mistakes-log.md +15 -0
- package/docs-scaffolds/time-log.md +14 -0
- package/guides/figma-workflow.md +135 -0
- package/guides/getting-started.md +61 -0
- package/guides/prompt-playbook.md +64 -0
- package/guides/token-saving-tips.md +50 -0
- package/guides/when-to-use-ai.md +44 -0
- package/package.json +58 -0
- package/templates/claude-md/base.md +173 -0
- package/templates/claude-md/figma.md +62 -0
- package/templates/claude-md/monorepo.md +17 -0
- package/templates/claude-md/nextjs-app-router.md +29 -0
- package/templates/claude-md/nextjs-pages-router.md +28 -0
- package/templates/claude-md/sitecore-xmc.md +46 -0
- package/templates/claude-md/tailwind.md +18 -0
- package/templates/claude-md/typescript.md +19 -0
- package/templates/cursorrules/base.md +84 -0
- package/templates/cursorrules/figma.md +32 -0
- package/templates/cursorrules/monorepo.md +7 -0
- package/templates/cursorrules/nextjs-app-router.md +8 -0
- package/templates/cursorrules/nextjs-pages-router.md +7 -0
- package/templates/cursorrules/sitecore-xmc.md +9 -0
- package/templates/cursorrules/tailwind.md +8 -0
- package/templates/cursorrules/typescript.md +8 -0
- package/templates/header.md +4 -0
- package/templates/token-dashboard.html +732 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# Error Boundary Generator
|
|
2
|
+
|
|
3
|
+
> **Role**: You are a senior React reliability engineer. Your core principle is: "Every state must be visible." You ensure applications never show blank white screens to users, and every failure mode has a graceful, accessible fallback.
|
|
4
|
+
> **Goal**: Analyze the target file(s), identify every failure mode, and generate comprehensive error handling — error boundaries, loading states, fallback UI, and typed error classes.
|
|
5
|
+
|
|
6
|
+
## Mandatory Steps
|
|
7
|
+
|
|
8
|
+
You MUST follow these steps in order. Do not skip any step.
|
|
9
|
+
|
|
10
|
+
1. **Read the target file(s)** — Use the Read tool to open and examine every file specified. Understand all the ways the code can fail.
|
|
11
|
+
2. **Identify failure modes** — List every operation that can fail: API calls, data fetching, form submissions, null/undefined access, third-party services, network timeouts. For each, note what the user currently sees when it fails.
|
|
12
|
+
3. **Generate route-level error handling** — If the target is a route directory, generate `error.tsx` and `loading.tsx` files.
|
|
13
|
+
4. **Generate component-level error handling** — For data-fetching components, add try-catch with user-friendly fallback UI for error, empty, and not-found states.
|
|
14
|
+
5. **Generate typed error classes** — If the project doesn't have them, create `ApiError`, `ValidationError`, and `NotFoundError` classes with proper typing.
|
|
15
|
+
6. **Generate form error states** — For any forms, ensure all states are handled: idle, loading, success, error — with accessible feedback.
|
|
16
|
+
7. **Verify the rule** — Confirm that every state has a visible UI. No blank screens anywhere.
|
|
17
|
+
|
|
18
|
+
## What Gets Generated — Reference Examples
|
|
19
|
+
|
|
20
|
+
### 1. Route-Level Error Boundary (App Router)
|
|
21
|
+
|
|
22
|
+
**error.tsx:**
|
|
23
|
+
```tsx
|
|
24
|
+
'use client';
|
|
25
|
+
|
|
26
|
+
interface ErrorProps {
|
|
27
|
+
error: Error & { digest?: string };
|
|
28
|
+
reset: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function Error({ error, reset }: ErrorProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div role="alert" className="flex flex-col items-center justify-center min-h-[400px] gap-4">
|
|
34
|
+
<h2 className="text-xl font-semibold">Something went wrong</h2>
|
|
35
|
+
<p className="text-gray-600 max-w-md text-center">
|
|
36
|
+
We encountered an unexpected error. Please try again.
|
|
37
|
+
</p>
|
|
38
|
+
<button
|
|
39
|
+
onClick={reset}
|
|
40
|
+
className="px-4 py-2 bg-primary text-white rounded hover:bg-primary/90"
|
|
41
|
+
>
|
|
42
|
+
Try again
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**loading.tsx:**
|
|
50
|
+
```tsx
|
|
51
|
+
export default function Loading() {
|
|
52
|
+
return (
|
|
53
|
+
<div className="flex items-center justify-center min-h-[400px]" role="status">
|
|
54
|
+
<div className="animate-spin h-8 w-8 border-4 border-gray-200 border-t-primary rounded-full" />
|
|
55
|
+
<span className="sr-only">Loading...</span>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Component-Level Error Handling
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
interface Props {
|
|
65
|
+
productId: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function ProductDetail({ productId }: Props) {
|
|
69
|
+
try {
|
|
70
|
+
const product = await fetchProduct(productId);
|
|
71
|
+
|
|
72
|
+
if (!product) {
|
|
73
|
+
return (
|
|
74
|
+
<div className="text-center py-8">
|
|
75
|
+
<h3 className="text-lg font-medium">Product not found</h3>
|
|
76
|
+
<p className="text-gray-500">The product you're looking for doesn't exist or has been removed.</p>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return <ProductCard product={product} />;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(`Failed to fetch product ${productId}:`, error);
|
|
84
|
+
return (
|
|
85
|
+
<div role="alert" className="bg-red-50 border border-red-200 rounded p-4">
|
|
86
|
+
<p className="text-red-800">Unable to load product details. Please try refreshing the page.</p>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Typed Error Handling for API Calls
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// lib/errors.ts
|
|
97
|
+
export class ApiError extends Error {
|
|
98
|
+
constructor(
|
|
99
|
+
message: string,
|
|
100
|
+
public statusCode: number,
|
|
101
|
+
public code: string,
|
|
102
|
+
) {
|
|
103
|
+
super(message);
|
|
104
|
+
this.name = 'ApiError';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class ValidationError extends ApiError {
|
|
109
|
+
constructor(
|
|
110
|
+
message: string,
|
|
111
|
+
public fields: Record<string, string>,
|
|
112
|
+
) {
|
|
113
|
+
super(message, 400, 'VALIDATION_ERROR');
|
|
114
|
+
this.name = 'ValidationError';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export class NotFoundError extends ApiError {
|
|
119
|
+
constructor(resource: string) {
|
|
120
|
+
super(`${resource} not found`, 404, 'NOT_FOUND');
|
|
121
|
+
this.name = 'NotFoundError';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Usage in API calls
|
|
126
|
+
export async function fetchWithError<T>(url: string): Promise<T> {
|
|
127
|
+
const response = await fetch(url);
|
|
128
|
+
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
if (response.status === 404) throw new NotFoundError(url);
|
|
131
|
+
if (response.status === 400) {
|
|
132
|
+
const body = await response.json();
|
|
133
|
+
throw new ValidationError('Validation failed', body.errors);
|
|
134
|
+
}
|
|
135
|
+
throw new ApiError('Request failed', response.status, 'UNKNOWN');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return response.json() as Promise<T>;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 4. Form Error States
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
'use client';
|
|
146
|
+
|
|
147
|
+
function ContactForm() {
|
|
148
|
+
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
149
|
+
const [errorMessage, setErrorMessage] = useState('');
|
|
150
|
+
|
|
151
|
+
async function handleSubmit(formData: FormData) {
|
|
152
|
+
setStatus('loading');
|
|
153
|
+
try {
|
|
154
|
+
await submitContactForm(formData);
|
|
155
|
+
setStatus('success');
|
|
156
|
+
} catch (error) {
|
|
157
|
+
setStatus('error');
|
|
158
|
+
setErrorMessage(
|
|
159
|
+
error instanceof ValidationError
|
|
160
|
+
? 'Please check the form fields and try again.'
|
|
161
|
+
: 'Something went wrong. Please try again later.'
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (status === 'success') {
|
|
167
|
+
return <p className="text-green-600">Thanks! We'll be in touch.</p>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<form action={handleSubmit}>
|
|
172
|
+
{status === 'error' && (
|
|
173
|
+
<div role="alert" className="bg-red-50 border border-red-200 rounded p-3 mb-4">
|
|
174
|
+
<p className="text-red-800">{errorMessage}</p>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
{/* form fields */}
|
|
178
|
+
<button type="submit" disabled={status === 'loading'}>
|
|
179
|
+
{status === 'loading' ? 'Sending...' : 'Send Message'}
|
|
180
|
+
</button>
|
|
181
|
+
</form>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## The Rule: Every State Must Be Visible
|
|
187
|
+
|
|
188
|
+
| State | What the user sees | What to generate |
|
|
189
|
+
|-------|-------------------|-----------------|
|
|
190
|
+
| Loading | Spinner or skeleton | `loading.tsx` or inline skeleton |
|
|
191
|
+
| Success | Data or confirmation | Main component render |
|
|
192
|
+
| Empty | Helpful message | Empty state component |
|
|
193
|
+
| Error | Friendly error + retry | `error.tsx` or inline error |
|
|
194
|
+
| Not Found | 404 message | `not-found.tsx` or conditional |
|
|
195
|
+
|
|
196
|
+
**Never show a blank screen.** If something can fail, it must have a visible failure state.
|
|
197
|
+
|
|
198
|
+
## Output Format
|
|
199
|
+
|
|
200
|
+
You MUST structure your response exactly as follows:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
## Failure Mode Analysis
|
|
204
|
+
|
|
205
|
+
| # | What Can Fail | Current Behavior | Needed |
|
|
206
|
+
|---|---------------|-----------------|--------|
|
|
207
|
+
| 1 | [operation] | [what user sees now — e.g., blank screen] | [what to generate] |
|
|
208
|
+
|
|
209
|
+
## Generated Files
|
|
210
|
+
|
|
211
|
+
### 1. [filename]
|
|
212
|
+
**Path:** `src/app/[route]/error.tsx`
|
|
213
|
+
```tsx
|
|
214
|
+
// full file content
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 2. [filename]
|
|
218
|
+
**Path:** `src/app/[route]/loading.tsx`
|
|
219
|
+
```tsx
|
|
220
|
+
// full file content
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 3. [filename] (if needed)
|
|
224
|
+
...
|
|
225
|
+
|
|
226
|
+
## State Coverage Verification
|
|
227
|
+
|
|
228
|
+
| State | Covered? | Where |
|
|
229
|
+
|-------|----------|-------|
|
|
230
|
+
| Loading | Yes | `loading.tsx` line X / component line Y |
|
|
231
|
+
| Success | Yes | component line Z |
|
|
232
|
+
| Empty | Yes | component line W |
|
|
233
|
+
| Error | Yes | `error.tsx` / component line V |
|
|
234
|
+
| Not Found | Yes | component line U |
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Self-Check
|
|
238
|
+
|
|
239
|
+
Before responding, verify:
|
|
240
|
+
- [ ] You read the target file(s) before analyzing
|
|
241
|
+
- [ ] You identified every failure mode in the code
|
|
242
|
+
- [ ] Every state (loading, success, empty, error, not-found) has visible UI
|
|
243
|
+
- [ ] Error messages are user-friendly, not technical
|
|
244
|
+
- [ ] All error UI includes `role="alert"` for screen readers
|
|
245
|
+
- [ ] You provided complete, copy-pasteable file contents
|
|
246
|
+
|
|
247
|
+
## Constraints
|
|
248
|
+
|
|
249
|
+
- Do NOT leave any state without visible UI — the rule is "every state must be visible."
|
|
250
|
+
- Do NOT show technical error details to users (stack traces, error codes) — log them server-side.
|
|
251
|
+
- Do NOT generate error handling that swallows errors silently.
|
|
252
|
+
- Do NOT give generic advice. Every generated file must be specific to the target route/component.
|
|
253
|
+
|
|
254
|
+
Target: $ARGUMENTS
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Extract Hook
|
|
2
|
+
|
|
3
|
+
> **Role**: You are a senior React architect. You specialize in separating concerns — logic goes in hooks, rendering goes in components. You create hooks that are typed, testable, and reusable.
|
|
4
|
+
> **Goal**: Read the target component, identify all extractable logic (state, effects, derived values), create a properly typed custom hook, update the component to use it, and generate a test file for the hook.
|
|
5
|
+
|
|
6
|
+
## Mandatory Steps
|
|
7
|
+
|
|
8
|
+
You MUST follow these steps in order. Do not skip any step.
|
|
9
|
+
|
|
10
|
+
1. **Read the target component** — Use the Read tool to open and examine the file. Understand all the state, effects, callbacks, and derived values it contains.
|
|
11
|
+
2. **Identify extractable logic** — Find all of the following in the component:
|
|
12
|
+
- `useState` calls (3+ is a strong signal to extract)
|
|
13
|
+
- `useEffect` with complex logic (data fetching, subscriptions, timers)
|
|
14
|
+
- `useMemo` / `useCallback` with non-trivial computations
|
|
15
|
+
- Derived state (values computed from other state)
|
|
16
|
+
- Logic that is duplicated in other components
|
|
17
|
+
3. **Design the hook interface** — Define the typed `Options` (input) and `Return` (output) interfaces. Return an object (not an array) — objects are easier to destructure selectively.
|
|
18
|
+
4. **Create the hook file** — Move all identified logic into a `useXxx` function with the typed interface. Place it in `hooks/` directory (or colocated if single-use).
|
|
19
|
+
5. **Update the component** — Replace the extracted logic with a single hook call. The component should now only handle rendering.
|
|
20
|
+
6. **Generate a test file** — Create a test file for the hook using `@testing-library/react-hooks` or `renderHook` patterns.
|
|
21
|
+
|
|
22
|
+
## When to Extract a Hook
|
|
23
|
+
|
|
24
|
+
Extract when you see:
|
|
25
|
+
- **3+ `useState` calls** in one component
|
|
26
|
+
- **`useEffect` with complex logic** (data fetching, subscriptions, timers)
|
|
27
|
+
- **Same state pattern** in 2+ components (duplicate logic)
|
|
28
|
+
- **Component is hard to test** because logic and UI are tangled
|
|
29
|
+
|
|
30
|
+
## Example: Full Extraction
|
|
31
|
+
|
|
32
|
+
### Before — Everything in the component
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// ProductList.tsx — 150 lines, mixing logic and UI
|
|
36
|
+
'use client';
|
|
37
|
+
|
|
38
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
39
|
+
|
|
40
|
+
export function ProductList({ categoryId }: { categoryId: string }) {
|
|
41
|
+
const [products, setProducts] = useState<Product[]>([]);
|
|
42
|
+
const [loading, setLoading] = useState(true);
|
|
43
|
+
const [error, setError] = useState<string | null>(null);
|
|
44
|
+
const [search, setSearch] = useState('');
|
|
45
|
+
const [sortBy, setSortBy] = useState<'name' | 'price'>('name');
|
|
46
|
+
const [page, setPage] = useState(1);
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setLoading(true);
|
|
50
|
+
setError(null);
|
|
51
|
+
fetch(`/api/products?category=${categoryId}&page=${page}`)
|
|
52
|
+
.then(res => {
|
|
53
|
+
if (!res.ok) throw new Error('Failed to fetch');
|
|
54
|
+
return res.json();
|
|
55
|
+
})
|
|
56
|
+
.then(data => {
|
|
57
|
+
setProducts(data.products);
|
|
58
|
+
setLoading(false);
|
|
59
|
+
})
|
|
60
|
+
.catch(err => {
|
|
61
|
+
setError(err.message);
|
|
62
|
+
setLoading(false);
|
|
63
|
+
});
|
|
64
|
+
}, [categoryId, page]);
|
|
65
|
+
|
|
66
|
+
const filtered = useMemo(() =>
|
|
67
|
+
products
|
|
68
|
+
.filter(p => p.name.toLowerCase().includes(search.toLowerCase()))
|
|
69
|
+
.sort((a, b) => sortBy === 'name'
|
|
70
|
+
? a.name.localeCompare(b.name)
|
|
71
|
+
: a.price - b.price
|
|
72
|
+
),
|
|
73
|
+
[products, search, sortBy]
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// ... 80 lines of JSX rendering
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### After — Logic extracted into a hook
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// hooks/useProducts.ts
|
|
84
|
+
'use client';
|
|
85
|
+
|
|
86
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
87
|
+
|
|
88
|
+
interface UseProductsOptions {
|
|
89
|
+
categoryId: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface UseProductsReturn {
|
|
93
|
+
products: Product[];
|
|
94
|
+
filtered: Product[];
|
|
95
|
+
loading: boolean;
|
|
96
|
+
error: string | null;
|
|
97
|
+
search: string;
|
|
98
|
+
setSearch: (value: string) => void;
|
|
99
|
+
sortBy: 'name' | 'price';
|
|
100
|
+
setSortBy: (value: 'name' | 'price') => void;
|
|
101
|
+
page: number;
|
|
102
|
+
setPage: (value: number) => void;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function useProducts({ categoryId }: UseProductsOptions): UseProductsReturn {
|
|
106
|
+
const [products, setProducts] = useState<Product[]>([]);
|
|
107
|
+
const [loading, setLoading] = useState(true);
|
|
108
|
+
const [error, setError] = useState<string | null>(null);
|
|
109
|
+
const [search, setSearch] = useState('');
|
|
110
|
+
const [sortBy, setSortBy] = useState<'name' | 'price'>('name');
|
|
111
|
+
const [page, setPage] = useState(1);
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
setLoading(true);
|
|
115
|
+
setError(null);
|
|
116
|
+
fetch(`/api/products?category=${categoryId}&page=${page}`)
|
|
117
|
+
.then(res => {
|
|
118
|
+
if (!res.ok) throw new Error('Failed to fetch');
|
|
119
|
+
return res.json();
|
|
120
|
+
})
|
|
121
|
+
.then(data => {
|
|
122
|
+
setProducts(data.products);
|
|
123
|
+
setLoading(false);
|
|
124
|
+
})
|
|
125
|
+
.catch(err => {
|
|
126
|
+
setError(err.message);
|
|
127
|
+
setLoading(false);
|
|
128
|
+
});
|
|
129
|
+
}, [categoryId, page]);
|
|
130
|
+
|
|
131
|
+
const filtered = useMemo(() =>
|
|
132
|
+
products
|
|
133
|
+
.filter(p => p.name.toLowerCase().includes(search.toLowerCase()))
|
|
134
|
+
.sort((a, b) => sortBy === 'name'
|
|
135
|
+
? a.name.localeCompare(b.name)
|
|
136
|
+
: a.price - b.price
|
|
137
|
+
),
|
|
138
|
+
[products, search, sortBy]
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return { products, filtered, loading, error, search, setSearch, sortBy, setSortBy, page, setPage };
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// ProductList.tsx — Now just UI
|
|
147
|
+
'use client';
|
|
148
|
+
|
|
149
|
+
import { useProducts } from '@/hooks/useProducts';
|
|
150
|
+
|
|
151
|
+
export function ProductList({ categoryId }: { categoryId: string }) {
|
|
152
|
+
const { filtered, loading, error, search, setSearch, sortBy, setSortBy, page, setPage } =
|
|
153
|
+
useProducts({ categoryId });
|
|
154
|
+
|
|
155
|
+
if (loading) return <Spinner />;
|
|
156
|
+
if (error) return <ErrorMessage message={error} />;
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<div>
|
|
160
|
+
<SearchBar value={search} onChange={setSearch} />
|
|
161
|
+
<SortSelector value={sortBy} onChange={setSortBy} />
|
|
162
|
+
<ProductGrid products={filtered} />
|
|
163
|
+
<Pagination page={page} onPageChange={setPage} />
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Output Format
|
|
170
|
+
|
|
171
|
+
You MUST structure your response exactly as follows:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
## Extraction Analysis
|
|
175
|
+
|
|
176
|
+
### Logic Found in Component
|
|
177
|
+
| # | Type | Lines | Extractable? | Why |
|
|
178
|
+
|---|------|-------|-------------|-----|
|
|
179
|
+
| 1 | useState | L5-L10 | Yes | 6 state variables managing product data |
|
|
180
|
+
| 2 | useEffect | L12-L25 | Yes | Data fetching logic |
|
|
181
|
+
| 3 | useMemo | L27-L35 | Yes | Derived filtered/sorted list |
|
|
182
|
+
|
|
183
|
+
### Hook Design
|
|
184
|
+
- **Name:** `useProducts`
|
|
185
|
+
- **File:** `hooks/useProducts.ts`
|
|
186
|
+
- **Input:** `{ categoryId: string }`
|
|
187
|
+
- **Output:** `{ products, filtered, loading, error, search, setSearch, sortBy, setSortBy, page, setPage }`
|
|
188
|
+
|
|
189
|
+
## Generated Files
|
|
190
|
+
|
|
191
|
+
### 1. Hook File
|
|
192
|
+
**Path:** `hooks/useProducts.ts`
|
|
193
|
+
```tsx
|
|
194
|
+
// complete hook code
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 2. Updated Component
|
|
198
|
+
**Path:** `src/components/ProductList.tsx`
|
|
199
|
+
```tsx
|
|
200
|
+
// complete updated component
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 3. Hook Test
|
|
204
|
+
**Path:** `hooks/__tests__/useProducts.test.ts`
|
|
205
|
+
```tsx
|
|
206
|
+
// test file
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Behavior Verification
|
|
210
|
+
- [ ] All state variables accounted for
|
|
211
|
+
- [ ] All effects moved to hook
|
|
212
|
+
- [ ] All derived values moved to hook
|
|
213
|
+
- [ ] Component only handles rendering
|
|
214
|
+
- [ ] Hook returns typed object (not array)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Self-Check
|
|
218
|
+
|
|
219
|
+
Before responding, verify:
|
|
220
|
+
- [ ] You read the target file before analyzing
|
|
221
|
+
- [ ] You identified ALL useState, useEffect, useMemo, and useCallback in the component
|
|
222
|
+
- [ ] The hook has typed `Options` and `Return` interfaces
|
|
223
|
+
- [ ] The hook returns an object, not an array
|
|
224
|
+
- [ ] The updated component only handles rendering
|
|
225
|
+
- [ ] The test file covers the hook's key behaviors
|
|
226
|
+
- [ ] Behavior is identical before and after extraction
|
|
227
|
+
|
|
228
|
+
## Constraints
|
|
229
|
+
|
|
230
|
+
- Hook name MUST start with `use` (React convention).
|
|
231
|
+
- Hook MUST return a typed object (not an array — objects are easier to destructure selectively).
|
|
232
|
+
- Hook file goes in `hooks/` directory (or colocated if single-use).
|
|
233
|
+
- Component MUST only handle rendering after extraction.
|
|
234
|
+
- Behavior MUST stay identical — extract, don't enhance.
|
|
235
|
+
- Do NOT give generic advice. Every suggestion must reference specific code in the target component.
|
|
236
|
+
|
|
237
|
+
Target: $ARGUMENTS
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Figma-to-Code
|
|
2
|
+
|
|
3
|
+
> **Role**: You are a senior UI engineer with deep Figma expertise and production React/Next.js experience. You bridge design and code with pixel-perfect precision.
|
|
4
|
+
> **Goal**: Convert a Figma design into production-ready code that uses the project's existing design tokens, components, and patterns.
|
|
5
|
+
|
|
6
|
+
## Mandatory Steps
|
|
7
|
+
|
|
8
|
+
You MUST follow these steps in order. Do not skip any step.
|
|
9
|
+
|
|
10
|
+
1. **Understand the Task** — Ask the developer what they are implementing:
|
|
11
|
+
- A new component (e.g., Card, Hero, Modal)
|
|
12
|
+
- A full page or section
|
|
13
|
+
- Updating an existing component to match a new design
|
|
14
|
+
- Extracting design tokens from Figma
|
|
15
|
+
|
|
16
|
+
2. **Get the Figma Source** — Ask:
|
|
17
|
+
- Paste the Figma link or node URL
|
|
18
|
+
- Which specific frame or section to implement (if full page)
|
|
19
|
+
- Are there multiple variants (hover, active, disabled) in the design?
|
|
20
|
+
- Is there a mobile/tablet version in Figma?
|
|
21
|
+
|
|
22
|
+
3. **Check Figma MCP** — Determine if Figma MCP is configured:
|
|
23
|
+
- Look for MCP config in `.claude/settings.json`, `.mcp.json`, or VS Code settings
|
|
24
|
+
- If configured: use `get_design_context` and `get_screenshot` to extract design data
|
|
25
|
+
- If NOT configured: ask the developer to either:
|
|
26
|
+
a. Set up Figma MCP (see ai-kit/guides/figma-workflow.md)
|
|
27
|
+
b. Provide a screenshot and describe the design manually
|
|
28
|
+
|
|
29
|
+
4. **Extract Design Context** — Gather all design details:
|
|
30
|
+
- If Figma MCP is available: call `get_design_context` with the Figma node URL, call `get_screenshot` for visual reference. Note colors, spacing, typography, layout direction, component variants.
|
|
31
|
+
- If MCP is NOT available: ask the developer to describe layout, colors, spacing, typography, interactions. Ask for a screenshot if possible.
|
|
32
|
+
|
|
33
|
+
5. **Map to Project Tokens** — Before writing ANY code:
|
|
34
|
+
- Read the project's `tailwind.config.ts` or `globals.css` (`@theme` section)
|
|
35
|
+
- Map every Figma color to the nearest design token
|
|
36
|
+
- Map every spacing value to the nearest Tailwind scale value
|
|
37
|
+
- Map typography to the project's type scale
|
|
38
|
+
- If a value doesn't match any token, flag it and use the nearest one
|
|
39
|
+
- Ask: "Does this project have a design token file or theme config I should reference?"
|
|
40
|
+
|
|
41
|
+
6. **Check for Reusable Components** — Read `src/components/` to find existing components that match. Show the developer what you found:
|
|
42
|
+
> "I found these existing components that might work:
|
|
43
|
+
> - `Button` (src/components/Button.tsx) — has primary/secondary variants
|
|
44
|
+
> - `Card` (src/components/Card.tsx) — has image + text layout
|
|
45
|
+
> Should I reuse these or create new components?"
|
|
46
|
+
|
|
47
|
+
7. **Ask Implementation Details** — Based on the task type:
|
|
48
|
+
|
|
49
|
+
**For a New Component:**
|
|
50
|
+
- Component name?
|
|
51
|
+
- Where should it go? (suggest based on project structure)
|
|
52
|
+
- Does it need to be a Sitecore component with field helpers? (if XM Cloud project)
|
|
53
|
+
- What states does it have? (hover, active, disabled, loading, empty)
|
|
54
|
+
- Does it receive data through props or fetch its own?
|
|
55
|
+
- Should it match an existing component pattern in the project?
|
|
56
|
+
|
|
57
|
+
**For a Full Page:**
|
|
58
|
+
- Which route/URL for this page?
|
|
59
|
+
- Should I implement all sections or specific ones?
|
|
60
|
+
- Which sections are above the fold (priority)?
|
|
61
|
+
- Any sections that need data fetching?
|
|
62
|
+
|
|
63
|
+
**For Updating an Existing Component:**
|
|
64
|
+
- Which component file?
|
|
65
|
+
- What changed in the design? (colors, spacing, layout, new elements)
|
|
66
|
+
- Should I preserve the existing API (props) or is it OK to change?
|
|
67
|
+
|
|
68
|
+
8. **Generate Code** — Write production code following these rules:
|
|
69
|
+
- Use ONLY project design tokens — no hardcoded values
|
|
70
|
+
- Reuse existing components where identified
|
|
71
|
+
- Use semantic HTML elements
|
|
72
|
+
- Implement responsive with mobile-first approach
|
|
73
|
+
- Add all states from Figma (hover, focus, active, disabled)
|
|
74
|
+
- Follow the project's component patterns (check CLAUDE.md)
|
|
75
|
+
- Include TypeScript types for all props
|
|
76
|
+
|
|
77
|
+
9. **Verify Responsive** — After generating code, run through this checklist:
|
|
78
|
+
- [ ] Layout matches Figma (flex/grid direction, alignment)
|
|
79
|
+
- [ ] Spacing matches (padding, gap, margins)
|
|
80
|
+
- [ ] Colors use correct tokens
|
|
81
|
+
- [ ] Typography matches (size, weight, line-height)
|
|
82
|
+
- [ ] Responsive: mobile layout verified separately
|
|
83
|
+
- [ ] States implemented (hover, focus, active, disabled)
|
|
84
|
+
- [ ] Content container pattern correct (full-width bg, constrained content)
|
|
85
|
+
|
|
86
|
+
## What to Check / Generate
|
|
87
|
+
|
|
88
|
+
### Token Mapping Examples
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Figma Color → Token: #1A1A1A → text-neutral-900
|
|
92
|
+
Figma Spacing → Token: 24px → p-6 (or gap-6)
|
|
93
|
+
Figma Font → Token: Inter 24px Bold → text-h2 font-bold
|
|
94
|
+
Figma Radius → Token: 8px → rounded-card
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Code Generation Rules
|
|
98
|
+
|
|
99
|
+
- Use ONLY project design tokens — never hardcode `#hex` values or arbitrary `px` values
|
|
100
|
+
- Prefer Tailwind utility classes over inline styles
|
|
101
|
+
- Use `next/image` for all images with proper `sizes` prop
|
|
102
|
+
- Include ARIA labels for interactive elements
|
|
103
|
+
- Follow existing naming conventions in the codebase
|
|
104
|
+
|
|
105
|
+
## Output Format
|
|
106
|
+
|
|
107
|
+
You MUST structure your final response exactly as follows:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
## Figma-to-Code Summary
|
|
111
|
+
|
|
112
|
+
### Files Created/Modified
|
|
113
|
+
- [list all files with full paths]
|
|
114
|
+
|
|
115
|
+
### Design Tokens Used
|
|
116
|
+
- Colors: [list tokens mapped]
|
|
117
|
+
- Spacing: [list tokens]
|
|
118
|
+
- Typography: [list tokens]
|
|
119
|
+
|
|
120
|
+
### Components Reused
|
|
121
|
+
- [list existing components that were reused]
|
|
122
|
+
|
|
123
|
+
### Responsive Breakpoints
|
|
124
|
+
- Desktop (1440px): [verified/not verified]
|
|
125
|
+
- Tablet (768px): [verified/not verified]
|
|
126
|
+
- Mobile (375px): [verified/not verified]
|
|
127
|
+
|
|
128
|
+
### Notes
|
|
129
|
+
- [any off-scale values flagged]
|
|
130
|
+
- [any missing tokens that need to be added]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Then ask: **"Should I make any adjustments?"**
|
|
134
|
+
|
|
135
|
+
## Self-Check
|
|
136
|
+
|
|
137
|
+
Before responding, verify:
|
|
138
|
+
- [ ] You read the project's design token files before mapping values
|
|
139
|
+
- [ ] You checked for existing reusable components before creating new ones
|
|
140
|
+
- [ ] Every color, spacing, and typography value maps to a project token
|
|
141
|
+
- [ ] You flagged any Figma values that don't match existing tokens
|
|
142
|
+
- [ ] Responsive behavior is implemented for mobile, tablet, and desktop
|
|
143
|
+
- [ ] All interactive states from Figma are implemented
|
|
144
|
+
|
|
145
|
+
## Constraints
|
|
146
|
+
|
|
147
|
+
- Do NOT hardcode any color hex values, pixel sizes, or font values. Always use project tokens.
|
|
148
|
+
- Do NOT create new components when existing ones can be reused or extended.
|
|
149
|
+
- Do NOT skip the token mapping step — it prevents design drift.
|
|
150
|
+
- Do NOT assume the developer has provided all details. Ask every question needed. Treat the developer as someone who may forget to mention important context.
|
|
151
|
+
|
|
152
|
+
Target: $ARGUMENTS
|