@nebulit/embuilder 0.1.40 → 0.1.41
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/package.json +1 -1
- package/templates/.claude/skills/sample-slices/templates/.slices/index.json +1 -1
- package/templates/.claude/skills/ui-analyze-slices/SKILL.md +102 -0
- package/templates/.claude/skills/ui-build-slice-ui/SKILL.md +228 -0
- package/templates/.claude/skills/ui-generate-api/SKILL.md +141 -0
- package/templates/.claude/skills/ui-generate-hook/SKILL.md +118 -0
- package/templates/.claude/skills/ui-generate-types/SKILL.md +223 -0
- package/templates/.claude/skills/ui-read-ui-prompts/SKILL.md +192 -0
- package/templates/.claude/skills/ui-scaffold-component/SKILL.md +274 -0
- package/templates/frontend/prompt.md +250 -90
- package/templates/.claude/skills/sample-slices/templates/Cart/additem/slice.json +0 -979
- package/templates/.claude/skills/sample-slices/templates/Cart/archiveitem/slice.json +0 -529
- package/templates/.claude/skills/sample-slices/templates/Cart/cartitems/slice.json +0 -1072
- package/templates/.claude/skills/sample-slices/templates/Cart/cartwithproducts/slice.json +0 -394
- package/templates/.claude/skills/sample-slices/templates/Cart/changedprices/slice.json +0 -88
- package/templates/.claude/skills/sample-slices/templates/Cart/changeinventory/slice.json +0 -264
- package/templates/.claude/skills/sample-slices/templates/Cart/changeprice/slice.json +0 -308
- package/templates/.claude/skills/sample-slices/templates/Cart/clearcart/slice.json +0 -358
- package/templates/.claude/skills/sample-slices/templates/Cart/inventories/slice.json +0 -203
- package/templates/.claude/skills/sample-slices/templates/Cart/publishcart/slice.json +0 -876
- package/templates/.claude/skills/sample-slices/templates/Cart/removeitem/slice.json +0 -560
- package/templates/.claude/skills/sample-slices/templates/Cart/submitcart/slice.json +0 -708
- package/templates/.claude/skills/sample-slices/templates/Cart/submittedcartdata/slice.json +0 -399
- package/templates/.claude/skills/sample-slices/templates/index.json +0 -108
|
@@ -4,6 +4,22 @@ Build React + TypeScript UI components from slice JSON definitions using establi
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## 0. Available Skills (Use These!)
|
|
8
|
+
|
|
9
|
+
This project has custom skills available in `.claude/skills/` that automate common tasks:
|
|
10
|
+
|
|
11
|
+
- **`/ui-build-slice-ui`**: Complete orchestrator - builds entire UI from slice definitions (types → API → hooks → components)
|
|
12
|
+
- **`/ui-analyze-slices`**: Analyze slice JSON files to identify grouping, dependencies, and implementation strategy
|
|
13
|
+
- **`/ui-read-ui-prompts`**: Find and parse UI prompts from slice definitions and `ui-prompt.md`
|
|
14
|
+
- **`/ui-generate-types`**: Generate TypeScript interfaces from slice field definitions
|
|
15
|
+
- **`/ui-generate-api`**: Generate API layer functions for queries (Supabase) and commands (POST)
|
|
16
|
+
- **`/ui-generate-hook`**: Generate React Query hooks for STATE_VIEW (queries) and STATE_CHANGE (mutations)
|
|
17
|
+
- **`/ui-scaffold-component`**: Scaffold React components (List, Dialog, Page) using Bulma CSS
|
|
18
|
+
|
|
19
|
+
**IMPORTANT**: When asked to build UI from slices, USE the `/ui-build-slice-ui` skill first! It will orchestrate all other skills in the correct order. Only use individual skills when you need to regenerate or modify a specific part.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
7
23
|
## 1. Slice Composition (CRITICAL)
|
|
8
24
|
|
|
9
25
|
### Slice Types
|
|
@@ -25,8 +41,8 @@ Slice C: { groupId: "123", sliceType: "STATE_CHANGE", title: "Cancel Event" }
|
|
|
25
41
|
|
|
26
42
|
### UI Prompts Priority
|
|
27
43
|
|
|
28
|
-
1. Check `ui-prompt.md` (detailed specs)
|
|
29
|
-
2. Check `codeGen.uiPrompts` array (high-level guidance)
|
|
44
|
+
1. Check `ui-prompt.md` (detailed specs) - Use `/ui-read-ui-prompts` skill
|
|
45
|
+
2. Check `codeGen.uiPrompts` array (high-level guidance) - Use `/ui-read-ui-prompts` skill
|
|
30
46
|
3. Follow this prompt (standard patterns)
|
|
31
47
|
4. Keep it simple if no guidance
|
|
32
48
|
|
|
@@ -56,10 +72,10 @@ import { useQuery } from "@tanstack/react-query";
|
|
|
56
72
|
import * as api from "@/lib/api";
|
|
57
73
|
|
|
58
74
|
export function useEvents() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
return useQuery({
|
|
76
|
+
queryKey: ["events"],
|
|
77
|
+
queryFn: () => api.fetchEvents(),
|
|
78
|
+
});
|
|
63
79
|
}
|
|
64
80
|
```
|
|
65
81
|
|
|
@@ -67,15 +83,15 @@ export function useEvents() {
|
|
|
67
83
|
|
|
68
84
|
```typescript
|
|
69
85
|
export function useCreateEvent() {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
86
|
+
const ctx = useApiContext();
|
|
87
|
+
const queryClient = useQueryClient();
|
|
88
|
+
|
|
89
|
+
return useMutation({
|
|
90
|
+
mutationFn: (params: api.CreateEventParams) => api.createEvent(params, ctx),
|
|
91
|
+
onSuccess: () => {
|
|
92
|
+
queryClient.invalidateQueries({ queryKey: ["events"] });
|
|
93
|
+
},
|
|
94
|
+
});
|
|
79
95
|
}
|
|
80
96
|
```
|
|
81
97
|
|
|
@@ -88,11 +104,11 @@ export function useCreateEvent() {
|
|
|
88
104
|
```typescript
|
|
89
105
|
// src/lib/api.ts
|
|
90
106
|
export async function fetchEvents(): Promise<Event[]> {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
const { data, error } = await supabase
|
|
108
|
+
.from("events_for_planning") // Read model table
|
|
109
|
+
.select("*");
|
|
110
|
+
if (error) throw new Error(error.message);
|
|
111
|
+
return data || [];
|
|
96
112
|
}
|
|
97
113
|
```
|
|
98
114
|
|
|
@@ -100,21 +116,21 @@ export async function fetchEvents(): Promise<Event[]> {
|
|
|
100
116
|
|
|
101
117
|
```typescript
|
|
102
118
|
export async function createEvent(params: CreateEventParams, ctx: ApiContext) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
const response = await apiRequest(
|
|
120
|
+
commandEndpoints.createEvent, // /api/createevent
|
|
121
|
+
ctx,
|
|
122
|
+
{ method: "POST", body: { ...params } }
|
|
123
|
+
);
|
|
124
|
+
if (!response.ok) throw new Error(response.error);
|
|
125
|
+
return response.data;
|
|
110
126
|
}
|
|
111
127
|
```
|
|
112
128
|
|
|
113
129
|
**Add endpoint in `src/lib/api-client.ts`**:
|
|
114
130
|
```typescript
|
|
115
131
|
export const commandEndpoints = {
|
|
116
|
-
|
|
117
|
-
|
|
132
|
+
createEvent: "/api/createevent",
|
|
133
|
+
// ...
|
|
118
134
|
};
|
|
119
135
|
```
|
|
120
136
|
|
|
@@ -130,22 +146,22 @@ import { Skeleton } from "@/components/ui/skeleton";
|
|
|
130
146
|
import { useEvents } from "@/hooks/api/useEvents";
|
|
131
147
|
|
|
132
148
|
export function EventList() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
const { data: events = [], isLoading } = useEvents();
|
|
150
|
+
|
|
151
|
+
if (isLoading) {
|
|
152
|
+
return <Skeleton className="h-20 w-full" />;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
157
|
+
{events.map(event => (
|
|
158
|
+
<Card key={event.id}>
|
|
159
|
+
<CardHeader><CardTitle>{event.name}</CardTitle></CardHeader>
|
|
160
|
+
<CardContent>{event.date}</CardContent>
|
|
161
|
+
</Card>
|
|
162
|
+
))}
|
|
147
163
|
</div>
|
|
148
|
-
|
|
164
|
+
);
|
|
149
165
|
}
|
|
150
166
|
```
|
|
151
167
|
|
|
@@ -161,36 +177,36 @@ import { useCreateEvent } from "@/hooks/api/useEvents";
|
|
|
161
177
|
import { toast } from "sonner";
|
|
162
178
|
|
|
163
179
|
export function CreateEventDialog({ open, onOpenChange }) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
const createEvent = useCreateEvent();
|
|
181
|
+
const [form, setForm] = useState({ name: "", date: "" });
|
|
182
|
+
|
|
183
|
+
const handleSubmit = async () => {
|
|
184
|
+
if (!form.name) return toast.error("Name required");
|
|
185
|
+
try {
|
|
186
|
+
await createEvent.mutateAsync(form);
|
|
187
|
+
toast.success("Created");
|
|
188
|
+
onOpenChange(false);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
toast.error(`Error: ${err.message}`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
196
|
+
<DialogContent>
|
|
197
|
+
<DialogHeader><DialogTitle>Create Event</DialogTitle></DialogHeader>
|
|
198
|
+
<div className="space-y-4">
|
|
199
|
+
<div>
|
|
184
200
|
<Label>Name</Label>
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
201
|
+
<Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} />
|
|
202
|
+
</div>
|
|
203
|
+
<Button onClick={handleSubmit} disabled={createEvent.isPending}>
|
|
204
|
+
Create
|
|
205
|
+
</Button>
|
|
190
206
|
</div>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
207
|
+
</DialogContent>
|
|
208
|
+
</Dialog>
|
|
209
|
+
);
|
|
194
210
|
}
|
|
195
211
|
```
|
|
196
212
|
|
|
@@ -198,19 +214,19 @@ export function CreateEventDialog({ open, onOpenChange }) {
|
|
|
198
214
|
|
|
199
215
|
```typescript
|
|
200
216
|
export function EventsPage() {
|
|
201
|
-
|
|
217
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
202
218
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
219
|
+
return (
|
|
220
|
+
<div className="p-6">
|
|
221
|
+
<div className="flex justify-between mb-6">
|
|
206
222
|
<h1 className="text-2xl font-bold">Events</h1>
|
|
207
|
-
|
|
208
|
-
|
|
223
|
+
<Button onClick={() => setDialogOpen(true)}>Create Event</Button>
|
|
224
|
+
</div>
|
|
209
225
|
|
|
210
|
-
|
|
211
|
-
|
|
226
|
+
<EventList />
|
|
227
|
+
<CreateEventDialog open={dialogOpen} onOpenChange={setDialogOpen} />
|
|
212
228
|
</div>
|
|
213
|
-
|
|
229
|
+
);
|
|
214
230
|
}
|
|
215
231
|
```
|
|
216
232
|
|
|
@@ -218,6 +234,33 @@ export function EventsPage() {
|
|
|
218
234
|
|
|
219
235
|
## 6. Implementation Workflow
|
|
220
236
|
|
|
237
|
+
### Recommended Approach: Use Skills!
|
|
238
|
+
|
|
239
|
+
**For complete UI generation from slices:**
|
|
240
|
+
```bash
|
|
241
|
+
# Use the orchestrator skill - it handles everything
|
|
242
|
+
/ui-build-slice-ui <slice-file-paths>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
This will automatically:
|
|
246
|
+
1. Analyze slices (`/ui-analyze-slices`)
|
|
247
|
+
2. Read UI prompts (`/ui-read-ui-prompts`)
|
|
248
|
+
3. Generate types (`/ui-generate-types`)
|
|
249
|
+
4. Generate API functions (`/ui-generate-api`)
|
|
250
|
+
5. Generate hooks (`/ui-generate-hook`)
|
|
251
|
+
6. Scaffold components (`/ui-scaffold-component`)
|
|
252
|
+
7. Verify integration
|
|
253
|
+
|
|
254
|
+
**For individual tasks:**
|
|
255
|
+
- **Analyze before coding**: `/ui-analyze-slices <slice-files>` - Understand grouping and dependencies
|
|
256
|
+
- **Read requirements**: `/ui-read-ui-prompts <slice-folder>` - Extract design specs and validation rules
|
|
257
|
+
- **Generate types only**: `/ui-generate-types <slice-file>` - Create TypeScript interfaces
|
|
258
|
+
- **Generate API only**: `/ui-generate-api <slice-file>` - Create Supabase queries or POST commands
|
|
259
|
+
- **Generate hook only**: `/ui-generate-hook <slice-file>` - Create React Query hooks
|
|
260
|
+
- **Generate component only**: `/ui-scaffold-component <slice-files>` - Create React components with Bulma CSS
|
|
261
|
+
|
|
262
|
+
### Manual Workflow (If not using skills)
|
|
263
|
+
|
|
221
264
|
### Step 0: Analyze Grouping
|
|
222
265
|
- Find all slices with same `groupId`
|
|
223
266
|
- Check `codeGen.uiPrompts` and `ui-prompt.md`
|
|
@@ -227,14 +270,14 @@ export function EventsPage() {
|
|
|
227
270
|
```typescript
|
|
228
271
|
// src/types/index.ts
|
|
229
272
|
export interface Event {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
273
|
+
event_id: string;
|
|
274
|
+
name: string;
|
|
275
|
+
date: string;
|
|
233
276
|
}
|
|
234
277
|
|
|
235
278
|
export interface CreateEventParams {
|
|
236
|
-
|
|
237
|
-
|
|
279
|
+
name: string;
|
|
280
|
+
date: string;
|
|
238
281
|
}
|
|
239
282
|
```
|
|
240
283
|
|
|
@@ -273,10 +316,10 @@ export interface CreateEventParams {
|
|
|
273
316
|
**Error Handling**:
|
|
274
317
|
```typescript
|
|
275
318
|
try {
|
|
276
|
-
|
|
277
|
-
|
|
319
|
+
await mutation.mutateAsync(params);
|
|
320
|
+
toast.success("Success");
|
|
278
321
|
} catch (err) {
|
|
279
|
-
|
|
322
|
+
toast.error(`Error: ${err.message}`);
|
|
280
323
|
}
|
|
281
324
|
```
|
|
282
325
|
|
|
@@ -286,7 +329,21 @@ try {
|
|
|
286
329
|
|
|
287
330
|
---
|
|
288
331
|
|
|
289
|
-
## 9. UI Components
|
|
332
|
+
## 9. UI Components
|
|
333
|
+
|
|
334
|
+
**NOTE**: The skills in `.claude/skills/` are configured to use **Bulma CSS** for styling. If you're using the skills (especially `/scaffold-component`), components will be generated with Bulma classes.
|
|
335
|
+
|
|
336
|
+
### Bulma CSS (Used by Skills)
|
|
337
|
+
|
|
338
|
+
When using skills, components use Bulma classes:
|
|
339
|
+
- Layout: `container`, `section`, `columns`, `column`
|
|
340
|
+
- Components: `card`, `modal`, `button`, `notification`, `box`
|
|
341
|
+
- Forms: `field`, `control`, `label`, `input`, `select`, `textarea`
|
|
342
|
+
- Modifiers: `is-primary`, `is-active`, `is-fullwidth`, `has-text-centered`
|
|
343
|
+
|
|
344
|
+
### shadcn/ui (Alternative)
|
|
345
|
+
|
|
346
|
+
If manually implementing (not using skills), you can use shadcn/ui components:
|
|
290
347
|
|
|
291
348
|
Import from `@/components/ui/*`:
|
|
292
349
|
- `Button`, `Input`, `Label`, `Textarea`, `Select`
|
|
@@ -295,6 +352,8 @@ Import from `@/components/ui/*`:
|
|
|
295
352
|
- `Table`, `Tabs`, `Skeleton`
|
|
296
353
|
- `toast` from `sonner`
|
|
297
354
|
|
|
355
|
+
**Recommendation**: Use the skills with Bulma CSS for consistency with project configuration.
|
|
356
|
+
|
|
298
357
|
---
|
|
299
358
|
|
|
300
359
|
## Checklist
|
|
@@ -322,3 +381,104 @@ Import from `@/components/ui/*`:
|
|
|
322
381
|
✅ **STATE_CHANGE** = Command → Mutation hook → Form/Dialog
|
|
323
382
|
✅ **Keep modular** = Sub-components for each slice capability
|
|
324
383
|
✅ **Keep simple** = Follow existing patterns, don't over-engineer
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 10. Skills Usage Examples
|
|
388
|
+
|
|
389
|
+
### Example 1: Building Complete UI from Scratch
|
|
390
|
+
|
|
391
|
+
**User Request**: "Build the UI for the events management slices"
|
|
392
|
+
|
|
393
|
+
**Your Response**:
|
|
394
|
+
```bash
|
|
395
|
+
# First, analyze what we're working with
|
|
396
|
+
/ui-analyze-slices src/slices/events/*.json
|
|
397
|
+
|
|
398
|
+
# Then build everything at once
|
|
399
|
+
/ui-build-slice-ui src/slices/events/ViewEvents.json src/slices/events/CreateEvent.json
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Example 2: Just Need to Understand Slices
|
|
403
|
+
|
|
404
|
+
**User Request**: "What slices are in the orders group?"
|
|
405
|
+
|
|
406
|
+
**Your Response**:
|
|
407
|
+
```bash
|
|
408
|
+
# Use ui-analyze-slices to understand the grouping
|
|
409
|
+
/ui-analyze-slices src/slices/orders/*.json
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Example 3: Regenerating Just Types
|
|
413
|
+
|
|
414
|
+
**User Request**: "The Event interface is wrong, regenerate it from the slice"
|
|
415
|
+
|
|
416
|
+
**Your Response**:
|
|
417
|
+
```bash
|
|
418
|
+
# Use ui-generate-types to recreate just the TypeScript interfaces
|
|
419
|
+
/ui-generate-types src/slices/events/ViewEvents.json
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Example 4: Adding New API Endpoint
|
|
423
|
+
|
|
424
|
+
**User Request**: "Add the API function for the CancelEvent command"
|
|
425
|
+
|
|
426
|
+
**Your Response**:
|
|
427
|
+
```bash
|
|
428
|
+
# Use ui-generate-api to create the API layer
|
|
429
|
+
/ui-generate-api src/slices/events/CancelEvent.json
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Example 5: Understanding UI Requirements
|
|
433
|
+
|
|
434
|
+
**User Request**: "What are the validation rules for the event form?"
|
|
435
|
+
|
|
436
|
+
**Your Response**:
|
|
437
|
+
```bash
|
|
438
|
+
# Use ui-read-ui-prompts to extract requirements
|
|
439
|
+
/ui-read-ui-prompts src/slices/events/
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Example 6: Fixing Component Styling
|
|
443
|
+
|
|
444
|
+
**User Request**: "The EventList component doesn't look right, regenerate it with proper Bulma styling"
|
|
445
|
+
|
|
446
|
+
**Your Response**:
|
|
447
|
+
```bash
|
|
448
|
+
# Use ui-scaffold-component to regenerate with Bulma CSS
|
|
449
|
+
/ui-scaffold-component src/slices/events/ViewEvents.json
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Decision Tree: Which Skill to Use?
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
Need to build complete UI from slices?
|
|
456
|
+
└─> /ui-build-slice-ui (orchestrates everything)
|
|
457
|
+
|
|
458
|
+
Just exploring/understanding?
|
|
459
|
+
└─> /ui-analyze-slices (analysis only)
|
|
460
|
+
|
|
461
|
+
Just need to understand UI requirements?
|
|
462
|
+
└─> /ui-read-ui-prompts (extract specs)
|
|
463
|
+
|
|
464
|
+
Need to fix/regenerate specific layer?
|
|
465
|
+
├─> Types wrong? → /ui-generate-types
|
|
466
|
+
├─> API functions wrong? → /ui-generate-api
|
|
467
|
+
├─> Hooks wrong? → /ui-generate-hook
|
|
468
|
+
└─> Components wrong? → /ui-scaffold-component
|
|
469
|
+
|
|
470
|
+
Don't know which skill to use?
|
|
471
|
+
└─> Start with /ui-analyze-slices, then use /ui-build-slice-ui
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Remember
|
|
477
|
+
|
|
478
|
+
**ALWAYS** prefer using the skills over manual implementation! They ensure:
|
|
479
|
+
- Consistency across the codebase
|
|
480
|
+
- Proper use of Bulma CSS
|
|
481
|
+
- Correct CQRS patterns
|
|
482
|
+
- Proper TypeScript types
|
|
483
|
+
- React Query best practices
|
|
484
|
+
- Adherence to UI prompts and validation rules
|